├── .github └── workflows │ └── rust.yml ├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── LICENSE ├── README ├── README.md ├── common ├── Cargo.toml ├── build.rs └── src │ ├── args_parse.rs │ ├── callback.rs │ ├── cli.rs │ ├── command │ ├── client.rs │ ├── entity.rs │ ├── mod.rs │ └── server.rs │ ├── config │ ├── file_config.rs │ └── mod.rs │ ├── console_out │ ├── mod.rs │ └── table.rs │ ├── identifier.rs │ └── lib.rs ├── documents └── img │ └── ssh.jpg ├── vn-link-cli ├── Cargo.toml ├── README.md └── src │ └── main.rs ├── vn-link ├── Cargo.toml └── src │ ├── config.rs │ ├── in_mapping │ ├── mod.rs │ ├── tcp.rs │ └── udp.rs │ ├── lib.rs │ ├── out_mapping │ ├── mod.rs │ ├── tcp.rs │ └── udp.rs │ └── vnt_link │ └── mod.rs ├── vnt-cli ├── Cargo.toml ├── README.md └── src │ ├── main.rs │ └── root_check │ ├── mod.rs │ ├── unix.rs │ └── windows.rs └── vnt ├── Cargo.toml ├── LICENSE ├── build.rs ├── packet ├── Cargo.toml └── src │ ├── arp │ ├── arp.rs │ └── mod.rs │ ├── ethernet │ ├── mod.rs │ ├── packet.rs │ └── protocol.rs │ ├── icmp │ ├── icmp.rs │ └── mod.rs │ ├── igmp │ ├── igmp_v1.rs │ ├── igmp_v2.rs │ ├── igmp_v3.rs │ └── mod.rs │ ├── ip │ ├── ipv4 │ │ ├── mod.rs │ │ ├── packet.rs │ │ └── protocol.rs │ └── mod.rs │ ├── lib.rs │ ├── tcp │ ├── mod.rs │ └── tcp.rs │ └── udp │ ├── mod.rs │ └── udp.rs ├── proto └── message.proto └── src ├── channel ├── context.rs ├── handler.rs ├── idle.rs ├── mod.rs ├── notify.rs ├── punch.rs ├── sender.rs ├── socket │ ├── mod.rs │ ├── unix.rs │ └── windows.rs ├── tcp_channel.rs ├── udp_channel.rs └── ws_channel.rs ├── cipher ├── aes_cbc │ ├── mod.rs │ └── rs_aes_cbc.rs ├── aes_ecb │ ├── mod.rs │ ├── openssl_aes_ecb.rs │ └── rs_aes_ecb.rs ├── aes_gcm │ ├── aes_gcm_cipher.rs │ ├── mod.rs │ └── ring_aes_gcm_cipher.rs ├── chacha20 │ ├── mod.rs │ └── rs_chacha20.rs ├── chacha20_poly1305 │ ├── mod.rs │ ├── ring_chacha20_poly1305.rs │ └── rs_chacha20_poly1305.rs ├── cipher.rs ├── finger.rs ├── mod.rs ├── rsa_cipher.rs ├── sm4_cbc │ ├── mod.rs │ └── rs_sm4_cbc.rs └── xor │ ├── mod.rs │ └── xor.rs ├── compression ├── lz4_compress.rs ├── mod.rs └── zstd_compress.rs ├── core ├── conn.rs └── mod.rs ├── external_route └── mod.rs ├── handle ├── callback.rs ├── extension │ └── mod.rs ├── handshaker.rs ├── maintain │ ├── addr_request.rs │ ├── heartbeat.rs │ ├── idle.rs │ ├── mod.rs │ ├── punch.rs │ ├── re_nat_type.rs │ └── up_status.rs ├── mod.rs ├── recv_data │ ├── client.rs │ ├── mod.rs │ ├── server.rs │ └── turn.rs ├── registrar.rs └── tun_tap │ ├── mod.rs │ ├── platform.rs │ └── tun_handler.rs ├── ip_proxy ├── icmp_proxy.rs ├── mod.rs ├── tcp_proxy.rs └── udp_proxy.rs ├── lib.rs ├── nat ├── mod.rs └── stun.rs ├── port_mapping ├── mod.rs ├── tcp_mapping.rs └── udp_mapping.rs ├── protocol ├── body.rs ├── control_packet.rs ├── error_packet.rs ├── extension.rs ├── ip_turn_packet.rs ├── mod.rs ├── other_turn_packet.rs └── service_packet.rs ├── tun_tap_device ├── create_device.rs ├── mod.rs ├── tun_create_helper.rs └── vnt_device.rs └── util ├── counter ├── adder.rs └── mod.rs ├── dns_query.rs ├── limit ├── mod.rs ├── rate_limiter.rs └── traffic_meter.rs ├── mod.rs ├── notify.rs ├── scheduler.rs └── upnp.rs /.gitignore: -------------------------------------------------------------------------------- 1 | target/* 2 | vnt/src/proto/* 3 | common/src/generated_serial_number.rs 4 | 5 | # RustRover 6 | .idea -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = ["vnt", "common", "vnt-cli", "vn-link", "vn-link-cli"] 3 | 4 | [profile.release] 5 | opt-level = 'z' 6 | debug = 0 7 | debug-assertions = false 8 | strip = "debuginfo" 9 | lto = true 10 | panic = 'abort' 11 | incremental = false 12 | codegen-units = 1 13 | rpath = false 14 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | 一、程序说明 2 | 1. vnt-cli vnt的命令行程序 3 | 2. vn-link-cli 功能和vnt-cli基本一致,但是不依赖tun、不改变本地路由、不需要管理员/root权限 4 | 5 | 二、使用说明 6 | 使用-k参数构建虚拟网络 7 | 8 | 9 | 1. Program Description 10 | a. vnt-cli: Command-line program for VNT. 11 | b. vn-link-cli: Functions similarly to vnt-cli, but does not depend on TUN, does not change local routing, and does not require administrator/root permissions. 12 | 13 | 2. Instructions for Use 14 | Use the -k parameter to create a virtual network. -------------------------------------------------------------------------------- /common/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "common" 3 | version = "1.2.16" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | vnt = { path = "../vnt", package = "vnt", default-features = false } 10 | anyhow = "1.0.82" 11 | console = "0.15.2" 12 | log = "0.4.17" 13 | log4rs = { version = "1.3.0", optional = true } 14 | serde = { version = "1.0", features = ["derive"] } 15 | serde_yaml = "0.9.32" 16 | getopts = "0.2.21" 17 | gethostname = "0.4.3" 18 | uuid = { version = "1.8.0", features = ["v4"] } 19 | sys-locale = "0.3.1" 20 | 21 | [features] 22 | default = [] 23 | openssl = ["vnt/openssl"] 24 | openssl-vendored = ["vnt/openssl-vendored"] 25 | ring-cipher = ["vnt/ring-cipher"] 26 | aes_cbc = ["vnt/aes_cbc"] 27 | aes_ecb = ["vnt/aes_ecb"] 28 | sm4_cbc = ["vnt/sm4_cbc"] 29 | aes_gcm = ["vnt/aes_gcm"] 30 | chacha20_poly1305 = ["vnt/chacha20_poly1305"] 31 | server_encrypt = ["vnt/server_encrypt"] 32 | ip_proxy = ["vnt/ip_proxy"] 33 | port_mapping = ["vnt/port_mapping"] 34 | lz4 = ["vnt/lz4_compress"] 35 | zstd = ["vnt/zstd_compress"] 36 | upnp = ["vnt/upnp"] 37 | ws = ["vnt/ws"] 38 | wss = ["vnt/wss"] 39 | command = [] 40 | file_config = [] 41 | log = ["log4rs"] 42 | integrated_tun = ["vnt/integrated_tun"] 43 | 44 | [build-dependencies] 45 | rand = "0.8.5" 46 | chrono = "0.4.23" -------------------------------------------------------------------------------- /common/build.rs: -------------------------------------------------------------------------------- 1 | use rand::Rng; 2 | use std::fs::File; 3 | use std::io::Write; 4 | 5 | fn main() { 6 | let now_time = chrono::Local::now(); 7 | let serial_number = format!( 8 | "{}-{}", 9 | &now_time.format("%y%m%d%H%M").to_string(), 10 | rand::thread_rng().gen_range(100..1000) 11 | ); 12 | let generated_code = format!(r#"pub const SERIAL_NUMBER: &str = "{}";"#, serial_number); 13 | let dest_path = "src/generated_serial_number.rs"; 14 | let mut file = File::create(&dest_path).unwrap(); 15 | file.write_all(generated_code.as_bytes()).unwrap(); 16 | } 17 | -------------------------------------------------------------------------------- /common/src/args_parse.rs: -------------------------------------------------------------------------------- 1 | use std::net::Ipv4Addr; 2 | 3 | pub fn ips_parse(ips: &Vec) -> Result, String> { 4 | let mut in_ips_c = vec![]; 5 | for x in ips { 6 | let mut split = x.split(","); 7 | let net = if let Some(net) = split.next() { 8 | net 9 | } else { 10 | return Err(format!("ipv4/mask,ipv4 {:?}", x)); 11 | }; 12 | let ip = if let Some(ip) = split.next() { 13 | ip 14 | } else { 15 | return Err(format!("ipv4/mask,ipv4 {:?}", x)); 16 | }; 17 | let ip = if let Ok(ip) = ip.parse::() { 18 | ip 19 | } else { 20 | return Err(format!("not ipv4 {:?}", ip)); 21 | }; 22 | let mut split = net.split("/"); 23 | let dest = if let Some(dest) = split.next() { 24 | dest 25 | } else { 26 | return Err(format!("no ipv4/mask {:?}", net)); 27 | }; 28 | let mask = if let Some(mask) = split.next() { 29 | mask 30 | } else { 31 | return Err(format!("no netmask {:?}", net)); 32 | }; 33 | let dest = if let Ok(dest) = dest.parse::() { 34 | dest 35 | } else { 36 | return Err(format!("not ipv4 {:?}", dest)); 37 | }; 38 | let mask = to_ip(mask)?; 39 | in_ips_c.push((u32::from_be_bytes(dest.octets()), mask, ip)); 40 | } 41 | Ok(in_ips_c) 42 | } 43 | 44 | pub fn out_ips_parse(ips: &Vec) -> Result, String> { 45 | let mut in_ips_c = vec![]; 46 | for x in ips { 47 | let mut split = x.split("/"); 48 | let dest = if let Some(dest) = split.next() { 49 | dest 50 | } else { 51 | return Err(format!("no ipv4/mask {:?}", x)); 52 | }; 53 | let mask = if let Some(mask) = split.next() { 54 | mask 55 | } else { 56 | return Err(format!("no netmask {:?}", x)); 57 | }; 58 | let dest = if let Ok(dest) = dest.parse::() { 59 | dest 60 | } else { 61 | return Err(format!("not ipv4 {:?}", dest)); 62 | }; 63 | let mask = to_ip(mask)?; 64 | in_ips_c.push((u32::from_be_bytes(dest.octets()), mask)); 65 | } 66 | Ok(in_ips_c) 67 | } 68 | 69 | pub fn to_ip(mask: &str) -> Result { 70 | if let Ok(m) = mask.parse::() { 71 | if m > 32 { 72 | return Err("not netmask".to_string()); 73 | } 74 | let mut mask = 0u32; 75 | for i in 0..m { 76 | mask = mask | (1 << (31 - i)); 77 | } 78 | Ok(mask) 79 | } else { 80 | Err("not netmask".to_string()) 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /common/src/callback.rs: -------------------------------------------------------------------------------- 1 | use std::process; 2 | 3 | use console::style; 4 | use vnt::{ConnectInfo, ErrorInfo, ErrorType, HandshakeInfo, RegisterInfo, VntCallback}; 5 | 6 | #[derive(Clone)] 7 | pub struct VntHandler {} 8 | 9 | impl VntCallback for VntHandler { 10 | fn success(&self) { 11 | println!(" {} ", style("====== Connect Successfully ======").green()) 12 | } 13 | #[cfg(feature = "integrated_tun")] 14 | fn create_tun(&self, info: vnt::DeviceInfo) { 15 | println!("create_tun {}", info) 16 | } 17 | 18 | fn connect(&self, info: ConnectInfo) { 19 | println!("connect {}", info) 20 | } 21 | 22 | fn handshake(&self, info: HandshakeInfo) -> bool { 23 | println!("handshake {}", info); 24 | true 25 | } 26 | 27 | fn register(&self, info: RegisterInfo) -> bool { 28 | println!("register {}", style(info).green()); 29 | true 30 | } 31 | 32 | fn error(&self, info: ErrorInfo) { 33 | log::error!("error {:?}", info); 34 | println!("{}", style(format!("error {}", info)).red()); 35 | match info.code { 36 | ErrorType::TokenError 37 | | ErrorType::AddressExhausted 38 | | ErrorType::IpAlreadyExists 39 | | ErrorType::InvalidIp 40 | | ErrorType::LocalIpExists 41 | | ErrorType::FailedToCrateDevice => { 42 | self.stop(); 43 | } 44 | _ => {} 45 | } 46 | } 47 | 48 | fn stop(&self) { 49 | println!("stopped"); 50 | process::exit(0) 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /common/src/command/client.rs: -------------------------------------------------------------------------------- 1 | use serde::Deserialize; 2 | use std::io; 3 | use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4, UdpSocket}; 4 | use std::str::FromStr; 5 | use std::time::Duration; 6 | 7 | use crate::command::entity::{ChartA, ChartB, DeviceItem, Info, RouteItem}; 8 | 9 | pub struct CommandClient { 10 | buf: Vec, 11 | udp: UdpSocket, 12 | } 13 | 14 | impl CommandClient { 15 | pub fn new() -> io::Result { 16 | let port = read_command_port().unwrap_or_else(|e| { 17 | log::warn!("read_command_port:{:?}", e); 18 | 39271 19 | }); 20 | let udp = UdpSocket::bind("127.0.0.1:0")?; 21 | udp.set_read_timeout(Some(Duration::from_secs(5)))?; 22 | udp.connect(SocketAddr::V4(SocketAddrV4::new( 23 | Ipv4Addr::new(127, 0, 0, 1), 24 | port, 25 | )))?; 26 | Ok(Self { 27 | udp, 28 | buf: vec![0; 65536 * 8], 29 | }) 30 | } 31 | } 32 | fn read_command_port() -> io::Result { 33 | let path_buf = crate::cli::app_home()?.join("command-port"); 34 | let port = std::fs::read_to_string(path_buf)?; 35 | match u16::from_str(&port) { 36 | Ok(port) => Ok(port), 37 | Err(_) => { 38 | return Err(io::Error::new( 39 | io::ErrorKind::Other, 40 | "'command-port' file error", 41 | )); 42 | } 43 | } 44 | } 45 | 46 | impl CommandClient { 47 | pub fn list(&mut self) -> io::Result> { 48 | self.send_cmd(b"list") 49 | } 50 | pub fn route(&mut self) -> io::Result> { 51 | self.send_cmd(b"route") 52 | } 53 | pub fn info(&mut self) -> io::Result { 54 | self.send_cmd(b"info") 55 | } 56 | pub fn chart_a(&mut self) -> io::Result { 57 | self.send_cmd(b"chart_a") 58 | } 59 | pub fn chart_b(&mut self, input: &str) -> io::Result { 60 | let cmd = if input.is_empty() { 61 | "chart_b".to_string() 62 | } else { 63 | format!("chart_b:{}", input) 64 | }; 65 | self.send_cmd(cmd.as_bytes()) 66 | } 67 | fn send_cmd<'a, V: Deserialize<'a>>(&'a mut self, cmd: &[u8]) -> io::Result { 68 | self.udp.send(cmd)?; 69 | let len = self.udp.recv(&mut self.buf)?; 70 | match serde_yaml::from_slice::(&self.buf[..len]) { 71 | Ok(val) => Ok(val), 72 | Err(e) => { 73 | log::error!( 74 | "send_cmd {:?} {:?},{:?}", 75 | std::str::from_utf8(cmd), 76 | std::str::from_utf8(&self.buf[..len]), 77 | e 78 | ); 79 | Err(io::Error::new( 80 | io::ErrorKind::Other, 81 | format!("data error {:?} buf_len={}", e, len), 82 | )) 83 | } 84 | } 85 | } 86 | pub fn stop(&self) -> io::Result { 87 | self.udp.send(b"stop")?; 88 | let mut buf = [0; 10240]; 89 | let len = self.udp.recv(&mut buf)?; 90 | Ok(String::from_utf8(buf[..len].to_vec()).unwrap()) 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /common/src/command/entity.rs: -------------------------------------------------------------------------------- 1 | use serde::{Deserialize, Serialize}; 2 | use std::collections::HashMap; 3 | use std::net::{Ipv4Addr, SocketAddr}; 4 | 5 | #[derive(Serialize, Deserialize, Debug)] 6 | pub struct Info { 7 | pub name: String, 8 | pub virtual_ip: String, 9 | pub virtual_gateway: String, 10 | pub virtual_netmask: String, 11 | pub connect_status: String, 12 | pub relay_server: String, 13 | pub nat_type: String, 14 | pub public_ips: String, 15 | pub local_addr: String, 16 | pub ipv6_addr: String, 17 | pub port_mapping_list: Vec<(bool, SocketAddr, String)>, 18 | pub in_ips: Vec<(u32, u32, Ipv4Addr)>, 19 | pub out_ips: Vec<(u32, u32)>, 20 | pub udp_listen_addr: Vec, 21 | pub tcp_listen_addr: String, 22 | } 23 | 24 | #[derive(Serialize, Deserialize, Debug)] 25 | pub struct RouteItem { 26 | pub destination: String, 27 | pub next_hop: String, 28 | pub metric: String, 29 | pub rt: String, 30 | pub interface: String, 31 | } 32 | 33 | #[derive(Serialize, Deserialize, Debug)] 34 | pub struct DeviceItem { 35 | pub name: String, 36 | pub virtual_ip: String, 37 | pub nat_type: String, 38 | pub public_ips: String, 39 | pub local_ip: String, 40 | pub ipv6: String, 41 | pub nat_traversal_type: String, 42 | pub rt: String, 43 | pub status: String, 44 | pub client_secret: bool, 45 | pub client_secret_hash: Vec, 46 | pub current_client_secret: bool, 47 | pub current_client_secret_hash: Vec, 48 | pub wire_guard: bool, 49 | } 50 | 51 | #[derive(Serialize, Deserialize, Debug, Default)] 52 | pub struct ChartA { 53 | pub disable_stats: bool, 54 | pub up_total: u64, 55 | pub down_total: u64, 56 | pub up_map: HashMap, 57 | pub down_map: HashMap, 58 | } 59 | 60 | #[derive(Serialize, Deserialize, Debug, Default)] 61 | pub struct ChartB { 62 | pub disable_stats: bool, 63 | pub ip: Option, 64 | pub up_total: u64, 65 | pub up_list: Vec, 66 | pub down_total: u64, 67 | pub down_list: Vec, 68 | } 69 | -------------------------------------------------------------------------------- /common/src/command/server.rs: -------------------------------------------------------------------------------- 1 | use crate::command::command_chart_b; 2 | use std::io; 3 | use std::io::Write; 4 | use std::net::UdpSocket; 5 | use vnt::core::Vnt; 6 | 7 | pub struct CommandServer {} 8 | 9 | impl CommandServer { 10 | pub fn new() -> Self { 11 | Self {} 12 | } 13 | } 14 | 15 | impl CommandServer { 16 | pub fn start(self, vnt: Vnt) -> io::Result<()> { 17 | let udp = if let Ok(udp) = UdpSocket::bind("127.0.0.1:39271") { 18 | udp 19 | } else { 20 | UdpSocket::bind("127.0.0.1:0")? 21 | }; 22 | let addr = udp.local_addr()?; 23 | log::info!("启动后台cmd:{:?}", addr); 24 | if let Err(e) = save_port(addr.port()) { 25 | log::warn!("保存后台命令端口失败:{:?}", e); 26 | } 27 | 28 | let mut buf = [0u8; 64]; 29 | loop { 30 | let (len, addr) = udp.recv_from(&mut buf)?; 31 | match std::str::from_utf8(&buf[..len]) { 32 | Ok(cmd) => { 33 | if let Ok(out) = command(cmd, &vnt) { 34 | if let Err(e) = udp.send_to(out.as_bytes(), addr) { 35 | log::warn!("cmd={},err={:?}", cmd, e); 36 | } 37 | if "stopped" == &out { 38 | break; 39 | } 40 | } 41 | } 42 | Err(e) => { 43 | log::warn!("{:?}", e); 44 | } 45 | } 46 | } 47 | Ok(()) 48 | } 49 | } 50 | fn save_port(port: u16) -> io::Result<()> { 51 | let path_buf = crate::cli::app_home()?.join("command-port"); 52 | let mut file = std::fs::File::create(path_buf)?; 53 | file.write_all(port.to_string().as_bytes())?; 54 | file.sync_all() 55 | } 56 | 57 | fn command(cmd: &str, vnt: &Vnt) -> io::Result { 58 | let cmd = cmd.trim(); 59 | let out_str = match cmd { 60 | "route" => serde_yaml::to_string(&crate::command::command_route(vnt)) 61 | .unwrap_or_else(|e| format!("error {:?}", e)), 62 | "list" => serde_yaml::to_string(&crate::command::command_list(vnt)) 63 | .unwrap_or_else(|e| format!("error {:?}", e)), 64 | "info" => serde_yaml::to_string(&crate::command::command_info(vnt)) 65 | .unwrap_or_else(|e| format!("error {:?}", e)), 66 | "chart_a" => serde_yaml::to_string(&crate::command::command_chart_a(vnt)) 67 | .unwrap_or_else(|e| format!("error {:?}", e)), 68 | "stop" => { 69 | vnt.stop(); 70 | "stopped".to_string() 71 | } 72 | _ => { 73 | if let Some(ip) = cmd.strip_prefix("chart_b") { 74 | let chart = if ip.is_empty() { 75 | command_chart_b(&vnt, &vnt.current_device().virtual_gateway.to_string()) 76 | } else { 77 | command_chart_b(&vnt, &ip[1..]) 78 | }; 79 | serde_yaml::to_string(&chart).unwrap_or_else(|e| format!("error {:?}", e)) 80 | } else { 81 | format!( 82 | "command '{}' not found. Try to enter: 'route'/'list'/'stop' \n", 83 | cmd 84 | ) 85 | } 86 | } 87 | }; 88 | Ok(out_str) 89 | } 90 | -------------------------------------------------------------------------------- /common/src/config/mod.rs: -------------------------------------------------------------------------------- 1 | pub const PUB_STUN: [&'static str; 4] = [ 2 | "stun.miwifi.com", 3 | "stun.chat.bilibili.com", 4 | "stun.hitv.com", 5 | "stun.cdnbye.com", 6 | ]; 7 | #[cfg(feature = "file_config")] 8 | mod file_config; 9 | 10 | use crate::identifier; 11 | #[cfg(feature = "file_config")] 12 | pub use file_config::read_config; 13 | 14 | #[cfg(not(feature = "file_config"))] 15 | pub fn read_config(_file_path: &str) -> anyhow::Result<(vnt::core::Config, Vec, bool)> { 16 | unimplemented!() 17 | } 18 | 19 | pub fn get_device_id() -> String { 20 | if let Some(id) = identifier::get_unique_identifier() { 21 | id 22 | } else { 23 | let path_buf = match crate::cli::app_home() { 24 | Ok(path_buf) => path_buf.join("device-id"), 25 | Err(e) => { 26 | log::warn!("{:?}", e); 27 | return String::new(); 28 | } 29 | }; 30 | if let Ok(id) = std::fs::read_to_string(path_buf.as_path()) { 31 | id 32 | } else { 33 | let id = uuid::Uuid::new_v4().to_string(); 34 | let _ = std::fs::write(path_buf, &id); 35 | id 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /common/src/console_out/table.rs: -------------------------------------------------------------------------------- 1 | use console::Style; 2 | 3 | pub fn println_table(table: Vec>) { 4 | if table.is_empty() { 5 | return; 6 | } 7 | let mut width_list = vec![0; table[0].len()]; 8 | for in_list in table.iter() { 9 | for (index, (item, _)) in in_list.iter().enumerate() { 10 | let width = console::measure_text_width(item) + 4; 11 | if width_list[index] < width { 12 | width_list[index] = width; 13 | } 14 | } 15 | } 16 | for in_list in table { 17 | for (col, (item, style)) in in_list.iter().enumerate() { 18 | let str = format!("{:1$}", item, width_list[col]); 19 | print!("{}", style.apply_to(str)); 20 | } 21 | println!() 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /common/src/identifier.rs: -------------------------------------------------------------------------------- 1 | #[cfg(target_os = "windows")] 2 | pub fn get_unique_identifier() -> Option { 3 | use std::os::windows::process::CommandExt; 4 | use std::process::Command; 5 | let output = match Command::new("wmic") 6 | .creation_flags(0x08000000) 7 | .args(&["csproduct", "get", "UUID"]) 8 | .output() 9 | { 10 | Ok(output) => output, 11 | Err(_) => { 12 | return None; 13 | } 14 | }; 15 | 16 | let result = String::from_utf8_lossy(&output.stdout); 17 | let identifier = result.lines().nth(1).unwrap_or("").trim(); 18 | if identifier.is_empty() { 19 | None 20 | } else { 21 | Some(identifier.to_string()) 22 | } 23 | } 24 | 25 | #[cfg(target_os = "macos")] 26 | pub fn get_unique_identifier() -> Option { 27 | use std::process::Command; 28 | let output = match Command::new("ioreg") 29 | .args(&["-rd1", "-c", "IOPlatformExpertDevice"]) 30 | .output() 31 | { 32 | Ok(output) => output, 33 | Err(_) => { 34 | return None; 35 | } 36 | }; 37 | 38 | let result = String::from_utf8_lossy(&output.stdout); 39 | let identifier = result 40 | .lines() 41 | .find(|line| line.contains("IOPlatformUUID")) 42 | .unwrap_or("") 43 | .trim(); 44 | if identifier.is_empty() { 45 | None 46 | } else { 47 | Some(identifier.to_string()) 48 | } 49 | } 50 | 51 | #[cfg(target_os = "linux")] 52 | pub fn get_unique_identifier() -> Option { 53 | use std::process::Command; 54 | 55 | // Try to execute 'dmidecode' command to get the system identifier first. 56 | if let Ok(output) = Command::new("dmidecode") 57 | .arg("-s") 58 | .arg("system-uuid") 59 | .output() 60 | { 61 | let identifier = String::from_utf8_lossy(&output.stdout).trim().to_owned(); 62 | if !identifier.is_empty() { 63 | return Some(identifier.to_string()); 64 | } 65 | } 66 | 67 | // Try to read file /etc/machine-id if 'dmidecode' command cannot be executed or get nothing. 68 | // 对 linux 或 wsl 来说,读取 /etc/machine-id 即可获取当前操作系统的 69 | // 唯一标识,而且某些环境没有预装`dmidecode`命令 70 | if let Ok(identifier) = std::fs::read_to_string("/etc/machine-id") { 71 | let identifier = identifier.trim(); 72 | if !identifier.is_empty() { 73 | return Some(identifier.to_string()); 74 | } 75 | } 76 | 77 | None 78 | } 79 | -------------------------------------------------------------------------------- /common/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod args_parse; 2 | #[cfg(feature = "command")] 3 | pub mod command; 4 | pub mod config; 5 | #[cfg(feature = "command")] 6 | mod console_out; 7 | pub mod identifier; 8 | 9 | pub mod cli; 10 | mod generated_serial_number; 11 | 12 | pub mod callback; 13 | -------------------------------------------------------------------------------- /documents/img/ssh.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vnt-dev/vnt/1cba2575317336496b7082a2e58203d99918a8e7/documents/img/ssh.jpg -------------------------------------------------------------------------------- /vn-link-cli/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "vn-link-cli" 3 | version = "1.2.16" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | vn-link = { path = "../vn-link", default-features = false } 8 | common = { path = "../common", default-features = false } 9 | tokio = { version = "1.37.0", features = ["full"] } 10 | log = "0.4.17" 11 | 12 | [features] 13 | default = ["default-feature"] 14 | default-feature = ["server_encrypt", "aes_gcm", "aes_cbc", "aes_ecb", "sm4_cbc", "chacha20_poly1305", "port_mapping", "log", "command", "file_config", "lz4", "ws"] 15 | 16 | openssl = ["vn-link/openssl", "common/openssl"] 17 | openssl-vendored = ["vn-link/openssl-vendored", "common/openssl-vendored"] 18 | ring-cipher = ["vn-link/ring-cipher", "common/ring-cipher"] 19 | aes_cbc = ["vn-link/aes_cbc", "common/aes_cbc"] 20 | aes_ecb = ["vn-link/aes_ecb", "common/aes_ecb"] 21 | sm4_cbc = ["vn-link/sm4_cbc", "common/sm4_cbc"] 22 | aes_gcm = ["vn-link/aes_gcm", "common/aes_gcm"] 23 | chacha20_poly1305 = ["vn-link/chacha20_poly1305", "common/chacha20_poly1305"] 24 | server_encrypt = ["vn-link/server_encrypt", "common/server_encrypt"] 25 | port_mapping = ["vn-link/port_mapping", "common/port_mapping"] 26 | lz4 = ["vn-link/lz4_compress", "common/lz4"] 27 | zstd = ["vn-link/zstd_compress", "common/zstd"] 28 | upnp = ["vn-link/upnp", "common/upnp"] 29 | ws = ["vn-link/ws", "common/ws"] 30 | wss = ["vn-link/wss", "common/wss"] 31 | log = ["common/log"] 32 | command = ["common/command"] 33 | file_config = ["common/file_config"] 34 | 35 | -------------------------------------------------------------------------------- /vn-link-cli/README.md: -------------------------------------------------------------------------------- 1 | # 端口映射模式 2 | 3 | ## 一、特点 4 | 5 | 1. 不需要tap/tun虚拟网卡 6 | 2. 不需要管理员/root权限 7 | 3. 不改变本地路由 8 | 4. 使用端口映射来访问目标服务 9 | 10 | ## 二、作用 11 | 12 | 和vnt互补,能简单快速构建网络,外部依赖更少 13 | 14 | ## 三、使用方式 15 | 16 | 和vnt的使用方式一样,只是多了"--vnt-mapping"这个参数 17 | 18 | ### vn-link作为被访问端,不需要额外配置vnt-mapping 19 | 20 | ### vn-link访问vnt或者vn-link,需要加vnt-mapping 21 | 22 | 例如: 23 | 24 | 设备A 运行vnt(虚拟IP 10.26.0.A),设备B 运行vn-link(虚拟IP 10.26.0.B)。 25 | 26 | 如果要用B访问A上的tcp 80端口,则在设备B上需要加--vnt-mapping "tcp:port1-10.26.0.A:80" 27 | 28 | 这个参数的作用是将B上的***本地端口port1***转发到设备A的地址10.26.0.A: 29 | 80,此时在设备B上可以访问本地port1端口从而间接访问10.26.0.A:80 30 | 31 | ## 四、vn-link的子网代理 32 | 33 | vn-link也支持点对网参数。 还是接着上面的例子 34 | 35 | 假设 设备C在设备A的子网下,C的子网IP为192.168.1.C,A的子网IP为192.168.1.A,要在设备B上访问C 36 | 37 | 则在B上加这些参数 38 | 39 | - --vnt-mapping "tcp:port2-192.168.1.C:80" (将本地port2端口映射到C的80端口) 40 | - -i 192.168.1.0/24,10.26.0.A (将目标192.168.1.0/24的数据发送到10.26.0.A,也就是A节点) 41 | 42 | 在A上加参数 43 | 44 | - -o 0.0.0.0/0 (允许所有流量转发) 45 | 46 | ***再次说明,vn-link作为被访问端时和vnt使用方式一致,vn-link作为访问端时需要加--vnt-mapping映射端口*** 47 | 48 | ***vn-link是基于端口映射的使用模式,不会改变本地路由*** 49 | 50 | ## 五、参数介绍 51 | 52 | --vnt-mapping支持udp/tcp,例如 --vnt-mapping "tcp:port1-remoteIp:remotePort" 53 | 54 | - 第一部分为协议,支持使用udp/tcp 55 | - 第二部分是本地端口,注意不要和本地服务的端口冲突 56 | - 第三部分是目标机器的地址,一般是目标虚拟IP地址,如果配置了点对网参数(-i和-o)则也可以是目标子网地址 57 | 58 | 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /vn-link-cli/src/main.rs: -------------------------------------------------------------------------------- 1 | use common::callback; 2 | use vn_link::config::VnLinkConfig; 3 | use vn_link::vnt::core::Config; 4 | 5 | fn main() { 6 | let (config, vnt_link_config, cmd) = match common::cli::parse_args_config() { 7 | Ok(rs) => { 8 | if let Some(rs) = rs { 9 | rs 10 | } else { 11 | return; 12 | } 13 | } 14 | Err(e) => { 15 | log::error!( 16 | "parse error={:?} cmd={:?}", 17 | e, 18 | std::env::args().collect::>() 19 | ); 20 | println!("Error {:?}", e); 21 | return; 22 | } 23 | }; 24 | let vnt_link_config = VnLinkConfig::new(vn_link::config::convert(vnt_link_config).unwrap()); 25 | main0(config, vnt_link_config, cmd) 26 | } 27 | 28 | #[tokio::main] 29 | async fn main0(config: Config, vn_link_config: VnLinkConfig, _show_cmd: bool) { 30 | #[cfg(feature = "port_mapping")] 31 | for (is_tcp, addr, dest) in config.port_mapping_list.iter() { 32 | if *is_tcp { 33 | println!("TCP port mapping {}->{}", addr, dest) 34 | } else { 35 | println!("UDP port mapping {}->{}", addr, dest) 36 | } 37 | } 38 | for x in &vn_link_config.mapping { 39 | if x.protocol.is_tcp() { 40 | println!("TCP vnt addr mapping 127.0.0.1:{}->{}", x.src_port, x.dest) 41 | } else { 42 | println!("UDP vnt addr mapping 127.0.0.1:{}->{}", x.src_port, x.dest) 43 | } 44 | } 45 | 46 | let vnt_util = match vn_link::VnLink::new(config, vn_link_config, callback::VntHandler {}).await 47 | { 48 | Ok(vnt) => vnt, 49 | Err(e) => { 50 | println!("error: {:?}", e); 51 | std::process::exit(1); 52 | } 53 | }; 54 | 55 | #[cfg(feature = "command")] 56 | { 57 | let vnt_c = vnt_util.as_vnt().clone(); 58 | std::thread::Builder::new() 59 | .name("CommandServer".into()) 60 | .spawn(move || { 61 | if let Err(e) = common::command::server::CommandServer::new().start(vnt_c) { 62 | log::warn!("cmd:{:?}", e); 63 | } 64 | }) 65 | .expect("CommandServer"); 66 | let vnt_c = vnt_util.as_vnt(); 67 | if _show_cmd { 68 | use tokio::io::AsyncBufReadExt; 69 | let mut cmd = String::new(); 70 | let mut reader = tokio::io::BufReader::new(tokio::io::stdin()); 71 | loop { 72 | cmd.clear(); 73 | println!("======== input:list,info,route,all,stop,chart_a,chart_b[:ip] ========"); 74 | match reader.read_line(&mut cmd).await { 75 | Ok(len) => { 76 | if !common::command::command_str(&cmd[..len], vnt_c) { 77 | break; 78 | } 79 | } 80 | Err(e) => { 81 | println!("input err:{}", e); 82 | break; 83 | } 84 | } 85 | } 86 | } 87 | } 88 | vnt_util.wait().await 89 | } 90 | -------------------------------------------------------------------------------- /vn-link/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "vn-link" 3 | version = "1.2.16" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | lwip-rs = { git = "https://github.com/vnt-dev/lwip-rs" } 8 | vnt = { path = "../vnt", package = "vnt", default-features = false } 9 | log = "0.4.17" 10 | anyhow = "1.0.82" 11 | parking_lot = "0.12.1" 12 | 13 | tokio = { version = "1.37.0", features = ["full"] } 14 | crossbeam-utils = "0.8" 15 | 16 | [features] 17 | default = ["server_encrypt", "aes_gcm", "aes_cbc", "aes_ecb", "sm4_cbc", "chacha20_poly1305", "port_mapping", "lz4_compress"] 18 | openssl = ["vnt/openssl"] 19 | openssl-vendored = ["vnt/openssl-vendored"] 20 | ring-cipher = ["vnt/ring-cipher"] 21 | aes_cbc = ["vnt/aes_cbc"] 22 | aes_ecb = ["vnt/aes_ecb"] 23 | sm4_cbc = ["vnt/sm4_cbc"] 24 | aes_gcm = ["vnt/aes_gcm"] 25 | chacha20_poly1305 = ["vnt/chacha20_poly1305"] 26 | server_encrypt = ["vnt/server_encrypt"] 27 | port_mapping = ["vnt/port_mapping"] 28 | lz4_compress = ["vnt/lz4_compress"] 29 | zstd_compress = ["vnt/zstd_compress"] 30 | upnp = ["vnt/upnp"] 31 | ws = ["vnt/ws"] 32 | wss = ["vnt/wss"] -------------------------------------------------------------------------------- /vn-link/src/config.rs: -------------------------------------------------------------------------------- 1 | use anyhow::Context; 2 | use std::net::SocketAddr; 3 | use std::str::FromStr; 4 | 5 | #[derive(Clone, Debug)] 6 | pub struct VnLinkConfig { 7 | pub mapping: Vec, 8 | } 9 | 10 | impl VnLinkConfig { 11 | pub fn new(mapping: Vec) -> Self { 12 | Self { mapping } 13 | } 14 | } 15 | 16 | #[derive(Copy, Clone, Eq, PartialEq, Debug)] 17 | pub enum LinkProtocol { 18 | Tcp, 19 | Udp, 20 | } 21 | 22 | impl LinkProtocol { 23 | pub fn is_tcp(&self) -> bool { 24 | self == &LinkProtocol::Tcp 25 | } 26 | } 27 | 28 | #[derive(Copy, Clone, Debug)] 29 | pub struct LinkItem { 30 | pub protocol: LinkProtocol, 31 | pub src_port: u16, 32 | pub dest: SocketAddr, 33 | } 34 | 35 | impl LinkItem { 36 | pub fn new(protocol: LinkProtocol, src_port: u16, dest: SocketAddr) -> Self { 37 | Self { 38 | protocol, 39 | src_port, 40 | dest, 41 | } 42 | } 43 | } 44 | 45 | pub fn convert(vec: Vec) -> anyhow::Result> { 46 | let mut rs = Vec::with_capacity(vec.len()); 47 | for x in vec { 48 | let string = x.trim().to_lowercase(); 49 | if let Some(udp_mapping) = string.strip_prefix("udp:") { 50 | let mut split = udp_mapping.split("-"); 51 | let bind_port = split 52 | .next() 53 | .with_context(|| format!("vnt-mapping error {:?},eg: udp:80-10.26.0.10:8080", x))?; 54 | let bind_port = u16::from_str(bind_port) 55 | .with_context(|| format!("udp_mapping error {}", bind_port))?; 56 | let dest = split 57 | .next() 58 | .with_context(|| format!("vnt-mapping error {:?},eg: udp:80-10.26.0.10:8080", x))?; 59 | let dest_addr = SocketAddr::from_str(dest) 60 | .with_context(|| format!("udp_mapping error {}", dest))?; 61 | rs.push(LinkItem::new(LinkProtocol::Udp, bind_port, dest_addr)); 62 | continue; 63 | } 64 | if let Some(tcp_mapping) = string.strip_prefix("tcp:") { 65 | let mut split = tcp_mapping.split("-"); 66 | let bind_port = split 67 | .next() 68 | .with_context(|| format!("vnt-mapping error {:?},eg: tcp:80-10.26.0.10:8080", x))?; 69 | let bind_port = u16::from_str(bind_port) 70 | .with_context(|| format!("tcp_mapping error {}", bind_port))?; 71 | let dest = split 72 | .next() 73 | .with_context(|| format!("vnt-mapping error {:?},eg: tcp:80-10.26.0.10:8080", x))?; 74 | let dest_addr = SocketAddr::from_str(dest) 75 | .with_context(|| format!("tcp_mapping error {}", dest))?; 76 | rs.push(LinkItem::new(LinkProtocol::Tcp, bind_port, dest_addr)); 77 | continue; 78 | } 79 | Err(anyhow::anyhow!( 80 | "vnt-mapping error {:?},eg: tcp:80-10.26.0.10:8080", 81 | x 82 | ))?; 83 | } 84 | Ok(rs) 85 | } 86 | -------------------------------------------------------------------------------- /vn-link/src/in_mapping/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod tcp; 2 | pub mod udp; 3 | -------------------------------------------------------------------------------- /vn-link/src/in_mapping/tcp.rs: -------------------------------------------------------------------------------- 1 | use crate::out_mapping::tcp::tcp_copy; 2 | use crossbeam_utils::atomic::AtomicCell; 3 | use lwip_rs::tcp_stream::TcpStream as LwIpTcpStream; 4 | use std::net::{IpAddr, SocketAddr}; 5 | use std::sync::Arc; 6 | use std::time::Duration; 7 | use tokio::net::TcpListener; 8 | use vnt::handle::CurrentDeviceInfo; 9 | 10 | pub async fn tcp_mapping_listen( 11 | tcp_listener: TcpListener, 12 | current_device: Arc>, 13 | dest: SocketAddr, 14 | ) { 15 | loop { 16 | let (stream, addr) = match tcp_listener.accept().await { 17 | Ok((stream, addr)) => (stream, addr), 18 | Err(e) => { 19 | log::warn!("tcp_mapping_listen {:?} dest {}", e, dest); 20 | continue; 21 | } 22 | }; 23 | let current_info = current_device.load(); 24 | if current_info.virtual_ip.is_unspecified() { 25 | continue; 26 | } 27 | if let IpAddr::V4(ip) = dest.ip() { 28 | if ip == current_info.virtual_ip { 29 | //防止用错参数的 30 | log::warn!("目的地址不能是本地虚拟ip tcp->{}", dest); 31 | continue; 32 | } 33 | } 34 | let src = SocketAddr::new(IpAddr::V4(current_info.virtual_ip), addr.port()); 35 | tokio::spawn(async move { 36 | match LwIpTcpStream::connect(src, dest, Duration::from_secs(5)).await { 37 | Ok(lw_tcp) => { 38 | tcp_copy(lw_tcp, stream); 39 | } 40 | Err(e) => { 41 | log::warn!("{} {}->{} {}", addr, src, dest, e); 42 | } 43 | }; 44 | }); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /vn-link/src/in_mapping/udp.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashMap; 2 | use std::net::{IpAddr, SocketAddr}; 3 | use std::sync::Arc; 4 | use std::time::Instant; 5 | 6 | use crossbeam_utils::atomic::AtomicCell; 7 | use parking_lot::Mutex; 8 | use tokio::net::UdpSocket; 9 | 10 | use lwip_rs::udp::UdpSocketWrite; 11 | use vnt::handle::CurrentDeviceInfo; 12 | 13 | pub async fn udp_mapping_start( 14 | udp: UdpSocket, 15 | lwip_udp_write: UdpSocketWrite, 16 | current_device: Arc>, 17 | in_udp_map: &Arc< 18 | Mutex< 19 | HashMap< 20 | (SocketAddr, SocketAddr), 21 | (Arc, Option, Arc>), 22 | >, 23 | >, 24 | >, 25 | 26 | dest: SocketAddr, 27 | ) { 28 | let udp = Arc::new(udp); 29 | let mut buf = [0u8; 65536]; 30 | loop { 31 | let (len, addr) = match udp.recv_from(&mut buf).await { 32 | Ok(rs) => rs, 33 | Err(e) => { 34 | log::warn!("recv_from {} {}", dest, e); 35 | continue; 36 | } 37 | }; 38 | let current_info = current_device.load(); 39 | if current_info.virtual_ip.is_unspecified() { 40 | continue; 41 | } 42 | if let IpAddr::V4(ip) = dest.ip() { 43 | if ip == current_info.virtual_ip { 44 | //防止用错参数的 45 | log::warn!("目的地址不能是本地虚拟ip udp->{}", dest); 46 | continue; 47 | } 48 | } 49 | let src = SocketAddr::new(IpAddr::V4(current_info.virtual_ip), addr.port()); 50 | in_udp_map.lock().insert( 51 | (dest, src), 52 | ( 53 | udp.clone(), 54 | Some(addr), 55 | Arc::new(AtomicCell::new(Instant::now())), 56 | ), 57 | ); 58 | 59 | if let Err(e) = lwip_udp_write.send(&buf[..len], &src, &dest) { 60 | log::warn!("lwip_udp_write {}->{} {}", src, dest, e); 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /vn-link/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod config; 2 | mod in_mapping; 3 | mod out_mapping; 4 | mod vnt_link; 5 | 6 | pub use vnt; 7 | 8 | pub use vnt_link::*; 9 | -------------------------------------------------------------------------------- /vn-link/src/out_mapping/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod tcp; 2 | pub mod udp; 3 | -------------------------------------------------------------------------------- /vn-link/src/out_mapping/tcp.rs: -------------------------------------------------------------------------------- 1 | use std::net::{IpAddr, Ipv4Addr}; 2 | use std::sync::Arc; 3 | 4 | use crossbeam_utils::atomic::AtomicCell; 5 | use tokio::net::TcpStream; 6 | 7 | use lwip_rs::tcp_listener::TcpListener; 8 | use lwip_rs::tcp_stream::TcpStream as LwIpTcpStream; 9 | use vnt::handle::CurrentDeviceInfo; 10 | 11 | pub async fn tcp_mapping_listen( 12 | mut tcp_listener: TcpListener, 13 | current_device: Arc>, 14 | ) { 15 | loop { 16 | let stream = match tcp_listener.accept().await { 17 | Ok(stream) => stream, 18 | Err(e) => { 19 | log::warn!("tcp_mapping_listen err {:?}", e); 20 | break; 21 | } 22 | }; 23 | let device_info = current_device.load(); 24 | tokio::spawn(async move { 25 | let dest = stream.dest_addr(); 26 | let src = stream.src_addr(); 27 | if let Err(e) = tcp_mapping_handle(stream, device_info).await { 28 | log::warn!("tcp_mapping_handle {}->{} {:?}", src, dest, e) 29 | } 30 | }); 31 | } 32 | } 33 | 34 | async fn tcp_mapping_handle( 35 | tcp_stream: LwIpTcpStream, 36 | device_info: CurrentDeviceInfo, 37 | ) -> anyhow::Result<()> { 38 | let mut dest = tcp_stream.dest_addr(); 39 | // let src = tcp_stream.src_addr(); 40 | if let IpAddr::V4(ip) = dest.ip() { 41 | if ip.is_unspecified() 42 | || ip.is_broadcast() 43 | || ip.is_multicast() 44 | || ip == device_info.virtual_ip 45 | || ip == device_info.broadcast_ip 46 | { 47 | //是自己 48 | dest.set_ip(IpAddr::V4(Ipv4Addr::LOCALHOST)); 49 | } 50 | } 51 | let peer_stream = TcpStream::connect(dest).await?; 52 | if dest.port() == peer_stream.local_addr()?.port() { 53 | return Err(anyhow::anyhow!("tcp port loop")); 54 | } 55 | tcp_copy(tcp_stream, peer_stream); 56 | Ok(()) 57 | } 58 | 59 | pub(crate) fn tcp_copy(lw_tcp: LwIpTcpStream, tokio_tcp: TcpStream) { 60 | let (mut write, mut read) = lw_tcp.into_split(); 61 | let (mut peer_read, mut peer_write) = tokio_tcp.into_split(); 62 | tokio::spawn(async move { tokio::io::copy(&mut read, &mut peer_write).await }); 63 | tokio::spawn(async move { tokio::io::copy(&mut peer_read, &mut write).await }); 64 | } 65 | -------------------------------------------------------------------------------- /vn-link/src/out_mapping/udp.rs: -------------------------------------------------------------------------------- 1 | use crossbeam_utils::atomic::AtomicCell; 2 | use lwip_rs::udp::{UdpSocketRead, UdpSocketWrite}; 3 | use parking_lot::Mutex; 4 | use std::collections::HashMap; 5 | use std::net::{IpAddr, Ipv4Addr, SocketAddr}; 6 | use std::sync::Arc; 7 | use std::time::{Duration, Instant}; 8 | use tokio::net::UdpSocket; 9 | use vnt::handle::CurrentDeviceInfo; 10 | 11 | pub async fn udp_mapping_start( 12 | lwip_udp_write: UdpSocketWrite, 13 | mut lwip_udp_read: UdpSocketRead, 14 | current_device: Arc>, 15 | in_udp_map: Arc< 16 | Mutex< 17 | HashMap< 18 | (SocketAddr, SocketAddr), 19 | (Arc, Option, Arc>), 20 | >, 21 | >, 22 | >, 23 | ) { 24 | loop { 25 | let (buf, src, dest) = match lwip_udp_read.recv().await { 26 | Ok(rs) => rs, 27 | Err(e) => { 28 | log::warn!("udp_mapping err {:?}", e); 29 | break; 30 | } 31 | }; 32 | if let Err(e) = handle( 33 | ¤t_device, 34 | &lwip_udp_write, 35 | &in_udp_map, 36 | buf, 37 | src, 38 | dest, 39 | ) 40 | .await 41 | { 42 | log::warn!("udp_mapping err {}->{} {:?}", src, dest, e) 43 | } 44 | } 45 | } 46 | 47 | async fn handle( 48 | current_device: &AtomicCell, 49 | lwip_udp_write: &UdpSocketWrite, 50 | map: &Arc< 51 | Mutex< 52 | HashMap< 53 | (SocketAddr, SocketAddr), 54 | (Arc, Option, Arc>), 55 | >, 56 | >, 57 | >, 58 | buf: Vec, 59 | src: SocketAddr, 60 | dest: SocketAddr, 61 | ) -> anyhow::Result<()> { 62 | let option = map.lock().get(&(src, dest)).cloned(); 63 | 64 | if let Some((dest_udp, addr, time)) = option { 65 | time.store(Instant::now()); 66 | if let Some(addr) = addr { 67 | dest_udp.send_to(&buf, addr).await?; 68 | } else { 69 | dest_udp.send(&buf).await?; 70 | } 71 | } else { 72 | let mut real_dest = dest; 73 | let peer_udp_socket = match UdpSocket::bind(format!("0.0.0.0:{}", src.port())).await { 74 | Ok(udp) => udp, 75 | Err(_) => UdpSocket::bind("0.0.0.0:0").await?, 76 | }; 77 | if let IpAddr::V4(ip) = dest.ip() { 78 | let device_info = current_device.load(); 79 | if ip.is_unspecified() 80 | || ip.is_broadcast() 81 | || ip.is_multicast() 82 | || ip == device_info.virtual_ip 83 | || ip == device_info.broadcast_ip 84 | { 85 | //是自己 86 | real_dest.set_ip(IpAddr::V4(Ipv4Addr::LOCALHOST)); 87 | } 88 | } 89 | peer_udp_socket.connect(real_dest).await?; 90 | peer_udp_socket.send(&buf).await?; 91 | let peer_udp_socket = Arc::new(peer_udp_socket); 92 | let time = Arc::new(AtomicCell::new(Instant::now())); 93 | let map = map.clone(); 94 | map.lock() 95 | .insert((src, dest), (peer_udp_socket.clone(), None, time.clone())); 96 | let lwip_udp_write = lwip_udp_write.clone(); 97 | tokio::spawn(async move { 98 | peer_udp_handle(peer_udp_socket, lwip_udp_write, src, dest, time).await; 99 | map.lock().remove(&(src, dest)); 100 | }); 101 | } 102 | Ok(()) 103 | } 104 | 105 | async fn peer_udp_handle( 106 | peer_udp_socket: Arc, 107 | lwip_udp_write: UdpSocketWrite, 108 | src: SocketAddr, 109 | dest: SocketAddr, 110 | time: Arc>, 111 | ) { 112 | let mut buf = [0u8; 65536]; 113 | loop { 114 | match tokio::time::timeout(Duration::from_secs(600), peer_udp_socket.recv(&mut buf)).await { 115 | Ok(rs) => match rs { 116 | Ok(len) => match lwip_udp_write.send(&buf[..len], &dest, &src) { 117 | Ok(_) => {} 118 | Err(e) => { 119 | log::warn!("udp proxy {}->{} {:?}", dest, src, e); 120 | break; 121 | } 122 | }, 123 | Err(e) => { 124 | log::warn!("udp proxy {}->{} {:?}", dest, src, e); 125 | break; 126 | } 127 | }, 128 | Err(_) => { 129 | if time.load().elapsed() > Duration::from_secs(580) { 130 | //超时关闭 131 | log::warn!("udp proxy timeout {}->{}", dest, src,); 132 | break; 133 | } 134 | } 135 | } 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /vnt-cli/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "vnt-cli" 3 | version = "1.2.16" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | vnt = { path = "../vnt", package = "vnt", default-features = false, features = ["integrated_tun"] } 10 | common = { path = "../common", default-features = false, features = ["integrated_tun"] } 11 | log = "0.4.17" 12 | anyhow = "1.0.82" 13 | console = "0.15.2" 14 | 15 | [target.'cfg(any(target_os = "linux",target_os = "macos"))'.dependencies] 16 | sudo = "0.6.0" 17 | signal-hook = "0.3.17" 18 | 19 | [target.'cfg(target_os = "windows")'.dependencies] 20 | winapi = { version = "0.3.9", features = ["handleapi", "processthreadsapi", "winnt", "securitybaseapi", "impl-default"] } 21 | 22 | [features] 23 | default = ["default-feature"] 24 | default-feature = ["server_encrypt", "aes_gcm", "aes_cbc", "aes_ecb", "sm4_cbc", "chacha20_poly1305", "ip_proxy", "port_mapping", "log", "command", "file_config", "lz4", "ws"] 25 | 26 | openssl = ["vnt/openssl", "common/openssl"] 27 | openssl-vendored = ["vnt/openssl-vendored", "common/openssl-vendored"] 28 | ring-cipher = ["vnt/ring-cipher", "common/ring-cipher"] 29 | aes_cbc = ["vnt/aes_cbc", "common/aes_cbc"] 30 | aes_ecb = ["vnt/aes_ecb", "common/aes_ecb"] 31 | sm4_cbc = ["vnt/sm4_cbc", "common/sm4_cbc"] 32 | aes_gcm = ["vnt/aes_gcm", "common/aes_gcm"] 33 | chacha20_poly1305 = ["vnt/chacha20_poly1305", "common/chacha20_poly1305"] 34 | server_encrypt = ["vnt/server_encrypt", "common/server_encrypt"] 35 | port_mapping = ["vnt/port_mapping", "common/port_mapping"] 36 | lz4 = ["vnt/lz4_compress", "common/lz4"] 37 | zstd = ["vnt/zstd_compress", "common/zstd"] 38 | ip_proxy = ["vnt/ip_proxy", "common/ip_proxy"] 39 | upnp = ["vnt/upnp", "common/upnp"] 40 | ws = ["vnt/ws", "common/ws"] 41 | wss = ["vnt/wss", "common/wss"] 42 | log = ["common/log"] 43 | command = ["common/command"] 44 | file_config = ["common/file_config"] 45 | [build-dependencies] 46 | rand = "0.8.5" 47 | chrono = "0.4.23" -------------------------------------------------------------------------------- /vnt-cli/src/main.rs: -------------------------------------------------------------------------------- 1 | use common::callback; 2 | use console::style; 3 | use vnt::core::{Config, Vnt}; 4 | mod root_check; 5 | fn main() { 6 | let (config, _vnt_link_config, cmd) = match common::cli::parse_args_config() { 7 | Ok(rs) => { 8 | if let Some(rs) = rs { 9 | rs 10 | } else { 11 | return; 12 | } 13 | } 14 | Err(e) => { 15 | log::error!( 16 | "parse error={:?} cmd={:?}", 17 | e, 18 | std::env::args().collect::>() 19 | ); 20 | println!("{}", style(format!("Error {:?}", e)).red()); 21 | return; 22 | } 23 | }; 24 | main0(config, cmd) 25 | } 26 | fn main0(config: Config, _show_cmd: bool) { 27 | if !root_check::is_app_elevated() { 28 | println!("Please run it with administrator or root privileges"); 29 | #[cfg(any(target_os = "linux", target_os = "macos"))] 30 | sudo::escalate_if_needed().unwrap(); 31 | return; 32 | } 33 | #[cfg(feature = "port_mapping")] 34 | for (is_tcp, addr, dest) in config.port_mapping_list.iter() { 35 | if *is_tcp { 36 | println!("TCP port mapping {}->{}", addr, dest) 37 | } else { 38 | println!("UDP port mapping {}->{}", addr, dest) 39 | } 40 | } 41 | let vnt_util = match Vnt::new(config, callback::VntHandler {}) { 42 | Ok(vnt) => vnt, 43 | Err(e) => { 44 | log::error!("vnt create error {:?}", e); 45 | println!("error: {:?}", e); 46 | std::process::exit(1); 47 | } 48 | }; 49 | #[cfg(any(target_os = "linux", target_os = "macos"))] 50 | { 51 | let vnt_c = vnt_util.clone(); 52 | let mut signals = signal_hook::iterator::Signals::new(&[ 53 | signal_hook::consts::SIGINT, 54 | signal_hook::consts::SIGTERM, 55 | ]) 56 | .unwrap(); 57 | let handle = signals.handle(); 58 | std::thread::spawn(move || { 59 | for sig in signals.forever() { 60 | match sig { 61 | signal_hook::consts::SIGINT | signal_hook::consts::SIGTERM => { 62 | println!("Received SIGINT, {}", sig); 63 | vnt_c.stop(); 64 | handle.close(); 65 | break; 66 | } 67 | _ => {} 68 | } 69 | } 70 | }); 71 | } 72 | #[cfg(feature = "command")] 73 | { 74 | let vnt_c = vnt_util.clone(); 75 | std::thread::Builder::new() 76 | .name("CommandServer".into()) 77 | .spawn(move || { 78 | if let Err(e) = common::command::server::CommandServer::new().start(vnt_c) { 79 | log::warn!("cmd:{:?}", e); 80 | } 81 | }) 82 | .expect("CommandServer"); 83 | if _show_cmd { 84 | let mut cmd = String::new(); 85 | loop { 86 | cmd.clear(); 87 | println!("======== input:list,info,route,all,stop,chart_a,chart_b[:ip] ========"); 88 | match std::io::stdin().read_line(&mut cmd) { 89 | Ok(len) => { 90 | if !common::command::command_str(&cmd[..len], &vnt_util) { 91 | break; 92 | } 93 | } 94 | Err(e) => { 95 | println!("input err:{}", e); 96 | break; 97 | } 98 | } 99 | } 100 | } 101 | } 102 | 103 | vnt_util.wait() 104 | } 105 | -------------------------------------------------------------------------------- /vnt-cli/src/root_check/mod.rs: -------------------------------------------------------------------------------- 1 | #[cfg(target_os = "windows")] 2 | mod windows; 3 | 4 | #[cfg(target_os = "windows")] 5 | pub use windows::is_app_elevated; 6 | 7 | #[cfg(any(target_os = "linux", target_os = "macos"))] 8 | mod unix; 9 | 10 | #[cfg(any(target_os = "linux", target_os = "macos"))] 11 | pub use unix::is_app_elevated; 12 | -------------------------------------------------------------------------------- /vnt-cli/src/root_check/unix.rs: -------------------------------------------------------------------------------- 1 | pub fn is_app_elevated() -> bool { 2 | sudo::RunningAs::Root == sudo::check() 3 | } 4 | -------------------------------------------------------------------------------- /vnt-cli/src/root_check/windows.rs: -------------------------------------------------------------------------------- 1 | /// 使用 https://github.com/spa5k/is_sudo/blob/main/src/window.rs 2 | use std::io::Error; 3 | use std::ptr; 4 | 5 | use winapi::um::handleapi::CloseHandle; 6 | use winapi::um::processthreadsapi::{GetCurrentProcess, OpenProcessToken}; 7 | use winapi::um::securitybaseapi::GetTokenInformation; 8 | use winapi::um::winnt::{TokenElevation, HANDLE, TOKEN_ELEVATION, TOKEN_QUERY}; 9 | 10 | // Use std::io::Error::last_os_error for errors. 11 | // NOTE: For this example I'm simple passing on the OS error. 12 | // However, customising the error could provide more context 13 | 14 | /// Returns true if the current process has admin rights, otherwise false. 15 | pub fn is_app_elevated() -> bool { 16 | _is_app_elevated().unwrap_or(false) 17 | } 18 | 19 | /// On success returns a bool indicating if the current process has admin rights. 20 | /// Otherwise returns an OS error. 21 | /// 22 | /// This is unlikely to fail but if it does it's even more unlikely that you have admin permissions anyway. 23 | /// Therefore the public function above simply eats the error and returns a bool. 24 | fn _is_app_elevated() -> Result { 25 | let token = QueryAccessToken::from_current_process()?; 26 | token.is_elevated() 27 | } 28 | 29 | /// A safe wrapper around querying Windows access tokens. 30 | pub struct QueryAccessToken(HANDLE); 31 | 32 | impl QueryAccessToken { 33 | pub fn from_current_process() -> Result { 34 | unsafe { 35 | let mut handle: HANDLE = ptr::null_mut(); 36 | let result = OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &mut handle); 37 | 38 | if result != 0 { 39 | Ok(Self(handle)) 40 | } else { 41 | Err(Error::last_os_error()) 42 | } 43 | } 44 | } 45 | 46 | /// On success returns a bool indicating if the access token has elevated privilidges. 47 | /// Otherwise returns an OS error. 48 | pub fn is_elevated(&self) -> Result { 49 | unsafe { 50 | let mut elevation = TOKEN_ELEVATION::default(); 51 | let size = std::mem::size_of::() as u32; 52 | let mut ret_size = size; 53 | // The weird looking repetition of `as *mut _` is casting the reference to a c_void pointer. 54 | if GetTokenInformation( 55 | self.0, 56 | TokenElevation, 57 | &mut elevation as *mut _ as *mut _, 58 | size, 59 | &mut ret_size, 60 | ) != 0 61 | { 62 | Ok(elevation.TokenIsElevated != 0) 63 | } else { 64 | Err(Error::last_os_error()) 65 | } 66 | } 67 | } 68 | } 69 | 70 | impl Drop for QueryAccessToken { 71 | fn drop(&mut self) { 72 | if !self.0.is_null() { 73 | unsafe { CloseHandle(self.0) }; 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /vnt/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "vnt" 3 | version = "1.2.16" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | http_req = { git = "https://github.com/lmq8267/http_req.git", default-features = false, features = ["rust-tls"] } 10 | tun-rs = { version = "2", optional = true, features = ["experimental"] } 11 | packet = { path = "./packet" } 12 | bytes = "1.5.0" 13 | log = "0.4.17" 14 | libc = "0.2.137" 15 | crossbeam-utils = "0.8" 16 | crossbeam-epoch = "0.9.15" 17 | parking_lot = "0.12.1" 18 | rand = "0.8.5" 19 | sha2 = { version = "0.10.6", features = ["oid"] } 20 | thiserror = "1.0.37" 21 | protobuf = "=3.2.0" 22 | socket2 = { version = "0.5.7", features = ["all"] } 23 | aes-gcm = { version = "0.10.2", optional = true } 24 | ring = { version = "0.17.0", optional = true } 25 | cbc = { version = "0.1.2", optional = true } 26 | ecb = { version = "0.1.2", optional = true } 27 | chacha20poly1305 = { version = "0.10.1", optional = true } 28 | chacha20 = { version = "0.9.1", optional = true } 29 | aes = "0.8.3" 30 | stun-format = { version = "1.0.1", features = ["fmt", "rfc3489"] } 31 | rsa = { version = "0.9.2", features = [], optional = true } 32 | spki = { version = "0.7.2", features = ["fingerprint", "alloc", "base64"], optional = true } 33 | openssl-sys = { git = "https://github.com/vnt-dev/rust-openssl", optional = true } 34 | libsm = { git = "https://github.com/vnt-dev/libsm", optional = true } 35 | 36 | mio = { version = "=0.8.11", features = ["os-poll", "net", "os-ext"] } 37 | crossbeam-queue = "0.3.11" 38 | anyhow = "1.0.82" 39 | dns-parser = "0.8.0" 40 | 41 | tokio = { version = "1.37.0", features = ["full"] } 42 | 43 | lz4_flex = { version = "0.11", default-features = false, optional = true } 44 | zstd = { version = "0.13.1", optional = true } 45 | 46 | fnv = "1.0.7" 47 | igd = { version = "0.12.1", optional = true } 48 | tokio-tungstenite = { version = "0.23.1", optional = true } 49 | rustls = { version = "0.23.0", features = ["ring"], default-features = false, optional = true } 50 | 51 | network-interface = "2.0.0" 52 | 53 | futures-util = "0.3.30" 54 | [target.'cfg(target_os = "windows")'.dependencies] 55 | libloading = "0.8.0" 56 | windows-sys = { version = "0.59.0", features = ["Win32_Foundation", 57 | "Win32_NetworkManagement", 58 | "Win32_NetworkManagement_IpHelper", 59 | "Win32_Networking_WinSock", 60 | "Win32_System_IO", 61 | "Win32_System_Threading", 62 | "Win32_System_WindowsProgramming", ] } 63 | 64 | [build-dependencies] 65 | protobuf-codegen = "=3.2.0" 66 | protoc-bin-vendored = "3.0.0" 67 | cfg_aliases = "0.2.1" 68 | 69 | [features] 70 | default = ["server_encrypt", "aes_gcm", "aes_cbc", "aes_ecb", "sm4_cbc", "chacha20_poly1305", "ip_proxy", "port_mapping", "lz4_compress", "zstd_compress", "integrated_tun"] 71 | openssl = ["openssl-sys"] 72 | # 从源码编译 73 | openssl-vendored = ["openssl-sys/vendored"] 74 | ring-cipher = ["ring"] 75 | aes_cbc = ["cbc"] 76 | aes_ecb = ["ecb"] 77 | sm4_cbc = ["libsm"] 78 | aes_gcm = ["aes-gcm"] 79 | chacha20_poly1305 = ["chacha20poly1305", "chacha20"] 80 | server_encrypt = ["aes-gcm", "rsa", "spki"] 81 | ip_proxy = [] 82 | port_mapping = [] 83 | lz4_compress = ["lz4_flex"] 84 | zstd_compress = ["zstd"] 85 | integrated_tun = ["tun-rs"] 86 | upnp = ["igd"] 87 | ws = ["tokio-tungstenite"] 88 | wss = ["ws", "tokio-tungstenite/rustls-tls-native-roots", "tokio-tungstenite/rustls-tls-webpki-roots", "rustls"] 89 | -------------------------------------------------------------------------------- /vnt/build.rs: -------------------------------------------------------------------------------- 1 | use cfg_aliases::cfg_aliases; 2 | 3 | fn main() { 4 | cfg_aliases! { 5 | cipher: { 6 | any(feature = "aes_gcm", 7 | feature = "chacha20_poly1305", 8 | feature = "server_encrypt", 9 | feature = "aes_cbc", 10 | feature = "aes_ecb", 11 | feature = "sm4_cbc" 12 | )}, 13 | } 14 | 15 | std::fs::create_dir_all("src/proto").unwrap(); 16 | protobuf_codegen::Codegen::new() 17 | .pure() 18 | .out_dir("src/proto") 19 | .inputs(&["proto/message.proto"]) 20 | .include("proto") 21 | // .customize( 22 | // protobuf_codegen::Customize::default() 23 | // .tokio_bytes(true) 24 | // ) 25 | .run() 26 | .expect("Codegen failed."); 27 | } 28 | -------------------------------------------------------------------------------- /vnt/packet/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "packet" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | byteorder = "1.4.3" 10 | -------------------------------------------------------------------------------- /vnt/packet/src/arp/arp.rs: -------------------------------------------------------------------------------- 1 | use std::{fmt, io}; 2 | 3 | /// 地址解析协议,由IP地址找到MAC地址 4 | /// https://www.ietf.org/rfc/rfc6747.txt 5 | /* 6 | 0 2 4 5 6 8 10 (字节) 7 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 8 | | 硬件类型|协议类型|硬件地址长度|协议地址长度|操作类型| 9 | | 源MAC地址 | 源ip地址 | 10 | | 目的MAC地址 | 目的ip地址 | 11 | */ 12 | 13 | pub struct ArpPacket { 14 | buffer: B, 15 | } 16 | 17 | impl> ArpPacket { 18 | pub fn unchecked(buffer: B) -> Self { 19 | Self { buffer } 20 | } 21 | pub fn new(buffer: B) -> io::Result { 22 | if buffer.as_ref().len() != 28 { 23 | Err(io::Error::from(io::ErrorKind::InvalidData))?; 24 | } 25 | let packet = Self::unchecked(buffer); 26 | Ok(packet) 27 | } 28 | } 29 | 30 | impl> ArpPacket { 31 | /// 硬件类型 以太网类型为1 32 | pub fn hardware_type(&self) -> u16 { 33 | u16::from_be_bytes(self.buffer.as_ref()[0..2].try_into().unwrap()) 34 | } 35 | /// 上层协议类型,ipv4是0x0800 36 | pub fn protocol_type(&self) -> u16 { 37 | u16::from_be_bytes(self.buffer.as_ref()[2..4].try_into().unwrap()) 38 | } 39 | /// 如果是MAC地址 则长度为6 40 | pub fn hardware_size(&self) -> u8 { 41 | self.buffer.as_ref()[4] 42 | } 43 | /// 如果是IPv4 则长度为4 44 | pub fn protocol_size(&self) -> u8 { 45 | self.buffer.as_ref()[5] 46 | } 47 | /// 操作类型,请求和响应 1:ARP请求,2:ARP响应,3:RARP请求,4:RARP响应 48 | pub fn op_code(&self) -> u16 { 49 | u16::from_be_bytes(self.buffer.as_ref()[6..8].try_into().unwrap()) 50 | } 51 | /// 发送端硬件地址,仅支持以太网 52 | pub fn sender_hardware_addr(&self) -> &[u8] { 53 | &self.buffer.as_ref()[8..14] 54 | } 55 | /// 发送端协议地址,仅支持IPv4 56 | pub fn sender_protocol_addr(&self) -> &[u8] { 57 | &self.buffer.as_ref()[14..18] 58 | } 59 | /// 接收端硬件地址,仅支持以太网 60 | pub fn target_hardware_addr(&self) -> &[u8] { 61 | &self.buffer.as_ref()[18..24] 62 | } 63 | /// 接收端协议地址,仅支持IPv4 64 | pub fn target_protocol_addr(&self) -> &[u8] { 65 | &self.buffer.as_ref()[24..28] 66 | } 67 | } 68 | 69 | impl + AsMut<[u8]>> ArpPacket { 70 | /// 硬件类型 以太网类型为1 71 | pub fn set_hardware_type(&mut self, value: u16) { 72 | self.buffer.as_mut()[0..2].copy_from_slice(&value.to_be_bytes()) 73 | } 74 | /// 上层协议类型,ipv4是0x0800 75 | pub fn set_protocol_type(&mut self, value: u16) { 76 | self.buffer.as_mut()[2..4].copy_from_slice(&value.to_be_bytes()) 77 | } 78 | /// 如果是MAC地址 则长度为6 79 | pub fn set_hardware_size(&mut self, value: u8) { 80 | self.buffer.as_mut()[4] = value 81 | } 82 | /// 如果是IPv4 则长度为4 83 | pub fn set_protocol_size(&mut self, value: u8) { 84 | self.buffer.as_mut()[5] = value 85 | } 86 | /// 操作类型,请求和响应 1:ARP请求,2:ARP响应,3:RARP请求,4:RARP响应 87 | pub fn set_op_code(&mut self, value: u16) { 88 | self.buffer.as_mut()[6..8].copy_from_slice(&value.to_be_bytes()) 89 | } 90 | /// 发送端硬件地址,仅支持以太网 91 | pub fn set_sender_hardware_addr(&mut self, buf: &[u8]) { 92 | self.buffer.as_mut()[8..14].copy_from_slice(buf) 93 | } 94 | /// 发送端协议地址,仅支持IPv4 95 | pub fn set_sender_protocol_addr(&mut self, buf: &[u8]) { 96 | self.buffer.as_mut()[14..18].copy_from_slice(buf) 97 | } 98 | /// 接收端硬件地址,仅支持以太网 99 | pub fn set_target_hardware_addr(&mut self, buf: &[u8]) { 100 | self.buffer.as_mut()[18..24].copy_from_slice(buf) 101 | } 102 | /// 接收端协议地址,仅支持IPv4 103 | pub fn set_target_protocol_addr(&mut self, buf: &[u8]) { 104 | self.buffer.as_mut()[24..28].copy_from_slice(buf) 105 | } 106 | } 107 | 108 | impl> fmt::Debug for ArpPacket { 109 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 110 | f.debug_struct("ArpPacket") 111 | .field("hardware_type", &self.hardware_type()) 112 | .field("protocol_type", &self.protocol_type()) 113 | .field("hardware_size", &self.hardware_size()) 114 | .field("protocol_size", &self.protocol_size()) 115 | .field("op_code", &self.op_code()) 116 | .field("sender_hardware_addr", &self.sender_hardware_addr()) 117 | .field("sender_protocol_addr", &self.sender_protocol_addr()) 118 | .field("target_hardware_addr", &self.target_hardware_addr()) 119 | .field("target_protocol_addr", &self.target_protocol_addr()) 120 | .finish() 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /vnt/packet/src/arp/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod arp; 2 | -------------------------------------------------------------------------------- /vnt/packet/src/ethernet/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod packet; 2 | pub mod protocol; 3 | -------------------------------------------------------------------------------- /vnt/packet/src/ethernet/packet.rs: -------------------------------------------------------------------------------- 1 | use crate::ethernet::protocol::Protocol; 2 | use std::{fmt, io}; 3 | 4 | /// 以太网帧协议 5 | /// https://www.ietf.org/rfc/rfc894.txt 6 | /* 7 | 0 6 12 14 (字节) 8 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 9 | | 目的地址 | 源地址 | 类型 | 10 | */ 11 | pub struct EthernetPacket { 12 | pub buffer: B, 13 | } 14 | 15 | impl> EthernetPacket { 16 | pub fn unchecked(buffer: B) -> EthernetPacket { 17 | EthernetPacket { buffer } 18 | } 19 | 20 | pub fn new(buffer: B) -> io::Result> { 21 | let packet = EthernetPacket::unchecked(buffer); 22 | //头部固定14位 23 | if packet.buffer.as_ref().len() < 14 { 24 | Err(io::Error::from(io::ErrorKind::InvalidData))?; 25 | } 26 | 27 | Ok(packet) 28 | } 29 | } 30 | 31 | impl> EthernetPacket { 32 | /// 目的MAC地址 33 | pub fn destination(&self) -> &[u8] { 34 | &self.buffer.as_ref()[0..6] 35 | } 36 | /// 源MAC地址 37 | pub fn source(&self) -> &[u8] { 38 | &self.buffer.as_ref()[6..12] 39 | } 40 | /// 3层协议 41 | pub fn protocol(&self) -> Protocol { 42 | u16::from_be_bytes(self.buffer.as_ref()[12..14].try_into().unwrap()).into() 43 | } 44 | /// 载荷 45 | pub fn payload(&self) -> &[u8] { 46 | &self.buffer.as_ref()[14..] 47 | } 48 | } 49 | 50 | impl + AsMut<[u8]>> EthernetPacket { 51 | pub fn set_destination(&mut self, value: &[u8]) { 52 | self.buffer.as_mut()[0..6].copy_from_slice(value); 53 | } 54 | 55 | pub fn set_source(&mut self, value: &[u8]) { 56 | self.buffer.as_mut()[6..12].copy_from_slice(value); 57 | } 58 | 59 | pub fn set_protocol(&mut self, value: Protocol) { 60 | let p: u16 = value.into(); 61 | self.buffer.as_mut()[12..14].copy_from_slice(&p.to_be_bytes()) 62 | } 63 | pub fn payload_mut(&mut self) -> &mut [u8] { 64 | &mut self.buffer.as_mut()[14..] 65 | } 66 | } 67 | 68 | impl> fmt::Debug for EthernetPacket { 69 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 70 | f.debug_struct("EthernetPacket") 71 | .field("destination", &self.destination()) 72 | .field("source", &self.source()) 73 | .field("protocol", &self.protocol()) 74 | .field("payload", &self.payload()) 75 | .finish() 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /vnt/packet/src/ethernet/protocol.rs: -------------------------------------------------------------------------------- 1 | /// 以太网帧协议 2 | #[derive(Eq, PartialEq, Copy, Clone, Debug)] 3 | pub enum Protocol { 4 | /// 5 | Ipv4, 6 | 7 | /// 8 | Arp, 9 | 10 | /// 11 | WakeOnLan, 12 | 13 | /// 14 | Trill, 15 | 16 | /// 17 | DecNet, 18 | 19 | /// 20 | Rarp, 21 | 22 | /// 23 | AppleTalk, 24 | 25 | /// 26 | Aarp, 27 | 28 | /// 29 | Ipx, 30 | 31 | /// 32 | Qnx, 33 | 34 | /// 35 | Ipv6, 36 | 37 | /// 38 | FlowControl, 39 | 40 | /// 41 | CobraNet, 42 | 43 | /// 44 | Mpls, 45 | 46 | /// 47 | MplsMulticast, 48 | 49 | /// 50 | PppoeDiscovery, 51 | 52 | /// 53 | PppoeSession, 54 | 55 | /// 56 | Vlan, 57 | 58 | /// 59 | PBridge, 60 | 61 | /// 62 | Lldp, 63 | 64 | /// 65 | Ptp, 66 | 67 | /// 68 | Cfm, 69 | 70 | /// 71 | QinQ, 72 | 73 | /// 74 | Unknown(u16), 75 | } 76 | 77 | impl From for Protocol { 78 | fn from(value: u16) -> Protocol { 79 | use self::Protocol::*; 80 | 81 | match value { 82 | 0x0800 => Ipv4, 83 | 0x0806 => Arp, 84 | 0x0842 => WakeOnLan, 85 | 0x22f3 => Trill, 86 | 0x6003 => DecNet, 87 | 0x8035 => Rarp, 88 | 0x809b => AppleTalk, 89 | 0x80f3 => Aarp, 90 | 0x8137 => Ipx, 91 | 0x8204 => Qnx, 92 | 0x86dd => Ipv6, 93 | 0x8808 => FlowControl, 94 | 0x8819 => CobraNet, 95 | 0x8847 => Mpls, 96 | 0x8848 => MplsMulticast, 97 | 0x8863 => PppoeDiscovery, 98 | 0x8864 => PppoeSession, 99 | 0x8100 => Vlan, 100 | 0x88a8 => PBridge, 101 | 0x88cc => Lldp, 102 | 0x88f7 => Ptp, 103 | 0x8902 => Cfm, 104 | 0x9100 => QinQ, 105 | n => Unknown(n), 106 | } 107 | } 108 | } 109 | 110 | impl Into for Protocol { 111 | fn into(self) -> u16 { 112 | use self::Protocol::*; 113 | 114 | match self { 115 | Ipv4 => 0x0800, 116 | Arp => 0x0806, 117 | WakeOnLan => 0x0842, 118 | Trill => 0x22f3, 119 | DecNet => 0x6003, 120 | Rarp => 0x8035, 121 | AppleTalk => 0x809b, 122 | Aarp => 0x80f3, 123 | Ipx => 0x8137, 124 | Qnx => 0x8204, 125 | Ipv6 => 0x86dd, 126 | FlowControl => 0x8808, 127 | CobraNet => 0x8819, 128 | Mpls => 0x8847, 129 | MplsMulticast => 0x8848, 130 | PppoeDiscovery => 0x8863, 131 | PppoeSession => 0x8864, 132 | Vlan => 0x8100, 133 | PBridge => 0x88a8, 134 | Lldp => 0x88cc, 135 | Ptp => 0x88f7, 136 | Cfm => 0x8902, 137 | QinQ => 0x9100, 138 | Unknown(n) => n, 139 | } 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /vnt/packet/src/igmp/igmp_v1.rs: -------------------------------------------------------------------------------- 1 | use crate::cal_checksum; 2 | use std::net::Ipv4Addr; 3 | use std::{fmt, io}; 4 | 5 | /// igmp v1 6 | /* https://datatracker.ietf.org/doc/html/rfc1112 7 | 0 1 2 3 8 | 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 9 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 10 | |Version| Type | Unused | Checksum | 11 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 12 | | Group Address | 13 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 14 | */ 15 | /// v1版本的报文 16 | pub struct IgmpV1Packet { 17 | pub buffer: B, 18 | } 19 | 20 | #[derive(Debug, Copy, Clone, Eq, PartialEq)] 21 | pub enum IgmpV1Type { 22 | /// 0x11 所有组224.0.0.1或者特定组 23 | Query, 24 | /// 0x12 25 | ReportV1, 26 | Unknown(u8), 27 | } 28 | 29 | impl From for IgmpV1Type { 30 | fn from(value: u8) -> IgmpV1Type { 31 | use self::IgmpV1Type::*; 32 | 33 | match value { 34 | 0x11 => Query, 35 | 0x12 => ReportV1, 36 | v => Unknown(v), 37 | } 38 | } 39 | } 40 | 41 | impl Into for IgmpV1Type { 42 | fn into(self) -> u8 { 43 | match self { 44 | IgmpV1Type::Query => 0x11, 45 | IgmpV1Type::ReportV1 => 0x12, 46 | IgmpV1Type::Unknown(v) => v, 47 | } 48 | } 49 | } 50 | 51 | impl> IgmpV1Packet { 52 | pub fn unchecked(buffer: B) -> Self { 53 | Self { buffer } 54 | } 55 | pub fn new(buffer: B) -> io::Result { 56 | if buffer.as_ref().len() != 8 { 57 | Err(io::Error::from(io::ErrorKind::InvalidData)) 58 | } else { 59 | let packet = Self::unchecked(buffer); 60 | Ok(packet) 61 | } 62 | } 63 | } 64 | 65 | impl> IgmpV1Packet { 66 | pub fn version(&self) -> u8 { 67 | self.buffer.as_ref()[0] >> 4 68 | } 69 | pub fn igmp_type(&self) -> IgmpV1Type { 70 | IgmpV1Type::from(self.buffer.as_ref()[0] & 0x0F) 71 | } 72 | pub fn unused(&self) -> u8 { 73 | self.buffer.as_ref()[1] 74 | } 75 | pub fn checksum(&self) -> u16 { 76 | u16::from_be_bytes(self.buffer.as_ref()[2..4].try_into().unwrap()) 77 | } 78 | pub fn is_valid(&self) -> bool { 79 | self.checksum() == 0 || cal_checksum(self.buffer.as_ref()) == 0 80 | } 81 | pub fn group_address(&self) -> Ipv4Addr { 82 | let tmp: [u8; 4] = self.buffer.as_ref()[4..8].try_into().unwrap(); 83 | Ipv4Addr::from(tmp) 84 | } 85 | } 86 | 87 | impl + AsMut<[u8]>> IgmpV1Packet { 88 | pub fn set_version(&mut self, version: u8) { 89 | self.buffer.as_mut()[0] = (version << 4) | 0x0F & self.buffer.as_mut()[0] 90 | } 91 | pub fn set_type(&mut self, igmp_type: IgmpV1Type) { 92 | let t: u8 = igmp_type.into(); 93 | self.buffer.as_mut()[0] = self.buffer.as_mut()[0] & 0xF0 | t 94 | } 95 | pub fn set_checksum(&mut self, checksum: u16) { 96 | self.buffer.as_mut()[2..4].copy_from_slice(&checksum.to_be_bytes()); 97 | } 98 | pub fn update_checksum(&mut self) { 99 | self.set_checksum(0); 100 | self.set_checksum(cal_checksum(self.buffer.as_ref())); 101 | } 102 | pub fn set_group_address(&mut self, group_address: Ipv4Addr) { 103 | self.buffer.as_mut()[4..8].copy_from_slice(&group_address.octets()); 104 | } 105 | } 106 | 107 | impl> fmt::Debug for IgmpV1Packet { 108 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 109 | f.debug_struct("igmp::V1") 110 | .field("version", &self.version()) 111 | .field("type", &self.igmp_type()) 112 | .field("checksum", &self.checksum()) 113 | .field("is_valid", &self.is_valid()) 114 | .field("group_address", &self.group_address()) 115 | .finish() 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /vnt/packet/src/igmp/igmp_v2.rs: -------------------------------------------------------------------------------- 1 | use crate::cal_checksum; 2 | use std::net::Ipv4Addr; 3 | use std::{fmt, io}; 4 | 5 | /// igmp v2 6 | /* https://www.rfc-editor.org/rfc/rfc2236.html 7 | 8 | 0 1 2 3 9 | 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 10 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 11 | | Type | Max Resp Time | Checksum | 12 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 13 | | Group Address | 14 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 15 | */ 16 | 17 | /// v2版本的报文 18 | pub struct IgmpV2Packet { 19 | pub buffer: B, 20 | } 21 | 22 | #[derive(Debug, Copy, Clone, Eq, PartialEq)] 23 | pub enum IgmpV2Type { 24 | /// 0x11 所有组224.0.0.1或者特定组 25 | Query, 26 | /// 0x16 27 | ReportV2, 28 | LeaveV2, 29 | Unknown(u8), 30 | } 31 | 32 | impl From for IgmpV2Type { 33 | fn from(value: u8) -> IgmpV2Type { 34 | use self::IgmpV2Type::*; 35 | 36 | match value { 37 | 0x11 => Query, 38 | 0x16 => ReportV2, 39 | 0x17 => LeaveV2, 40 | v => Unknown(v), 41 | } 42 | } 43 | } 44 | 45 | impl Into for IgmpV2Type { 46 | fn into(self) -> u8 { 47 | match self { 48 | IgmpV2Type::Query => 0x11, 49 | IgmpV2Type::ReportV2 => 0x16, 50 | IgmpV2Type::LeaveV2 => 0x17, 51 | IgmpV2Type::Unknown(v) => v, 52 | } 53 | } 54 | } 55 | 56 | impl> IgmpV2Packet { 57 | pub fn unchecked(buffer: B) -> Self { 58 | Self { buffer } 59 | } 60 | pub fn new(buffer: B) -> io::Result { 61 | if buffer.as_ref().len() != 8 { 62 | Err(io::Error::from(io::ErrorKind::InvalidData)) 63 | } else { 64 | let packet = Self::unchecked(buffer); 65 | Ok(packet) 66 | } 67 | } 68 | } 69 | 70 | impl> IgmpV2Packet { 71 | pub fn igmp_type(&self) -> IgmpV2Type { 72 | IgmpV2Type::from(self.buffer.as_ref()[0]) 73 | } 74 | pub fn max_resp_time(&self) -> u8 { 75 | self.buffer.as_ref()[1] 76 | } 77 | pub fn checksum(&self) -> u16 { 78 | u16::from_be_bytes(self.buffer.as_ref()[2..4].try_into().unwrap()) 79 | } 80 | pub fn is_valid(&self) -> bool { 81 | self.checksum() == 0 || cal_checksum(self.buffer.as_ref()) == 0 82 | } 83 | pub fn group_address(&self) -> Ipv4Addr { 84 | let tmp: [u8; 4] = self.buffer.as_ref()[4..8].try_into().unwrap(); 85 | Ipv4Addr::from(tmp) 86 | } 87 | } 88 | 89 | impl + AsMut<[u8]>> IgmpV2Packet { 90 | pub fn set_type(&mut self, igmp_type: IgmpV2Type) { 91 | self.buffer.as_mut()[0] = igmp_type.into() 92 | } 93 | pub fn set_max_resp_time(&mut self, resp: u8) { 94 | self.buffer.as_mut()[1] = resp 95 | } 96 | pub fn set_checksum(&mut self, checksum: u16) { 97 | self.buffer.as_mut()[2..4].copy_from_slice(&checksum.to_be_bytes()); 98 | } 99 | pub fn update_checksum(&mut self) { 100 | self.set_checksum(0); 101 | self.set_checksum(cal_checksum(self.buffer.as_ref())); 102 | } 103 | pub fn set_group_address(&mut self, group_address: Ipv4Addr) { 104 | self.buffer.as_mut()[4..8].copy_from_slice(&group_address.octets()); 105 | } 106 | } 107 | 108 | impl> fmt::Debug for IgmpV2Packet { 109 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 110 | f.debug_struct("igmp::V2") 111 | .field("type", &self.igmp_type()) 112 | .field("max_resp_time", &self.max_resp_time()) 113 | .field("checksum", &self.checksum()) 114 | .field("is_valid", &self.is_valid()) 115 | .field("group_address", &self.group_address()) 116 | .finish() 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /vnt/packet/src/igmp/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod igmp_v1; 2 | pub mod igmp_v2; 3 | pub mod igmp_v3; 4 | 5 | #[derive(Debug, Copy, Clone, Eq, PartialEq)] 6 | pub enum IgmpType { 7 | /// 0x11 所有组224.0.0.1或者特定组 8 | Query, 9 | /// 0x12 10 | ReportV1, 11 | /// 0x16 12 | ReportV2, 13 | /// 0x22 14 | ReportV3, 15 | /// 0x17 目标组固定是 224.0.0.2 16 | LeaveV2, 17 | Unknown(u8), 18 | } 19 | 20 | impl From for IgmpType { 21 | fn from(value: u8) -> IgmpType { 22 | use self::IgmpType::*; 23 | 24 | match value { 25 | 0x11 => Query, 26 | 0x12 => ReportV1, 27 | 0x16 => ReportV2, 28 | 0x22 => ReportV3, 29 | 0x17 => LeaveV2, 30 | v => Unknown(v), 31 | } 32 | } 33 | } 34 | 35 | impl Into for IgmpType { 36 | fn into(self) -> u8 { 37 | match self { 38 | IgmpType::Query => 0x11, 39 | IgmpType::ReportV1 => 0x12, 40 | IgmpType::ReportV2 => 0x16, 41 | IgmpType::ReportV3 => 0x22, 42 | IgmpType::LeaveV2 => 0x17, 43 | IgmpType::Unknown(v) => v, 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /vnt/packet/src/ip/ipv4/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod packet; 2 | pub mod protocol; 3 | -------------------------------------------------------------------------------- /vnt/packet/src/ip/mod.rs: -------------------------------------------------------------------------------- 1 | use ipv4::packet::IpV4Packet; 2 | use std::io; 3 | 4 | pub mod ipv4; 5 | 6 | pub enum IpPacket { 7 | V4(IpV4Packet), 8 | } 9 | 10 | impl> IpPacket { 11 | pub fn new(buffer: B) -> io::Result { 12 | match buffer.as_ref()[0] >> 4 { 13 | 4 => Ok(IpPacket::V4(IpV4Packet::new(buffer)?)), 14 | _ => Err(io::Error::from(io::ErrorKind::InvalidData)), 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /vnt/packet/src/lib.rs: -------------------------------------------------------------------------------- 1 | use std::net::Ipv4Addr; 2 | 3 | use byteorder::BigEndian; 4 | use byteorder::ReadBytesExt; 5 | 6 | pub mod arp; 7 | pub mod ethernet; 8 | pub mod icmp; 9 | pub mod igmp; 10 | pub mod ip; 11 | pub mod tcp; 12 | pub mod udp; 13 | // pub enum IpUpperLayer { 14 | // UDP(UdpPacket), 15 | // Unknown(B), 16 | // } 17 | // 18 | // impl> fmt::Debug for IpUpperLayer { 19 | // fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 20 | // match self { 21 | // IpUpperLayer::UDP(p) => { 22 | // f.debug_struct("udp::Packet") 23 | // .field("data", p).finish() 24 | // } 25 | // IpUpperLayer::Unknown(p) => { 26 | // f.debug_struct("Unknown") 27 | // .field("data", &p.as_ref()).finish() 28 | // } 29 | // } 30 | // } 31 | // } 32 | 33 | /// https://datatracker.ietf.org/doc/html/rfc1071 4.1节 34 | /// 35 | /// 计算校验和,各协议都是通用的 36 | /// 计算: 37 | /// 首先将校验和置0,然后对首部每个16位数进行二进制反码求和, 38 | /// 得到校验和之后,持续取高16位加到低16位,直到高16位全为0 39 | /// 最后取反 40 | /// 41 | /// 校验: 42 | /// 在已有校验和的情况下,再计算校验和,正确的数据计算得到的值为0 43 | /* 44 | unsigned short getChecksum(unsigned short * iphead, int count) 45 | { 46 | unsigned long int sum = 0; 47 | unsigned short checksum = 0; 48 | 49 | printf("\nStarting adress: %p\n", iphead); 50 | 51 | while(count > 1) { 52 | sum += * (unsigned short *) (iphead); 53 | count -=2; 54 | printf("a: %p, content is: %d, new sum: %ld\n", iphead, (unsigned short) *(iphead), sum); 55 | iphead++; 56 | } 57 | 58 | if(count > 0) { 59 | sum += * (unsigned short *) (iphead); 60 | } 61 | 62 | while(sum >> 16) { 63 | sum = (sum & 0xffff) + (sum >> 16); 64 | } 65 | 66 | checksum = ~sum; 67 | 68 | return checksum; 69 | } 70 | */ 71 | pub fn cal_checksum(buffer: &[u8]) -> u16 { 72 | use std::io::Cursor; 73 | let mut sum = 0; 74 | let mut buffer = Cursor::new(buffer); 75 | while let Ok(value) = buffer.read_u16::() { 76 | sum += u32::from(value); 77 | } 78 | if let Ok(l) = buffer.read_u8() { 79 | sum += u32c(l, 0); 80 | } 81 | while sum >> 16 != 0 { 82 | sum = (sum & 0xffff) + (sum >> 16); 83 | } 84 | !sum as u16 85 | } 86 | 87 | /// ipv4上层协议校验和计算方式 88 | /// ipv4 udp伪首部 用于参与计算首部校验和 89 | /* 90 | 0 7 8 15 16 23 24 31 91 | +--------+--------+--------+--------+ 92 | | source address | 93 | +--------+--------+--------+--------+ 94 | | destination address | 95 | +--------+--------+--------+--------+ 96 | | zero |protocol| length | 97 | +--------+--------+--------+--------+ 98 | */ 99 | pub fn ipv4_cal_checksum( 100 | buffer: &[u8], 101 | src_ip: &Ipv4Addr, 102 | dest_ip: &Ipv4Addr, 103 | protocol: u8, 104 | ) -> u16 { 105 | use std::io::Cursor; 106 | let length = buffer.len(); 107 | let mut sum = 0; 108 | let src_ip = src_ip.octets(); 109 | sum += u32c(src_ip[0], src_ip[1]); 110 | sum += u32c(src_ip[2], src_ip[3]); 111 | let dest_ip = dest_ip.octets(); 112 | sum += u32c(dest_ip[0], dest_ip[1]); 113 | sum += u32c(dest_ip[2], dest_ip[3]); 114 | sum += u32c(0, protocol); 115 | sum += length as u32; 116 | let mut buffer = Cursor::new(buffer); 117 | while let Ok(value) = buffer.read_u16::() { 118 | sum += u32::from(value); 119 | } 120 | if let Ok(l) = buffer.read_u8() { 121 | sum += u32c(l, 0); 122 | } 123 | while sum >> 16 != 0 { 124 | sum = (sum & 0xffff) + (sum >> 16); 125 | } 126 | !sum as u16 127 | } 128 | 129 | #[inline] 130 | fn u32c(x: u8, y: u8) -> u32 { 131 | ((x as u32) << 8) | y as u32 132 | } 133 | 134 | #[cfg(test)] 135 | mod tests { 136 | use super::*; 137 | 138 | #[test] 139 | fn it_works() { 140 | let sum = cal_checksum(&[255, 255]); 141 | println!("{:?}", sum); 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /vnt/packet/src/tcp/mod.rs: -------------------------------------------------------------------------------- 1 | use std::fmt; 2 | 3 | pub mod tcp; 4 | 5 | pub struct Flags(u8); 6 | 7 | pub const FIN: u8 = 0b0000_0001; 8 | pub const SYN: u8 = 0b0000_0010; 9 | pub const RST: u8 = 0b0000_0100; 10 | pub const PSH: u8 = 0b0000_1000; 11 | pub const ACK: u8 = 0b0001_0000; 12 | pub const URG: u8 = 0b0010_0000; 13 | 14 | impl fmt::Debug for Flags { 15 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 16 | let mut str = String::with_capacity(22); 17 | if self.0 & URG != 0 { 18 | str.push_str("URG|"); 19 | } 20 | if self.0 & ACK != 0 { 21 | str.push_str("ACK|"); 22 | } 23 | if self.0 & PSH != 0 { 24 | str.push_str("PSH|"); 25 | } 26 | if self.0 & RST != 0 { 27 | str.push_str("RST|"); 28 | } 29 | if self.0 & SYN != 0 { 30 | str.push_str("SYN|"); 31 | } 32 | if self.0 & FIN != 0 { 33 | str.push_str("FIN|"); 34 | } 35 | if str.is_empty() { 36 | f.debug_struct("NULL").finish() 37 | } else { 38 | let len = str.len() - 1; 39 | f.debug_struct(&str[..len]).finish() 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /vnt/packet/src/udp/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod udp; 2 | -------------------------------------------------------------------------------- /vnt/packet/src/udp/udp.rs: -------------------------------------------------------------------------------- 1 | use std::net::Ipv4Addr; 2 | use std::{fmt, io}; 3 | 4 | /// udp协议 5 | /// 6 | /* 7 | RFC 768 https://www.ietf.org/rfc/rfc768.txt 8 | 9 | 0 7 8 15 16 23 24 31 10 | +--------+--------+--------+--------+ 11 | | 源端口(16) | 目的端口(16) | 12 | +--------+--------+--------+--------+ 13 | | 长度(16) | 校验和(16) | 14 | +--------+--------+--------+--------+ 15 | | 16 | | 载荷 ... 17 | +---------------- ... 18 | 19 | 注:1.长度包含标头和数据体,以字节为单位 20 | 2.伪首部和载荷参与校验和的计算,位数不够则补0 21 | */ 22 | 23 | /// ipv6 udp伪首部 24 | /* https://datatracker.ietf.org/doc/html/rfc2460 25 | 26 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 27 | | | 28 | + + 29 | | | 30 | + Source Address + 31 | | | 32 | + + 33 | | | 34 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 35 | | | 36 | + + 37 | | | 38 | + Destination Address + 39 | | | 40 | + + 41 | | | 42 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 43 | | Upper-Layer Packet Length | 44 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 45 | | zero | Next Header | 46 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 47 | */ 48 | 49 | pub struct UdpPacket { 50 | source_ip: Ipv4Addr, 51 | destination_ip: Ipv4Addr, 52 | buffer: B, 53 | } 54 | 55 | impl> UdpPacket { 56 | pub fn unchecked(source_ip: Ipv4Addr, destination_ip: Ipv4Addr, buffer: B) -> UdpPacket { 57 | UdpPacket { 58 | source_ip, 59 | destination_ip, 60 | buffer, 61 | } 62 | } 63 | pub fn new( 64 | source_ip: Ipv4Addr, 65 | destination_ip: Ipv4Addr, 66 | buffer: B, 67 | ) -> io::Result> { 68 | if buffer.as_ref().len() < 8 { 69 | Err(io::Error::from(io::ErrorKind::InvalidData))?; 70 | } 71 | let packet = Self::unchecked(source_ip, destination_ip, buffer); 72 | Ok(packet) 73 | } 74 | } 75 | 76 | impl> UdpPacket { 77 | /// 源端口 78 | pub fn source_port(&self) -> u16 { 79 | u16::from_be_bytes(self.buffer.as_ref()[0..2].try_into().unwrap()) 80 | } 81 | 82 | /// 目标端口 83 | pub fn destination_port(&self) -> u16 { 84 | u16::from_be_bytes(self.buffer.as_ref()[2..4].try_into().unwrap()) 85 | } 86 | 87 | /// 总字节数 88 | pub fn length(&self) -> u16 { 89 | u16::from_be_bytes(self.buffer.as_ref()[4..6].try_into().unwrap()) 90 | } 91 | 92 | /// Checksum of the packet. 93 | pub fn checksum(&self) -> u16 { 94 | u16::from_be_bytes(self.buffer.as_ref()[6..8].try_into().unwrap()) 95 | } 96 | /// 验证校验和,ipv4中为0表示不使用校验和,ipv6校验和不能为0 97 | pub fn is_valid(&self) -> bool { 98 | self.checksum() == 0 || self.cal_checksum() == 0 99 | } 100 | pub fn payload(&self) -> &[u8] { 101 | &self.buffer.as_ref()[8..] 102 | } 103 | fn cal_checksum(&self) -> u16 { 104 | crate::ipv4_cal_checksum( 105 | self.buffer.as_ref(), 106 | &self.source_ip, 107 | &self.destination_ip, 108 | 17, 109 | ) 110 | } 111 | } 112 | 113 | // impl + AsMut<[u8]>> UdpPacket { 114 | // fn header_mut(&mut self) -> &mut [u8] { 115 | // &mut self.buffer.as_mut()[..8] 116 | // } 117 | // } 118 | 119 | impl + AsMut<[u8]>> UdpPacket { 120 | /// 设置源端口 121 | pub fn set_source_port(&mut self, value: u16) { 122 | self.buffer.as_mut()[0..2].copy_from_slice(&value.to_be_bytes()) 123 | } 124 | 125 | /// 设置目的端口 126 | pub fn set_destination_port(&mut self, value: u16) { 127 | self.buffer.as_mut()[2..4].copy_from_slice(&value.to_be_bytes()) 128 | } 129 | fn set_checksum(&mut self, value: u16) { 130 | self.buffer.as_mut()[6..8].copy_from_slice(&value.to_be_bytes()) 131 | } 132 | pub fn update_checksum(&mut self) { 133 | //先写0 134 | self.set_checksum(0); 135 | self.set_checksum(self.cal_checksum()); 136 | } 137 | } 138 | 139 | impl> fmt::Debug for UdpPacket { 140 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 141 | f.debug_struct("udp::Packet") 142 | .field("source", &self.source_port()) 143 | .field("destination", &self.destination_port()) 144 | .field("length", &self.length()) 145 | .field("checksum", &self.checksum()) 146 | .field("is_valid", &self.is_valid()) 147 | .field("payload", &self.payload()) 148 | .finish() 149 | } 150 | } 151 | -------------------------------------------------------------------------------- /vnt/proto/message.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | message HandshakeRequest { 4 | string version = 1; 5 | bool secret = 2; 6 | string key_finger = 3; 7 | } 8 | message HandshakeResponse { 9 | string version = 1; 10 | bool secret = 2; 11 | bytes public_key = 3; 12 | string key_finger = 4; 13 | } 14 | message SecretHandshakeRequest { 15 | string token = 1; 16 | bytes key = 2; 17 | } 18 | message RegistrationRequest { 19 | string token = 1; 20 | string device_id = 2; 21 | string name = 3; 22 | bool is_fast = 4; 23 | string version = 5; 24 | fixed32 virtual_ip = 6; 25 | bool allow_ip_change = 7; 26 | bool client_secret = 8; 27 | bytes client_secret_hash = 9; 28 | } 29 | 30 | message RegistrationResponse { 31 | fixed32 virtual_ip = 1; 32 | fixed32 virtual_gateway = 2; 33 | fixed32 virtual_netmask = 3; 34 | uint32 epoch = 4; 35 | repeated DeviceInfo device_info_list = 5; 36 | fixed32 public_ip = 6; 37 | uint32 public_port = 7; 38 | bytes public_ipv6 = 8; 39 | } 40 | message DeviceInfo { 41 | string name = 1; 42 | fixed32 virtual_ip = 2; 43 | uint32 device_status = 3; 44 | bool client_secret = 4; 45 | bytes client_secret_hash = 5; 46 | bool wireguard = 6; 47 | } 48 | 49 | message DeviceList { 50 | uint32 epoch = 1; 51 | repeated DeviceInfo device_info_list = 2; 52 | } 53 | 54 | message PunchInfo { 55 | repeated fixed32 public_ip_list = 2; 56 | uint32 public_port = 3; 57 | uint32 public_port_range = 4; 58 | PunchNatType nat_type = 5; 59 | bool reply = 6; 60 | fixed32 local_ip = 7; 61 | uint32 local_port = 8; 62 | bytes ipv6 = 9; 63 | uint32 ipv6_port = 10; 64 | uint32 tcp_port = 11; 65 | repeated uint32 udp_ports = 12; 66 | repeated uint32 public_ports = 13; 67 | uint32 public_tcp_port = 14; 68 | PunchNatModel punch_model = 15; 69 | } 70 | enum PunchNatType { 71 | Symmetric = 0; 72 | Cone = 1; 73 | } 74 | enum PunchNatModel { 75 | All = 0; 76 | IPv4 = 1; 77 | IPv6 = 2; 78 | IPv4Tcp = 3; 79 | IPv4Udp = 4; 80 | IPv6Tcp = 5; 81 | IPv6Udp = 6; 82 | } 83 | 84 | /// 向服务器上报客户端状态信息 85 | message ClientStatusInfo { 86 | fixed32 source = 1; 87 | repeated RouteItem p2p_list = 2; 88 | uint64 up_stream = 3; 89 | uint64 down_stream = 4; 90 | PunchNatType nat_type = 5; 91 | } 92 | message RouteItem { 93 | fixed32 next_ip = 1; 94 | } -------------------------------------------------------------------------------- /vnt/src/channel/handler.rs: -------------------------------------------------------------------------------- 1 | use crate::channel::context::ChannelContext; 2 | use crate::channel::RouteKey; 3 | 4 | pub trait RecvChannelHandler: Clone + Send + Sync + 'static { 5 | fn handle( 6 | &self, 7 | buf: &mut [u8], 8 | extend: &mut [u8], 9 | route_key: RouteKey, 10 | context: &ChannelContext, 11 | ); 12 | } 13 | -------------------------------------------------------------------------------- /vnt/src/channel/idle.rs: -------------------------------------------------------------------------------- 1 | use std::net::Ipv4Addr; 2 | use std::time::Duration; 3 | 4 | use crate::channel::context::ChannelContext; 5 | use crate::channel::Route; 6 | 7 | pub struct Idle { 8 | read_idle: Duration, 9 | context: ChannelContext, 10 | } 11 | 12 | impl Idle { 13 | pub fn new(read_idle: Duration, context: ChannelContext) -> Self { 14 | Self { read_idle, context } 15 | } 16 | } 17 | 18 | pub enum IdleType { 19 | Timeout(Ipv4Addr, Route), 20 | Sleep(Duration), 21 | None, 22 | } 23 | 24 | impl Idle { 25 | /// 获取空闲路由 26 | pub fn next_idle(&self) -> IdleType { 27 | let mut max = Duration::from_secs(0); 28 | let read_guard = self.context.route_table.route_table.read(); 29 | if read_guard.is_empty() { 30 | return IdleType::None; 31 | } 32 | for (ip, (_, routes)) in read_guard.iter() { 33 | for (route, time) in routes { 34 | let last_read = time.load().elapsed(); 35 | if last_read >= self.read_idle { 36 | return IdleType::Timeout(*ip, *route); 37 | } else if max < last_read { 38 | max = last_read; 39 | } 40 | } 41 | } 42 | let sleep_time = self.read_idle.checked_sub(max).unwrap_or_default(); 43 | return IdleType::Sleep(sleep_time); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /vnt/src/channel/notify.rs: -------------------------------------------------------------------------------- 1 | use mio::{Token, Waker}; 2 | use parking_lot::Mutex; 3 | use std::io; 4 | use std::ops::Deref; 5 | use std::sync::atomic::{AtomicUsize, Ordering}; 6 | use std::sync::Arc; 7 | 8 | #[derive(Clone)] 9 | pub struct WritableNotify { 10 | inner: Arc, 11 | } 12 | 13 | impl WritableNotify { 14 | pub fn new(waker: Waker) -> Self { 15 | Self { 16 | inner: Arc::new(WritableNotifyInner { 17 | waker, 18 | state: AtomicUsize::new(0), 19 | tokens: Mutex::new(Vec::with_capacity(8)), 20 | }), 21 | } 22 | } 23 | } 24 | 25 | impl Deref for WritableNotify { 26 | type Target = WritableNotifyInner; 27 | 28 | fn deref(&self) -> &Self::Target { 29 | &self.inner 30 | } 31 | } 32 | 33 | pub struct WritableNotifyInner { 34 | waker: Waker, 35 | state: AtomicUsize, 36 | tokens: Mutex>, 37 | } 38 | 39 | impl WritableNotifyInner { 40 | pub fn notify(&self, token: Token, state: bool) -> io::Result<()> { 41 | { 42 | let mut guard = self.tokens.lock(); 43 | if guard.is_empty() || !guard.contains(&(token, state)) { 44 | guard.push((token, state)); 45 | } 46 | drop(guard); 47 | } 48 | self.need_write() 49 | } 50 | 51 | pub fn stop(&self) -> io::Result<()> { 52 | self.state.store(0b001, Ordering::Release); 53 | self.waker.wake() 54 | } 55 | pub fn need_write(&self) -> io::Result<()> { 56 | self.state.fetch_or(0b010, Ordering::AcqRel); 57 | self.waker.wake() 58 | } 59 | pub fn add_socket(&self) -> io::Result<()> { 60 | self.state.fetch_or(0b100, Ordering::AcqRel); 61 | self.waker.wake() 62 | } 63 | pub fn take_all(&self) -> Option> { 64 | let mut guard = self.tokens.lock(); 65 | if guard.is_empty() { 66 | None 67 | } else { 68 | Some(guard.drain(..).collect()) 69 | } 70 | } 71 | pub fn is_stop(&self) -> bool { 72 | self.state.load(Ordering::Acquire) & 0b001 == 0b001 73 | } 74 | pub fn is_need_write(&self) -> bool { 75 | self.state.fetch_and(!0b010, Ordering::AcqRel) & 0b010 == 0b010 76 | } 77 | pub fn is_add_socket(&self) -> bool { 78 | self.state.fetch_and(!0b100, Ordering::AcqRel) & 0b100 == 0b100 79 | } 80 | } 81 | 82 | #[derive(Clone)] 83 | pub struct AcceptNotify { 84 | inner: Arc, 85 | } 86 | 87 | impl AcceptNotify { 88 | pub fn new(waker: Waker) -> Self { 89 | Self { 90 | inner: Arc::new(AcceptNotifyInner { 91 | waker, 92 | state: AtomicUsize::new(0), 93 | }), 94 | } 95 | } 96 | } 97 | 98 | impl Deref for AcceptNotify { 99 | type Target = AcceptNotifyInner; 100 | 101 | fn deref(&self) -> &Self::Target { 102 | &self.inner 103 | } 104 | } 105 | 106 | pub struct AcceptNotifyInner { 107 | waker: Waker, 108 | state: AtomicUsize, 109 | } 110 | 111 | impl AcceptNotifyInner { 112 | pub fn is_stop(&self) -> bool { 113 | self.state.load(Ordering::Acquire) & 0b001 == 0b001 114 | } 115 | pub fn is_add_socket(&self) -> bool { 116 | self.state.fetch_and(!0b100, Ordering::AcqRel) & 0b100 == 0b100 117 | } 118 | pub fn stop(&self) -> io::Result<()> { 119 | self.state.store(0b001, Ordering::Release); 120 | self.waker.wake() 121 | } 122 | pub fn add_socket(&self) -> io::Result<()> { 123 | self.state.fetch_or(0b100, Ordering::AcqRel); 124 | self.waker.wake() 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /vnt/src/channel/socket/mod.rs: -------------------------------------------------------------------------------- 1 | use anyhow::{anyhow, Context}; 2 | use network_interface::{NetworkInterface, NetworkInterfaceConfig}; 3 | use socket2::Protocol; 4 | use std::net::{IpAddr, Ipv4Addr, SocketAddr}; 5 | 6 | #[cfg(unix)] 7 | mod unix; 8 | #[cfg(windows)] 9 | mod windows; 10 | 11 | pub trait VntSocketTrait { 12 | fn set_ip_unicast_if(&self, _interface: &LocalInterface) -> anyhow::Result<()> { 13 | Ok(()) 14 | } 15 | } 16 | 17 | #[derive(Clone, Debug, Default)] 18 | pub struct LocalInterface { 19 | index: u32, 20 | #[cfg(unix)] 21 | name: Option, 22 | } 23 | 24 | pub async fn connect_tcp( 25 | addr: SocketAddr, 26 | bind_port: u16, 27 | default_interface: &LocalInterface, 28 | ) -> anyhow::Result { 29 | let socket = create_tcp0(addr.is_ipv4(), bind_port, default_interface)?; 30 | Ok(socket.connect(addr).await?) 31 | } 32 | pub fn create_tcp( 33 | v4: bool, 34 | default_interface: &LocalInterface, 35 | ) -> anyhow::Result { 36 | create_tcp0(v4, 0, default_interface) 37 | } 38 | pub fn create_tcp0( 39 | v4: bool, 40 | bind_port: u16, 41 | default_interface: &LocalInterface, 42 | ) -> anyhow::Result { 43 | let socket = if v4 { 44 | socket2::Socket::new( 45 | socket2::Domain::IPV4, 46 | socket2::Type::STREAM, 47 | Some(Protocol::TCP), 48 | )? 49 | } else { 50 | socket2::Socket::new( 51 | socket2::Domain::IPV6, 52 | socket2::Type::STREAM, 53 | Some(Protocol::TCP), 54 | )? 55 | }; 56 | if v4 { 57 | if let Err(e) = socket.set_ip_unicast_if(default_interface) { 58 | log::warn!("set_ip_unicast_if {:?}", e) 59 | } 60 | } 61 | if bind_port != 0 { 62 | socket 63 | .set_reuse_address(true) 64 | .context("set_reuse_address")?; 65 | #[cfg(unix)] 66 | if let Err(e) = socket.set_reuse_port(true) { 67 | log::warn!("set_reuse_port {:?}", e) 68 | } 69 | if v4 { 70 | let addr: SocketAddr = format!("0.0.0.0:{}", bind_port).parse().unwrap(); 71 | socket.bind(&addr.into())?; 72 | } else { 73 | socket.set_only_v6(true)?; 74 | let addr: SocketAddr = format!("[::]:{}", bind_port).parse().unwrap(); 75 | socket.bind(&addr.into())?; 76 | } 77 | } 78 | socket.set_nonblocking(true)?; 79 | socket.set_nodelay(true)?; 80 | Ok(tokio::net::TcpSocket::from_std_stream(socket.into())) 81 | } 82 | pub fn bind_udp_ops( 83 | addr: SocketAddr, 84 | only_v6: bool, 85 | default_interface: &LocalInterface, 86 | ) -> anyhow::Result { 87 | let socket = if addr.is_ipv4() { 88 | let socket = socket2::Socket::new( 89 | socket2::Domain::IPV4, 90 | socket2::Type::DGRAM, 91 | Some(Protocol::UDP), 92 | )?; 93 | if let Err(e) = socket.set_ip_unicast_if(default_interface) { 94 | log::warn!("set_ip_unicast_if {:?}", e) 95 | } 96 | socket 97 | } else { 98 | let socket = socket2::Socket::new( 99 | socket2::Domain::IPV6, 100 | socket2::Type::DGRAM, 101 | Some(Protocol::UDP), 102 | )?; 103 | socket 104 | .set_only_v6(only_v6) 105 | .with_context(|| format!("set_only_v6 failed: {}", &addr))?; 106 | socket 107 | }; 108 | socket.set_nonblocking(true)?; 109 | socket.bind(&addr.into())?; 110 | Ok(socket) 111 | } 112 | pub fn bind_udp( 113 | addr: SocketAddr, 114 | default_interface: &LocalInterface, 115 | ) -> anyhow::Result { 116 | bind_udp_ops(addr, true, default_interface).with_context(|| format!("{}", addr)) 117 | } 118 | 119 | pub fn get_interface(dest_name: String) -> anyhow::Result<(LocalInterface, Ipv4Addr)> { 120 | let network_interfaces = NetworkInterface::show()?; 121 | for iface in network_interfaces { 122 | if iface.name == dest_name { 123 | for addr in iface.addr { 124 | if let IpAddr::V4(ip) = addr.ip() { 125 | return Ok(( 126 | LocalInterface { 127 | index: iface.index, 128 | #[cfg(unix)] 129 | name: Some(iface.name), 130 | }, 131 | ip, 132 | )); 133 | } 134 | } 135 | } 136 | } 137 | Err(anyhow!("No network card with name {} found", dest_name)) 138 | } 139 | -------------------------------------------------------------------------------- /vnt/src/channel/socket/unix.rs: -------------------------------------------------------------------------------- 1 | use crate::channel::socket::{LocalInterface, VntSocketTrait}; 2 | #[cfg(any(target_os = "linux", target_os = "macos"))] 3 | use anyhow::Context; 4 | 5 | #[cfg(target_os = "linux")] 6 | impl VntSocketTrait for socket2::Socket { 7 | fn set_ip_unicast_if(&self, interface: &LocalInterface) -> anyhow::Result<()> { 8 | if let Some(name) = &interface.name { 9 | self.bind_device(Some(name.as_bytes())) 10 | .context("bind_device")?; 11 | } 12 | Ok(()) 13 | } 14 | } 15 | #[cfg(target_os = "macos")] 16 | impl VntSocketTrait for socket2::Socket { 17 | fn set_ip_unicast_if(&self, interface: &LocalInterface) -> anyhow::Result<()> { 18 | if interface.index != 0 { 19 | self.bind_device_by_index_v4(std::num::NonZeroU32::new(interface.index)) 20 | .with_context(|| format!("bind_device_by_index_v4 {:?}", interface))?; 21 | } 22 | Ok(()) 23 | } 24 | } 25 | #[cfg(target_os = "android")] 26 | impl VntSocketTrait for socket2::Socket { 27 | fn set_ip_unicast_if(&self, _interface: &LocalInterface) -> anyhow::Result<()> { 28 | Ok(()) 29 | } 30 | } 31 | 32 | // #[cfg(any(target_os = "linux", target_os = "macos"))] 33 | // pub fn get_best_interface(dest_ip: Ipv4Addr) -> anyhow::Result { 34 | // match get_interface(dest_ip) { 35 | // Ok(iface) => return Ok(iface), 36 | // Err(e) => { 37 | // log::warn!("not find interface e={:?},ip={}", e, dest_ip); 38 | // } 39 | // } 40 | // // 应该再查路由表找到默认路由的 41 | // Ok(LocalInterface::default()) 42 | // } 43 | // #[cfg(target_os = "android")] 44 | // pub fn get_best_interface(_dest_ip: Ipv4Addr) -> anyhow::Result { 45 | // Ok(LocalInterface::default()) 46 | // } 47 | -------------------------------------------------------------------------------- /vnt/src/channel/socket/windows.rs: -------------------------------------------------------------------------------- 1 | use std::mem; 2 | use std::os::windows::io::AsRawSocket; 3 | 4 | use windows_sys::core::PCSTR; 5 | use windows_sys::Win32::Networking::WinSock::{ 6 | htonl, setsockopt, IPPROTO_IP, IP_UNICAST_IF, SOCKET_ERROR, 7 | }; 8 | 9 | use crate::channel::socket::{LocalInterface, VntSocketTrait}; 10 | 11 | impl VntSocketTrait for socket2::Socket { 12 | fn set_ip_unicast_if(&self, interface: &LocalInterface) -> anyhow::Result<()> { 13 | let index = interface.index; 14 | if index == 0 { 15 | return Ok(()); 16 | } 17 | let raw_socket = self.as_raw_socket(); 18 | let result = unsafe { 19 | let best_interface = htonl(index); 20 | setsockopt( 21 | raw_socket as usize, 22 | IPPROTO_IP, 23 | IP_UNICAST_IF, 24 | &best_interface as *const _ as PCSTR, 25 | mem::size_of_val(&best_interface) as i32, 26 | ) 27 | }; 28 | if result == SOCKET_ERROR { 29 | Err(anyhow::anyhow!( 30 | "Failed to set IP_UNICAST_IF: {:?} {}", 31 | std::io::Error::last_os_error(), 32 | index 33 | ))?; 34 | } 35 | Ok(()) 36 | } 37 | } 38 | 39 | // pub fn get_best_interface(dest_ip: Ipv4Addr) -> anyhow::Result { 40 | // // 获取最佳接口 41 | // let index = unsafe { 42 | // let mut dest: SOCKADDR_IN = mem::zeroed(); 43 | // dest.sin_family = AF_INET as u16; 44 | // dest.sin_addr.S_un.S_addr = u32::from_ne_bytes(dest_ip.octets()); 45 | // 46 | // let mut index: u32 = 0; 47 | // if GetBestInterfaceEx(&dest as *const _ as *mut SOCKADDR, &mut index) != 0 { 48 | // Err(anyhow::anyhow!( 49 | // "Failed to GetBestInterfaceEx: {:?}", 50 | // std::io::Error::last_os_error() 51 | // ))?; 52 | // } 53 | // index 54 | // }; 55 | // Ok(LocalInterface { index }) 56 | // } 57 | -------------------------------------------------------------------------------- /vnt/src/cipher/aes_cbc/mod.rs: -------------------------------------------------------------------------------- 1 | mod rs_aes_cbc; 2 | pub use rs_aes_cbc::*; 3 | -------------------------------------------------------------------------------- /vnt/src/cipher/aes_ecb/mod.rs: -------------------------------------------------------------------------------- 1 | #[cfg(not(any(feature = "openssl-vendored", feature = "openssl")))] 2 | mod rs_aes_ecb; 3 | #[cfg(not(any(feature = "openssl-vendored", feature = "openssl")))] 4 | pub use rs_aes_ecb::*; 5 | 6 | #[cfg(any(feature = "openssl-vendored", feature = "openssl"))] 7 | mod openssl_aes_ecb; 8 | #[cfg(any(feature = "openssl-vendored", feature = "openssl"))] 9 | pub use openssl_aes_ecb::*; 10 | -------------------------------------------------------------------------------- /vnt/src/cipher/aes_gcm/aes_gcm_cipher.rs: -------------------------------------------------------------------------------- 1 | use aes_gcm::aead::consts::{U12, U16}; 2 | use aes_gcm::aead::generic_array::GenericArray; 3 | use aes_gcm::{AeadInPlace, Aes128Gcm, Aes256Gcm, Key, KeyInit, Nonce, Tag}; 4 | use anyhow::anyhow; 5 | use rand::RngCore; 6 | 7 | use crate::cipher::finger::Finger; 8 | use crate::protocol::{body::SecretBody, body::AES_GCM_ENCRYPTION_RESERVED, NetPacket}; 9 | 10 | #[derive(Clone)] 11 | pub struct AesGcmCipher { 12 | pub(crate) cipher: AesGcmEnum, 13 | pub(crate) finger: Option, 14 | } 15 | 16 | #[derive(Clone)] 17 | pub enum AesGcmEnum { 18 | AES128GCM(Aes128Gcm), 19 | AES256GCM(Aes256Gcm), 20 | } 21 | 22 | impl AesGcmCipher { 23 | pub fn new_128(key: [u8; 16], finger: Option) -> Self { 24 | let key: &Key = &key.into(); 25 | Self { 26 | cipher: AesGcmEnum::AES128GCM(Aes128Gcm::new(key)), 27 | finger, 28 | } 29 | } 30 | pub fn new_256(key: [u8; 32], finger: Option) -> Self { 31 | let key: &Key = &key.into(); 32 | Self { 33 | cipher: AesGcmEnum::AES256GCM(Aes256Gcm::new(key)), 34 | finger, 35 | } 36 | } 37 | 38 | pub fn decrypt_ipv4 + AsMut<[u8]>>( 39 | &self, 40 | net_packet: &mut NetPacket, 41 | ) -> anyhow::Result<()> { 42 | if !net_packet.is_encrypt() { 43 | //未加密的数据直接丢弃 44 | return Err(anyhow!("not encrypt")); 45 | } 46 | if net_packet.payload().len() < AES_GCM_ENCRYPTION_RESERVED { 47 | log::error!("数据异常,长度小于{}", AES_GCM_ENCRYPTION_RESERVED); 48 | return Err(anyhow!("data err")); 49 | } 50 | let nonce_raw = net_packet.head_tag(); 51 | let nonce: &GenericArray = Nonce::from_slice(&nonce_raw); 52 | 53 | let mut secret_body = SecretBody::new(net_packet.payload_mut(), self.finger.is_some())?; 54 | let tag = secret_body.tag(); 55 | if let Some(finger) = &self.finger { 56 | let finger = finger.calculate_finger(&nonce_raw, secret_body.en_body()); 57 | if &finger != secret_body.finger() { 58 | return Err(anyhow!("finger err")); 59 | } 60 | } 61 | let tag: GenericArray = Tag::clone_from_slice(tag); 62 | let rs = match &self.cipher { 63 | AesGcmEnum::AES128GCM(aes_gcm) => { 64 | aes_gcm.decrypt_in_place_detached(nonce, &[], secret_body.body_mut(), &tag) 65 | } 66 | AesGcmEnum::AES256GCM(aes_gcm) => { 67 | aes_gcm.decrypt_in_place_detached(nonce, &[], secret_body.body_mut(), &tag) 68 | } 69 | }; 70 | if let Err(e) = rs { 71 | return Err(anyhow!("解密失败:{}", e)); 72 | } 73 | net_packet.set_encrypt_flag(false); 74 | net_packet.set_data_len(net_packet.data_len() - AES_GCM_ENCRYPTION_RESERVED)?; 75 | return Ok(()); 76 | } 77 | /// net_packet 必须预留足够长度 78 | /// data_len是有效载荷的长度 79 | pub fn encrypt_ipv4 + AsMut<[u8]>>( 80 | &self, 81 | net_packet: &mut NetPacket, 82 | ) -> anyhow::Result<()> { 83 | if net_packet.reserve() < AES_GCM_ENCRYPTION_RESERVED { 84 | return Err(anyhow!("too short")); 85 | } 86 | let nonce_raw = net_packet.head_tag(); 87 | let nonce: &GenericArray = Nonce::from_slice(&nonce_raw); 88 | let data_len = net_packet.data_len() + AES_GCM_ENCRYPTION_RESERVED; 89 | net_packet.set_data_len(data_len)?; 90 | let mut secret_body = SecretBody::new(net_packet.payload_mut(), self.finger.is_some())?; 91 | secret_body.set_random(rand::thread_rng().next_u32()); 92 | let rs = match &self.cipher { 93 | AesGcmEnum::AES128GCM(aes_gcm) => { 94 | aes_gcm.encrypt_in_place_detached(nonce, &[], secret_body.body_mut()) 95 | } 96 | AesGcmEnum::AES256GCM(aes_gcm) => { 97 | aes_gcm.encrypt_in_place_detached(nonce, &[], secret_body.body_mut()) 98 | } 99 | }; 100 | return match rs { 101 | Ok(tag) => { 102 | secret_body.set_tag(tag.as_slice())?; 103 | if let Some(finger) = &self.finger { 104 | let finger = finger.calculate_finger(&nonce_raw, secret_body.en_body()); 105 | secret_body.set_finger(&finger)?; 106 | } 107 | net_packet.set_encrypt_flag(true); 108 | Ok(()) 109 | } 110 | Err(e) => Err(anyhow!("加密失败:{}", e)), 111 | }; 112 | } 113 | } 114 | 115 | #[test] 116 | fn test_aes_gcm() { 117 | let d = AesGcmCipher::new_256([0; 32], Some(Finger::new("123"))); 118 | let mut p = 119 | NetPacket::new_encrypt([1; 13 + crate::protocol::body::ENCRYPTION_RESERVED]).unwrap(); 120 | let src = p.buffer().to_vec(); 121 | d.encrypt_ipv4(&mut p).unwrap(); 122 | d.decrypt_ipv4(&mut p).unwrap(); 123 | assert_eq!(p.buffer(), &src); 124 | 125 | let d = AesGcmCipher::new_256([0; 32], None); 126 | let mut p = 127 | NetPacket::new_encrypt([0; 13 + crate::protocol::body::ENCRYPTION_RESERVED]).unwrap(); 128 | let src = p.buffer().to_vec(); 129 | d.encrypt_ipv4(&mut p).unwrap(); 130 | d.decrypt_ipv4(&mut p).unwrap(); 131 | assert_eq!(p.buffer(), &src); 132 | } 133 | -------------------------------------------------------------------------------- /vnt/src/cipher/aes_gcm/mod.rs: -------------------------------------------------------------------------------- 1 | #[cfg(feature = "ring-cipher")] 2 | mod ring_aes_gcm_cipher; 3 | #[cfg(feature = "ring-cipher")] 4 | pub use ring_aes_gcm_cipher::*; 5 | 6 | #[cfg(not(feature = "ring-cipher"))] 7 | mod aes_gcm_cipher; 8 | #[cfg(not(feature = "ring-cipher"))] 9 | pub use aes_gcm_cipher::*; 10 | -------------------------------------------------------------------------------- /vnt/src/cipher/chacha20/mod.rs: -------------------------------------------------------------------------------- 1 | mod rs_chacha20; 2 | pub use rs_chacha20::*; 3 | -------------------------------------------------------------------------------- /vnt/src/cipher/chacha20/rs_chacha20.rs: -------------------------------------------------------------------------------- 1 | use aes::cipher::Iv; 2 | use anyhow::anyhow; 3 | use chacha20::cipher::{Key, KeyIvInit, StreamCipher}; 4 | use chacha20::ChaCha20; 5 | 6 | use crate::cipher::finger::{gen_nonce, gen_random_nonce}; 7 | use crate::cipher::Finger; 8 | use crate::protocol::body::{ 9 | IVSecretBody, SecretTail, SecretTailMut, FINGER_RESERVED, RANDOM_RESERVED, 10 | }; 11 | use crate::protocol::NetPacket; 12 | 13 | #[derive(Clone)] 14 | pub struct ChaCha20Cipher { 15 | key: [u8; 32], 16 | pub(crate) finger: Option, 17 | } 18 | 19 | impl ChaCha20Cipher { 20 | pub fn new_256(key: [u8; 32], finger: Option) -> Self { 21 | Self { key, finger } 22 | } 23 | } 24 | 25 | impl ChaCha20Cipher { 26 | pub fn key(&self) -> &[u8] { 27 | &self.key 28 | } 29 | } 30 | 31 | impl ChaCha20Cipher { 32 | pub fn decrypt_ipv4 + AsMut<[u8]>>( 33 | &self, 34 | net_packet: &mut NetPacket, 35 | ) -> anyhow::Result<()> { 36 | if !net_packet.is_encrypt() { 37 | //未加密的数据直接丢弃 38 | return Err(anyhow!("not encrypt")); 39 | } 40 | let mut head_tag = net_packet.head_tag(); 41 | 42 | let mut secret_body = IVSecretBody::new(net_packet.payload_mut(), self.finger.is_some())?; 43 | if let Some(finger) = &self.finger { 44 | let finger = finger.calculate_finger(&head_tag, secret_body.data()); 45 | if &finger != secret_body.finger() { 46 | return Err(anyhow!("ChaCha20 finger err")); 47 | } 48 | } 49 | gen_nonce(&mut head_tag, secret_body.random_buf()); 50 | ChaCha20::new( 51 | Key::::from_slice(&self.key), 52 | Iv::::from_slice(&head_tag), 53 | ) 54 | .apply_keystream(secret_body.data_mut()); 55 | let len = secret_body.data().len(); 56 | net_packet.set_encrypt_flag(false); 57 | net_packet.set_payload_len(len)?; 58 | Ok(()) 59 | } 60 | pub fn encrypt_ipv4 + AsMut<[u8]>>( 61 | &self, 62 | net_packet: &mut NetPacket, 63 | ) -> anyhow::Result<()> { 64 | let data_len = net_packet.data_len(); 65 | let head_tag = net_packet.head_tag(); 66 | if let Some(_) = &self.finger { 67 | net_packet.set_data_len(data_len + RANDOM_RESERVED + FINGER_RESERVED)?; 68 | } else { 69 | net_packet.set_data_len(data_len + RANDOM_RESERVED)?; 70 | } 71 | let mut secret_body = IVSecretBody::new(net_packet.payload_mut(), self.finger.is_some())?; 72 | let mut nonce = head_tag; 73 | secret_body.set_random(&gen_random_nonce(&mut nonce)); 74 | 75 | ChaCha20::new( 76 | Key::::from_slice(&self.key), 77 | Iv::::from_slice(&nonce), 78 | ) 79 | .apply_keystream(secret_body.data_mut()); 80 | if let Some(finger) = &self.finger { 81 | let finger = finger.calculate_finger(&head_tag, secret_body.data()); 82 | let mut secret_body = IVSecretBody::new(net_packet.payload_mut(), true)?; 83 | secret_body.set_finger(&finger)?; 84 | } 85 | net_packet.set_encrypt_flag(true); 86 | Ok(()) 87 | } 88 | } 89 | 90 | #[test] 91 | fn test_chacha20() { 92 | let d = ChaCha20Cipher::new_256([0; 32], Some(Finger::new("123"))); 93 | let mut p = 94 | NetPacket::new_encrypt([1; 13 + crate::protocol::body::ENCRYPTION_RESERVED]).unwrap(); 95 | let src = p.buffer().to_vec(); 96 | d.encrypt_ipv4(&mut p).unwrap(); 97 | d.decrypt_ipv4(&mut p).unwrap(); 98 | assert_eq!(p.buffer(), &src); 99 | 100 | let d = ChaCha20Cipher::new_256([0; 32], None); 101 | let mut p = 102 | NetPacket::new_encrypt([2; 13 + crate::protocol::body::ENCRYPTION_RESERVED]).unwrap(); 103 | let src = p.buffer().to_vec(); 104 | d.encrypt_ipv4(&mut p).unwrap(); 105 | d.decrypt_ipv4(&mut p).unwrap(); 106 | assert_eq!(p.buffer(), &src); 107 | } 108 | -------------------------------------------------------------------------------- /vnt/src/cipher/chacha20_poly1305/mod.rs: -------------------------------------------------------------------------------- 1 | #[cfg(feature = "ring-cipher")] 2 | mod ring_chacha20_poly1305; 3 | #[cfg(feature = "ring-cipher")] 4 | pub use ring_chacha20_poly1305::*; 5 | 6 | #[cfg(not(feature = "ring-cipher"))] 7 | mod rs_chacha20_poly1305; 8 | #[cfg(not(feature = "ring-cipher"))] 9 | pub use rs_chacha20_poly1305::*; 10 | -------------------------------------------------------------------------------- /vnt/src/cipher/chacha20_poly1305/ring_chacha20_poly1305.rs: -------------------------------------------------------------------------------- 1 | use anyhow::anyhow; 2 | 3 | use ring::aead; 4 | use ring::aead::{LessSafeKey, UnboundKey}; 5 | 6 | use crate::cipher::finger::{gen_nonce, gen_random_nonce}; 7 | use crate::cipher::Finger; 8 | use crate::protocol::body::{ 9 | AEADSecretBody, SecretTail, SecretTailMut, FINGER_RESERVED, RANDOM_RESERVED, TAG_RESERVED, 10 | }; 11 | use crate::protocol::NetPacket; 12 | 13 | #[derive(Clone)] 14 | pub struct ChaCha20Poly1305Cipher { 15 | key: Vec, 16 | pub(crate) cipher: LessSafeKey, 17 | pub(crate) finger: Option, 18 | } 19 | 20 | impl ChaCha20Poly1305Cipher { 21 | pub fn new_256(key: [u8; 32], finger: Option) -> Self { 22 | let cipher = LessSafeKey::new(UnboundKey::new(&aead::CHACHA20_POLY1305, &key).unwrap()); 23 | Self { 24 | key: key.to_vec(), 25 | cipher, 26 | finger, 27 | } 28 | } 29 | } 30 | 31 | impl ChaCha20Poly1305Cipher { 32 | pub fn key(&self) -> &[u8] { 33 | &self.key 34 | } 35 | } 36 | 37 | impl ChaCha20Poly1305Cipher { 38 | pub fn decrypt_ipv4 + AsMut<[u8]>>( 39 | &self, 40 | net_packet: &mut NetPacket, 41 | ) -> anyhow::Result<()> { 42 | if !net_packet.is_encrypt() { 43 | //未加密的数据直接丢弃 44 | return Err(anyhow!("not encrypt")); 45 | } 46 | if net_packet.payload().len() < TAG_RESERVED { 47 | log::error!("数据异常,长度小于{}", TAG_RESERVED); 48 | return Err(anyhow!("data err")); 49 | } 50 | let mut head_tag = net_packet.head_tag(); 51 | let mut secret_body = AEADSecretBody::new(net_packet.payload_mut(), self.finger.is_some())?; 52 | if let Some(finger) = &self.finger { 53 | let finger = finger.calculate_finger(&head_tag, secret_body.data_tag_mut()); 54 | if &finger != secret_body.finger() { 55 | return Err(anyhow!("ring CHACHA20_POLY1305 finger err")); 56 | } 57 | } 58 | gen_nonce(&mut head_tag, secret_body.random_buf()); 59 | let nonce = aead::Nonce::assume_unique_for_key(head_tag); 60 | let rs = self 61 | .cipher 62 | .open_in_place(nonce, aead::Aad::empty(), secret_body.data_tag_mut()); 63 | if let Err(e) = rs { 64 | return Err(anyhow!("ring CHACHA20_POLY1305 解密失败:{}", e)); 65 | } 66 | let len = secret_body.data().len(); 67 | net_packet.set_encrypt_flag(false); 68 | net_packet.set_payload_len(len)?; 69 | return Ok(()); 70 | } 71 | /// net_packet 必须预留足够长度 72 | /// data_len是有效载荷的长度 73 | /// 返回加密后载荷的长度 74 | pub fn encrypt_ipv4 + AsMut<[u8]>>( 75 | &self, 76 | net_packet: &mut NetPacket, 77 | ) -> anyhow::Result<()> { 78 | let head_tag = net_packet.head_tag(); 79 | let data_len = net_packet.data_len(); 80 | if self.finger.is_some() { 81 | net_packet.set_data_len(data_len + TAG_RESERVED + RANDOM_RESERVED + FINGER_RESERVED)?; 82 | } else { 83 | net_packet.set_data_len(data_len + TAG_RESERVED + RANDOM_RESERVED)?; 84 | } 85 | let mut secret_body = AEADSecretBody::new(net_packet.payload_mut(), self.finger.is_some())?; 86 | let mut nonce = head_tag; 87 | secret_body.set_random(&gen_random_nonce(&mut nonce)); 88 | let nonce = aead::Nonce::assume_unique_for_key(nonce); 89 | let rs = self.cipher.seal_in_place_separate_tag( 90 | nonce, 91 | aead::Aad::empty(), 92 | secret_body.data_mut(), 93 | ); 94 | match rs { 95 | Ok(tag) => { 96 | let tag = tag.as_ref(); 97 | if tag.len() != 16 { 98 | return Err(anyhow!("加密tag长度错误:{}", tag.len())); 99 | } 100 | secret_body.set_tag(tag)?; 101 | if let Some(finger) = &self.finger { 102 | let finger = finger.calculate_finger(&head_tag, secret_body.data_tag_mut()); 103 | secret_body.set_finger(&finger)?; 104 | } 105 | net_packet.set_encrypt_flag(true); 106 | Ok(()) 107 | } 108 | Err(e) => Err(anyhow!("ring CHACHA20_POLY1305 加密失败:{}", e)), 109 | } 110 | } 111 | } 112 | 113 | #[test] 114 | fn test_ring_chacha20_poly1305() { 115 | let d = ChaCha20Poly1305Cipher::new_256([0; 32], Some(Finger::new("123"))); 116 | let mut p = NetPacket::new_encrypt([0; 73]).unwrap(); 117 | let src = p.buffer().to_vec(); 118 | d.encrypt_ipv4(&mut p).unwrap(); 119 | d.decrypt_ipv4(&mut p).unwrap(); 120 | assert_eq!(p.buffer(), &src); 121 | let d = ChaCha20Poly1305Cipher::new_256([0; 32], None); 122 | let mut p = NetPacket::new_encrypt([0; 73]).unwrap(); 123 | let src = p.buffer().to_vec(); 124 | d.encrypt_ipv4(&mut p).unwrap(); 125 | d.decrypt_ipv4(&mut p).unwrap(); 126 | assert_eq!(p.buffer(), &src); 127 | } 128 | -------------------------------------------------------------------------------- /vnt/src/cipher/chacha20_poly1305/rs_chacha20_poly1305.rs: -------------------------------------------------------------------------------- 1 | use crate::cipher::finger::{gen_nonce, gen_random_nonce}; 2 | use crate::cipher::Finger; 3 | use crate::protocol::body::{ 4 | AEADSecretBody, SecretTail, SecretTailMut, FINGER_RESERVED, RANDOM_RESERVED, TAG_RESERVED, 5 | }; 6 | use crate::protocol::NetPacket; 7 | use anyhow::anyhow; 8 | use chacha20poly1305::aead::{Nonce, Tag}; 9 | use chacha20poly1305::{AeadInPlace, ChaCha20Poly1305, Key, KeyInit}; 10 | 11 | #[derive(Clone)] 12 | pub struct ChaCha20Poly1305Cipher { 13 | key: Vec, 14 | pub(crate) cipher: ChaCha20Poly1305, 15 | pub(crate) finger: Option, 16 | } 17 | 18 | impl ChaCha20Poly1305Cipher { 19 | pub fn new_256(key: [u8; 32], finger: Option) -> Self { 20 | let key: &Key = &key.into(); 21 | let cipher = ChaCha20Poly1305::new(key); 22 | Self { 23 | key: key.to_vec(), 24 | cipher, 25 | finger, 26 | } 27 | } 28 | } 29 | 30 | impl ChaCha20Poly1305Cipher { 31 | pub fn key(&self) -> &[u8] { 32 | &self.key 33 | } 34 | } 35 | 36 | impl ChaCha20Poly1305Cipher { 37 | pub fn decrypt_ipv4 + AsMut<[u8]>>( 38 | &self, 39 | net_packet: &mut NetPacket, 40 | ) -> anyhow::Result<()> { 41 | if !net_packet.is_encrypt() { 42 | //未加密的数据直接丢弃 43 | return Err(anyhow!("not encrypt")); 44 | } 45 | if net_packet.payload().len() < TAG_RESERVED { 46 | log::error!("数据异常,长度小于{}", TAG_RESERVED); 47 | return Err(anyhow!("data err")); 48 | } 49 | let mut head_tag = net_packet.head_tag(); 50 | let mut secret_body = AEADSecretBody::new(net_packet.payload_mut(), self.finger.is_some())?; 51 | if let Some(finger) = &self.finger { 52 | let finger = finger.calculate_finger(&head_tag, secret_body.data_tag_mut()); 53 | if &finger != secret_body.finger() { 54 | return Err(anyhow!("rs CHACHA20_POLY1305 finger err")); 55 | } 56 | } 57 | gen_nonce(&mut head_tag, secret_body.random_buf()); 58 | let nonce: Nonce = head_tag.into(); 59 | let tag: Tag = 60 | Tag::::from_slice(secret_body.tag()).clone(); 61 | if let Err(e) = 62 | self.cipher 63 | .decrypt_in_place_detached(&nonce, &[], secret_body.data_mut(), &tag) 64 | { 65 | return Err(anyhow!("rs CHACHA20_POLY1305 decrypt_ipv4 {:?}", e)); 66 | } 67 | let len = secret_body.data().len(); 68 | net_packet.set_encrypt_flag(false); 69 | net_packet.set_payload_len(len)?; 70 | Ok(()) 71 | } 72 | /// net_packet 必须预留足够长度 73 | /// data_len是有效载荷的长度 74 | /// 返回加密后载荷的长度 75 | pub fn encrypt_ipv4 + AsMut<[u8]>>( 76 | &self, 77 | net_packet: &mut NetPacket, 78 | ) -> anyhow::Result<()> { 79 | let head_tag = net_packet.head_tag(); 80 | let data_len = net_packet.data_len(); 81 | if self.finger.is_some() { 82 | net_packet.set_data_len(data_len + TAG_RESERVED + RANDOM_RESERVED + FINGER_RESERVED)?; 83 | } else { 84 | net_packet.set_data_len(data_len + TAG_RESERVED + RANDOM_RESERVED)?; 85 | } 86 | let mut secret_body = AEADSecretBody::new(net_packet.payload_mut(), self.finger.is_some())?; 87 | let mut nonce = head_tag; 88 | secret_body.set_random(&gen_random_nonce(&mut nonce)); 89 | let nonce = nonce.into(); 90 | let rs = self 91 | .cipher 92 | .encrypt_in_place_detached(&nonce, &[], secret_body.data_mut()); 93 | match rs { 94 | Ok(tag) => { 95 | let tag: &[u8] = tag.as_ref(); 96 | if tag.len() != 16 { 97 | return Err(anyhow!("加密tag长度错误:{}", tag.len(),)); 98 | } 99 | secret_body.set_tag(tag)?; 100 | if let Some(finger) = &self.finger { 101 | let finger = finger.calculate_finger(&head_tag, secret_body.data_tag_mut()); 102 | secret_body.set_finger(&finger)?; 103 | } 104 | net_packet.set_encrypt_flag(true); 105 | Ok(()) 106 | } 107 | Err(e) => Err(anyhow!("rs CHACHA20_POLY1305 加密失败:{}", e)), 108 | } 109 | } 110 | } 111 | 112 | #[test] 113 | fn test_rs_chacha20_poly1305() { 114 | let d = ChaCha20Poly1305Cipher::new_256([0; 32], Some(Finger::new("123"))); 115 | let mut p = NetPacket::new_encrypt([0; 73]).unwrap(); 116 | let src = p.buffer().to_vec(); 117 | d.encrypt_ipv4(&mut p).unwrap(); 118 | d.decrypt_ipv4(&mut p).unwrap(); 119 | assert_eq!(p.buffer(), &src); 120 | let d = ChaCha20Poly1305Cipher::new_256([0; 32], None); 121 | let mut p = NetPacket::new_encrypt([0; 73]).unwrap(); 122 | let src = p.buffer().to_vec(); 123 | d.encrypt_ipv4(&mut p).unwrap(); 124 | d.decrypt_ipv4(&mut p).unwrap(); 125 | assert_eq!(p.buffer(), &src); 126 | } 127 | -------------------------------------------------------------------------------- /vnt/src/cipher/finger.rs: -------------------------------------------------------------------------------- 1 | use anyhow::anyhow; 2 | use rand::RngCore; 3 | 4 | use sha2::Digest; 5 | 6 | use crate::protocol::NetPacket; 7 | 8 | #[derive(Clone)] 9 | pub struct Finger { 10 | pub(crate) hash: [u8; 32], 11 | } 12 | 13 | impl Finger { 14 | pub fn new(str: &str) -> Self { 15 | let mut hasher = sha2::Sha256::new(); 16 | hasher.update(str.as_bytes()); 17 | let hash: [u8; 32] = hasher.finalize().into(); 18 | Finger { hash } 19 | } 20 | pub fn check_finger>(&self, net_packet: &NetPacket) -> anyhow::Result<()> { 21 | if !net_packet.is_encrypt() { 22 | //未加密的数据直接丢弃 23 | return Err(anyhow!("not encrypt")); 24 | } 25 | let payload_len = net_packet.payload().len(); 26 | if payload_len < 12 { 27 | log::error!("数据异常,长度小于{}", 12); 28 | return Err(anyhow!("data err")); 29 | } 30 | let mut nonce_raw = [0; 12]; 31 | nonce_raw[0..4].copy_from_slice(&net_packet.source().octets()); 32 | nonce_raw[4..8].copy_from_slice(&net_packet.destination().octets()); 33 | nonce_raw[8] = net_packet.protocol().into(); 34 | nonce_raw[9] = net_packet.transport_protocol(); 35 | nonce_raw[10] = net_packet.is_gateway() as u8; 36 | nonce_raw[11] = net_packet.source_ttl(); 37 | let payload = net_packet.payload(); 38 | let finger = self.calculate_finger(&nonce_raw, &payload[..payload_len - 12]); 39 | if &finger[..] != &payload[payload_len - 12..] { 40 | return Err(anyhow!("finger err")); 41 | } 42 | Ok(()) 43 | } 44 | pub fn calculate_finger(&self, nonce: &[u8], secret_body: &[u8]) -> [u8; 12] { 45 | let mut hasher = sha2::Sha256::new(); 46 | hasher.update(nonce); 47 | hasher.update(secret_body); 48 | hasher.update(&self.hash); 49 | let key: [u8; 32] = hasher.finalize().into(); 50 | return key[20..].try_into().unwrap(); 51 | } 52 | } 53 | impl> NetPacket { 54 | pub fn head_tag(&self) -> [u8; 12] { 55 | let mut tag = [0; 12]; 56 | tag[0..4].copy_from_slice(&self.buffer()[4..8]); 57 | tag[4..8].copy_from_slice(&self.buffer()[8..12]); 58 | tag[8] = self.protocol().into(); 59 | tag[9] = self.transport_protocol(); 60 | tag[10] = self.is_gateway() as u8; 61 | tag[11] = self.source_ttl(); 62 | tag 63 | } 64 | } 65 | pub fn gen_nonce(tag: &mut [u8], random: &[u8]) { 66 | tag[8] = random[0] ^ tag[8]; 67 | tag[9] = random[1] ^ tag[9]; 68 | tag[10] = random[2] ^ tag[10]; 69 | tag[11] = random[3] ^ tag[11]; 70 | } 71 | pub fn gen_random_nonce(tag: &mut [u8; 12]) -> [u8; 4] { 72 | let mut random = [0; 4]; 73 | rand::thread_rng().fill_bytes(&mut random); 74 | gen_nonce(tag, &random); 75 | random 76 | } 77 | -------------------------------------------------------------------------------- /vnt/src/cipher/mod.rs: -------------------------------------------------------------------------------- 1 | mod cipher; 2 | #[cfg(cipher)] 3 | mod finger; 4 | 5 | pub use cipher::Cipher; 6 | pub use cipher::CipherModel; 7 | #[cfg(cipher)] 8 | pub use finger::Finger; 9 | #[cfg(feature = "server_encrypt")] 10 | mod rsa_cipher; 11 | #[cfg(feature = "server_encrypt")] 12 | pub use rsa_cipher::RsaCipher; 13 | 14 | #[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))] 15 | mod aes_gcm; 16 | 17 | #[cfg(feature = "chacha20_poly1305")] 18 | mod chacha20; 19 | #[cfg(feature = "chacha20_poly1305")] 20 | mod chacha20_poly1305; 21 | 22 | #[cfg(feature = "aes_ecb")] 23 | mod aes_ecb; 24 | 25 | #[cfg(feature = "aes_cbc")] 26 | mod aes_cbc; 27 | 28 | #[cfg(feature = "sm4_cbc")] 29 | mod sm4_cbc; 30 | 31 | mod xor; 32 | pub use xor::simple_hash; 33 | -------------------------------------------------------------------------------- /vnt/src/cipher/rsa_cipher.rs: -------------------------------------------------------------------------------- 1 | use std::io; 2 | 3 | use { 4 | crate::protocol::body::{RsaSecretBody, RSA_ENCRYPTION_RESERVED}, 5 | rand::Rng, 6 | rsa::pkcs8::der::Decode, 7 | rsa::RsaPublicKey, 8 | sha2::Digest, 9 | spki::{DecodePublicKey, EncodePublicKey}, 10 | }; 11 | 12 | use crate::protocol::NetPacket; 13 | 14 | #[derive(Clone)] 15 | pub struct RsaCipher { 16 | inner: Inner, 17 | } 18 | #[derive(Clone)] 19 | struct Inner { 20 | public_key: RsaPublicKey, 21 | finger: String, 22 | } 23 | 24 | impl RsaCipher { 25 | pub fn new(der: &[u8]) -> io::Result { 26 | match RsaPublicKey::from_public_key_der(der) { 27 | Ok(public_key) => { 28 | let finger = finger(&public_key)?; 29 | let inner = Inner { public_key, finger }; 30 | Ok(Self { inner }) 31 | } 32 | Err(e) => Err(io::Error::new( 33 | io::ErrorKind::Other, 34 | format!("from_public_key_der failed {}", e), 35 | )), 36 | } 37 | } 38 | pub fn finger(&self) -> &String { 39 | &self.inner.finger 40 | } 41 | pub fn public_key(&self) -> io::Result<&RsaPublicKey> { 42 | return Ok(&self.inner.public_key); 43 | } 44 | } 45 | pub fn finger(public_key: &RsaPublicKey) -> io::Result { 46 | match public_key.to_public_key_der() { 47 | Ok(der) => match rsa::pkcs8::SubjectPublicKeyInfoRef::from_der(der.as_bytes()) { 48 | Ok(spki) => match spki.fingerprint_base64() { 49 | Ok(finger) => Ok(finger), 50 | Err(e) => Err(io::Error::new( 51 | io::ErrorKind::Other, 52 | format!("fingerprint_base64 error {}", e), 53 | )), 54 | }, 55 | Err(e) => Err(io::Error::new( 56 | io::ErrorKind::Other, 57 | format!("from_der error {}", e), 58 | )), 59 | }, 60 | Err(e) => Err(io::Error::new( 61 | io::ErrorKind::Other, 62 | format!("to_public_key_der error {}", e), 63 | )), 64 | } 65 | } 66 | 67 | impl RsaCipher { 68 | /// net_packet 必须预留足够长度 69 | pub fn encrypt + AsMut<[u8]>>( 70 | &self, 71 | net_packet: &mut NetPacket, 72 | ) -> io::Result>> { 73 | if net_packet.reserve() < RSA_ENCRYPTION_RESERVED { 74 | return Err(io::Error::new(io::ErrorKind::Other, "too short")); 75 | } 76 | let data_len = net_packet.data_len() + RSA_ENCRYPTION_RESERVED; 77 | net_packet.set_data_len(data_len)?; 78 | let mut nonce_raw = [0; 12]; 79 | nonce_raw[0..4].copy_from_slice(&net_packet.source().octets()); 80 | nonce_raw[4..8].copy_from_slice(&net_packet.destination().octets()); 81 | nonce_raw[8] = net_packet.protocol().into(); 82 | nonce_raw[9] = net_packet.transport_protocol(); 83 | nonce_raw[10] = net_packet.is_gateway() as u8; 84 | nonce_raw[11] = net_packet.source_ttl(); 85 | 86 | let mut secret_body = RsaSecretBody::new(net_packet.payload_mut())?; 87 | let mut rng = rand::thread_rng(); 88 | rng.fill(secret_body.random_mut()); 89 | 90 | let mut hasher = sha2::Sha256::new(); 91 | hasher.update(secret_body.body()); 92 | hasher.update(nonce_raw); 93 | let key: [u8; 32] = hasher.finalize().into(); 94 | secret_body.set_finger(&key[16..])?; 95 | match self.inner.public_key.encrypt( 96 | &mut rng, 97 | rsa::pkcs1v15::Pkcs1v15Encrypt, 98 | secret_body.buffer(), 99 | ) { 100 | Ok(enc_data) => { 101 | let mut net_packet_e = NetPacket::new(vec![0; 12 + enc_data.len()])?; 102 | net_packet_e.buffer_mut()[..12].copy_from_slice(&net_packet.buffer()[..12]); 103 | net_packet_e.set_payload(&enc_data)?; 104 | Ok(net_packet_e) 105 | } 106 | Err(e) => Err(io::Error::new( 107 | io::ErrorKind::Other, 108 | format!("encrypt failed {}", e), 109 | )), 110 | } 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /vnt/src/cipher/sm4_cbc/mod.rs: -------------------------------------------------------------------------------- 1 | mod rs_sm4_cbc; 2 | pub use rs_sm4_cbc::*; 3 | -------------------------------------------------------------------------------- /vnt/src/cipher/xor/mod.rs: -------------------------------------------------------------------------------- 1 | mod xor; 2 | pub use xor::*; 3 | -------------------------------------------------------------------------------- /vnt/src/cipher/xor/xor.rs: -------------------------------------------------------------------------------- 1 | use anyhow::anyhow; 2 | 3 | use crate::protocol::NetPacket; 4 | 5 | pub fn simple_hash(input: &str) -> [u8; 32] { 6 | let mut result = [0u8; 32]; 7 | let bytes = input.as_bytes(); 8 | for (index, v) in result.iter_mut().enumerate() { 9 | *v = bytes[index % bytes.len()]; 10 | } 11 | 12 | let mut state = 0u8; 13 | 14 | for (i, &byte) in bytes.iter().enumerate() { 15 | let combined = byte.wrapping_add(state).rotate_left((i % 8) as u32); 16 | result[i % 32] ^= combined; 17 | state = state.wrapping_add(byte).rotate_left(3); 18 | } 19 | 20 | for i in 0..32 { 21 | result[i] = result[i] 22 | .rotate_left((result[(i + 1) % 32] % 8) as u32) 23 | .wrapping_add(state); 24 | state = state.wrapping_add(result[i]).rotate_left(3); 25 | } 26 | 27 | result 28 | } 29 | 30 | #[derive(Clone)] 31 | pub struct XORCipher { 32 | key: [u8; 32], 33 | } 34 | 35 | impl XORCipher { 36 | pub fn new_256(key: [u8; 32]) -> Self { 37 | Self { key } 38 | } 39 | } 40 | 41 | impl XORCipher { 42 | pub fn key(&self) -> &[u8] { 43 | &self.key 44 | } 45 | } 46 | 47 | impl XORCipher { 48 | pub fn decrypt_ipv4 + AsMut<[u8]>>( 49 | &self, 50 | net_packet: &mut NetPacket, 51 | ) -> anyhow::Result<()> { 52 | if !net_packet.is_encrypt() { 53 | //未加密的数据直接丢弃 54 | return Err(anyhow!("not encrypt")); 55 | } 56 | let key = &self.key; 57 | for (i, byte) in net_packet.payload_mut().iter_mut().enumerate() { 58 | *byte ^= key[i & 31]; 59 | } 60 | net_packet.set_encrypt_flag(false); 61 | Ok(()) 62 | } 63 | pub fn encrypt_ipv4 + AsMut<[u8]>>( 64 | &self, 65 | net_packet: &mut NetPacket, 66 | ) -> anyhow::Result<()> { 67 | net_packet.set_encrypt_flag(true); 68 | let key = &self.key; 69 | for (i, byte) in net_packet.payload_mut().iter_mut().enumerate() { 70 | *byte ^= key[i & 31]; 71 | } 72 | Ok(()) 73 | } 74 | } 75 | 76 | #[test] 77 | fn test_xor() { 78 | let d = XORCipher::new_256(simple_hash("password")); 79 | let mut p = NetPacket::new_encrypt([0; 1000]).unwrap(); 80 | let src = p.buffer().to_vec(); 81 | d.encrypt_ipv4(&mut p).unwrap(); 82 | d.decrypt_ipv4(&mut p).unwrap(); 83 | assert_eq!(p.buffer(), &src) 84 | } 85 | -------------------------------------------------------------------------------- /vnt/src/compression/lz4_compress.rs: -------------------------------------------------------------------------------- 1 | use anyhow::anyhow; 2 | 3 | use crate::protocol::NetPacket; 4 | 5 | #[derive(Clone)] 6 | pub struct Lz4Compressor; 7 | 8 | impl Lz4Compressor { 9 | pub fn compress, O: AsRef<[u8]> + AsMut<[u8]>>( 10 | in_net_packet: &NetPacket, 11 | out: &mut NetPacket, 12 | ) -> anyhow::Result<()> { 13 | out.set_data_len_max(); 14 | let len = match lz4_flex::compress_into(in_net_packet.payload(), out.payload_mut()) { 15 | Ok(len) => len, 16 | Err(e) => Err(anyhow!("Lz4 compress {}", e))?, 17 | }; 18 | out.set_payload_len(len)?; 19 | Ok(()) 20 | } 21 | pub fn decompress, O: AsRef<[u8]> + AsMut<[u8]>>( 22 | in_net_packet: &NetPacket, 23 | out: &mut NetPacket, 24 | ) -> anyhow::Result<()> { 25 | out.set_data_len_max(); 26 | let len = match lz4_flex::decompress_into(in_net_packet.payload(), out.payload_mut()) { 27 | Ok(len) => len, 28 | Err(e) => Err(anyhow!("Lz4 decompress {}", e))?, 29 | }; 30 | out.set_payload_len(len)?; 31 | Ok(()) 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /vnt/src/compression/zstd_compress.rs: -------------------------------------------------------------------------------- 1 | use crate::protocol::NetPacket; 2 | use anyhow::anyhow; 3 | use zstd::zstd_safe::CompressionLevel; 4 | 5 | #[derive(Clone)] 6 | pub struct ZstdCompressor; 7 | 8 | impl ZstdCompressor { 9 | pub fn compress, O: AsRef<[u8]> + AsMut<[u8]>>( 10 | compression_level: CompressionLevel, 11 | in_net_packet: &NetPacket, 12 | out: &mut NetPacket, 13 | ) -> anyhow::Result<()> { 14 | out.set_data_len_max(); 15 | let len = match zstd::zstd_safe::compress( 16 | out.payload_mut(), 17 | in_net_packet.payload(), 18 | compression_level, 19 | ) { 20 | Ok(len) => len, 21 | Err(e) => Err(anyhow!("zstd compress {}", e))?, 22 | }; 23 | out.set_payload_len(len)?; 24 | Ok(()) 25 | } 26 | pub fn decompress, O: AsRef<[u8]> + AsMut<[u8]>>( 27 | in_net_packet: &NetPacket, 28 | out: &mut NetPacket, 29 | ) -> anyhow::Result<()> { 30 | out.set_data_len_max(); 31 | let len = match zstd::zstd_safe::decompress(out.payload_mut(), in_net_packet.payload()) { 32 | Ok(len) => len, 33 | Err(e) => Err(anyhow!("zstd decompress {}", e))?, 34 | }; 35 | out.set_payload_len(len)?; 36 | Ok(()) 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /vnt/src/external_route/mod.rs: -------------------------------------------------------------------------------- 1 | use std::net::Ipv4Addr; 2 | use std::sync::Arc; 3 | 4 | // 目标网段,子网掩码,网关 5 | #[derive(Clone)] 6 | pub struct ExternalRoute { 7 | route_table: Vec<(u32, u32, Ipv4Addr)>, 8 | } 9 | 10 | impl ExternalRoute { 11 | pub fn new(mut route_table: Vec<(u32, u32, Ipv4Addr)>) -> Self { 12 | for (dest, mask, _) in &mut route_table { 13 | *dest = *mask & *dest; 14 | } 15 | route_table.sort_by(|(dest1, _, _), (dest2, _, _)| dest2.cmp(dest1)); 16 | Self { route_table } 17 | } 18 | pub fn route(&self, ip: &Ipv4Addr) -> Option { 19 | if self.route_table.is_empty() { 20 | return None; 21 | } 22 | let ip = u32::from_be_bytes(ip.octets()); 23 | for (dest, mask, gateway) in self.route_table.iter() { 24 | if *mask & ip == *dest { 25 | return Some(*gateway); 26 | } 27 | } 28 | None 29 | } 30 | pub fn to_route(&self) -> Vec<(Ipv4Addr, Ipv4Addr)> { 31 | self.route_table 32 | .iter() 33 | .map(|(dest, mask, _)| (Ipv4Addr::from(*dest), Ipv4Addr::from(*mask))) 34 | .collect::>() 35 | } 36 | } 37 | 38 | // 目标网段,子网掩码 39 | #[derive(Clone)] 40 | pub struct AllowExternalRoute { 41 | route_table: Arc>, 42 | } 43 | 44 | impl AllowExternalRoute { 45 | pub fn new(mut route_table: Vec<(u32, u32)>) -> Self { 46 | for (dest, mask) in &mut route_table { 47 | *dest = *mask & *dest; 48 | } 49 | route_table.sort_by(|(dest1, _), (dest2, _)| dest2.cmp(dest1)); 50 | Self { 51 | route_table: Arc::new(route_table), 52 | } 53 | } 54 | pub fn allow(&self, ip: &Ipv4Addr) -> bool { 55 | if self.route_table.is_empty() { 56 | return false; 57 | } 58 | let ip = u32::from_be_bytes(ip.octets()); 59 | for (dest, mask) in self.route_table.iter() { 60 | if *mask & ip == *mask & *dest { 61 | return true; 62 | } 63 | } 64 | false 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /vnt/src/handle/extension/mod.rs: -------------------------------------------------------------------------------- 1 | use crate::compression::Compressor; 2 | use crate::protocol::extension::ExtensionTailPacket; 3 | use crate::protocol::NetPacket; 4 | use anyhow::anyhow; 5 | 6 | pub fn handle_extension_tail + AsMut<[u8]>, O: AsRef<[u8]> + AsMut<[u8]>>( 7 | in_net_packet: &mut NetPacket, 8 | out: &mut NetPacket, 9 | ) -> anyhow::Result { 10 | if in_net_packet.is_extension() { 11 | let tail_packet = in_net_packet.split_tail_packet()?; 12 | match tail_packet { 13 | ExtensionTailPacket::Compression(extension) => { 14 | let compression_algorithm = extension.algorithm(); 15 | Compressor::decompress(compression_algorithm, &in_net_packet, out)?; 16 | out.head_mut().copy_from_slice(in_net_packet.head()); 17 | Ok(true) 18 | } 19 | ExtensionTailPacket::Unknown => Err(anyhow!("Unknown decompress")), 20 | } 21 | } else { 22 | Ok(false) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /vnt/src/handle/handshaker.rs: -------------------------------------------------------------------------------- 1 | use std::io; 2 | use std::net::SocketAddr; 3 | use std::sync::Arc; 4 | use std::time::{Duration, Instant}; 5 | 6 | use crossbeam_utils::atomic::AtomicCell; 7 | #[cfg(feature = "server_encrypt")] 8 | use parking_lot::Mutex; 9 | use protobuf::Message; 10 | 11 | use crate::channel::context::ChannelContext; 12 | #[cfg(feature = "server_encrypt")] 13 | use crate::cipher::RsaCipher; 14 | use crate::handle::{GATEWAY_IP, SELF_IP}; 15 | use crate::proto::message::HandshakeRequest; 16 | #[cfg(feature = "server_encrypt")] 17 | use crate::proto::message::SecretHandshakeRequest; 18 | #[cfg(feature = "server_encrypt")] 19 | use crate::protocol::body::RSA_ENCRYPTION_RESERVED; 20 | use crate::protocol::{service_packet, NetPacket, Protocol, MAX_TTL}; 21 | 22 | #[derive(Clone)] 23 | pub struct Handshake { 24 | time: Arc>, 25 | #[cfg(feature = "server_encrypt")] 26 | rsa_cipher: Arc>>, 27 | } 28 | impl Handshake { 29 | pub fn new( 30 | #[cfg(feature = "server_encrypt")] rsa_cipher: Arc>>, 31 | ) -> Self { 32 | Handshake { 33 | time: Arc::new(AtomicCell::new( 34 | Instant::now() 35 | .checked_sub(Duration::from_secs(60)) 36 | .unwrap_or(Instant::now()), 37 | )), 38 | #[cfg(feature = "server_encrypt")] 39 | rsa_cipher, 40 | } 41 | } 42 | pub fn send(&self, context: &ChannelContext, secret: bool, addr: SocketAddr) -> io::Result<()> { 43 | let last = self.time.load(); 44 | //短时间不重复发送 45 | if last.elapsed() < Duration::from_secs(3) { 46 | return Ok(()); 47 | } 48 | let request_packet = self.handshake_request_packet(secret)?; 49 | log::info!("发送握手请求,secret={},{:?}", secret, addr); 50 | context.send_default(&request_packet, addr)?; 51 | self.time.store(Instant::now()); 52 | Ok(()) 53 | } 54 | /// 第一次握手数据 55 | pub fn handshake_request_packet(&self, secret: bool) -> io::Result>> { 56 | let mut request = HandshakeRequest::new(); 57 | request.secret = secret; 58 | request.version = crate::VNT_VERSION.to_string(); 59 | #[cfg(feature = "server_encrypt")] 60 | if let Some(finger) = self.rsa_cipher.lock().as_ref().map(|v| v.finger().clone()) { 61 | request.key_finger = finger; 62 | } 63 | let bytes = request.write_to_bytes().map_err(|e| { 64 | io::Error::new( 65 | io::ErrorKind::Other, 66 | format!("handshake_request_packet {:?}", e), 67 | ) 68 | })?; 69 | let buf = vec![0u8; 12 + bytes.len()]; 70 | let mut net_packet = NetPacket::new(buf)?; 71 | net_packet.set_default_version(); 72 | net_packet.set_gateway_flag(true); 73 | net_packet.set_destination(GATEWAY_IP); 74 | net_packet.set_source(SELF_IP); 75 | net_packet.set_protocol(Protocol::Service); 76 | net_packet.set_transport_protocol(service_packet::Protocol::HandshakeRequest.into()); 77 | net_packet.first_set_ttl(MAX_TTL); 78 | net_packet.set_payload(&bytes)?; 79 | Ok(net_packet) 80 | } 81 | } 82 | 83 | /// 第二次加密握手 84 | #[cfg(feature = "server_encrypt")] 85 | pub fn secret_handshake_request_packet( 86 | rsa_cipher: &RsaCipher, 87 | token: String, 88 | key: &[u8], 89 | ) -> io::Result>> { 90 | let mut request = SecretHandshakeRequest::new(); 91 | request.token = token; 92 | request.key = key.to_vec(); 93 | let bytes = request.write_to_bytes().map_err(|e| { 94 | io::Error::new( 95 | io::ErrorKind::Other, 96 | format!("secret_handshake_request_packet {:?}", e), 97 | ) 98 | })?; 99 | let mut net_packet = NetPacket::new0( 100 | 12 + bytes.len(), 101 | vec![0u8; 12 + bytes.len() + RSA_ENCRYPTION_RESERVED], 102 | )?; 103 | net_packet.set_default_version(); 104 | net_packet.set_gateway_flag(true); 105 | net_packet.set_destination(GATEWAY_IP); 106 | net_packet.set_source(SELF_IP); 107 | net_packet.set_protocol(Protocol::Service); 108 | net_packet.set_transport_protocol(service_packet::Protocol::SecretHandshakeRequest.into()); 109 | net_packet.first_set_ttl(MAX_TTL); 110 | net_packet.set_payload(&bytes)?; 111 | Ok(rsa_cipher.encrypt(&mut net_packet)?) 112 | } 113 | -------------------------------------------------------------------------------- /vnt/src/handle/maintain/addr_request.rs: -------------------------------------------------------------------------------- 1 | use std::sync::Arc; 2 | use std::time::Duration; 3 | 4 | use crossbeam_utils::atomic::AtomicCell; 5 | 6 | use crate::channel::context::ChannelContext; 7 | use crate::channel::punch::NatType; 8 | use crate::handle::{BaseConfigInfo, CurrentDeviceInfo}; 9 | use crate::nat::NatTest; 10 | use crate::util::Scheduler; 11 | 12 | pub fn addr_request( 13 | scheduler: &Scheduler, 14 | context: ChannelContext, 15 | current_device_info: Arc>, 16 | nat_test: NatTest, 17 | _config: BaseConfigInfo, 18 | ) { 19 | pub_address_request(scheduler, context, current_device_info.clone(), nat_test, 0); 20 | } 21 | 22 | fn pub_address_request( 23 | scheduler: &Scheduler, 24 | context: ChannelContext, 25 | current_device_info: Arc>, 26 | nat_test: NatTest, 27 | count: usize, 28 | ) { 29 | let channel_num = context.channel_num(); 30 | let index = count % channel_num; 31 | if let Err(e) = addr_request0(&context, ¤t_device_info, &nat_test, index) { 32 | log::warn!("{:?}", e); 33 | } 34 | let nat_info = nat_test.nat_info(); 35 | let time = if !nat_info.public_ports.contains(&0) && !nat_info.public_ips.is_empty() { 36 | //对称网络探测端口没啥作用,把频率放低,(锥形网络也只在打洞前需要探测端口,后续可以改改) 37 | if nat_info.nat_type == NatType::Symmetric { 38 | 600 39 | } else { 40 | if index == channel_num - 1 { 41 | 19 42 | } else { 43 | 9 44 | } 45 | } 46 | } else { 47 | 3 48 | }; 49 | 50 | let rs = scheduler.timeout(Duration::from_secs(time), move |s| { 51 | pub_address_request(s, context, current_device_info, nat_test, index + 1) 52 | }); 53 | if !rs { 54 | log::info!("定时任务停止"); 55 | } 56 | } 57 | 58 | fn addr_request0( 59 | context: &ChannelContext, 60 | current_device: &AtomicCell, 61 | nat_test: &NatTest, 62 | index: usize, 63 | ) -> anyhow::Result<()> { 64 | let current_dev = current_device.load(); 65 | if current_dev.status.offline() { 66 | return Ok(()); 67 | } 68 | let (data, addr) = nat_test.send_data()?; 69 | context.send_main_udp(index, &data, addr)?; 70 | Ok(()) 71 | } 72 | -------------------------------------------------------------------------------- /vnt/src/handle/maintain/mod.rs: -------------------------------------------------------------------------------- 1 | mod heartbeat; 2 | pub use heartbeat::client_relay; 3 | pub use heartbeat::heartbeat; 4 | 5 | mod re_nat_type; 6 | pub use re_nat_type::retrieve_nat_type; 7 | 8 | mod addr_request; 9 | pub use addr_request::*; 10 | 11 | mod punch; 12 | pub use punch::*; 13 | 14 | mod idle; 15 | pub use idle::idle_gateway; 16 | pub use idle::idle_route; 17 | 18 | mod up_status; 19 | pub use up_status::*; 20 | -------------------------------------------------------------------------------- /vnt/src/handle/maintain/re_nat_type.rs: -------------------------------------------------------------------------------- 1 | use std::thread; 2 | use std::time::Duration; 3 | 4 | use crate::channel::context::ChannelContext; 5 | use crate::channel::sender::AcceptSocketSender; 6 | use crate::nat; 7 | use crate::nat::NatTest; 8 | use crate::util::Scheduler; 9 | 10 | /// 10分钟探测一次nat 11 | pub fn retrieve_nat_type( 12 | scheduler: &Scheduler, 13 | context: ChannelContext, 14 | nat_test: NatTest, 15 | udp_socket_sender: AcceptSocketSender>>, 16 | ) { 17 | retrieve_nat_type0(context.clone(), nat_test.clone(), udp_socket_sender.clone()); 18 | scheduler.timeout(Duration::from_secs(60 * 10), move |s| { 19 | retrieve_nat_type(s, context, nat_test, udp_socket_sender) 20 | }); 21 | } 22 | 23 | fn retrieve_nat_type0( 24 | context: ChannelContext, 25 | nat_test: NatTest, 26 | udp_socket_sender: AcceptSocketSender>>, 27 | ) { 28 | thread::Builder::new() 29 | .name("natTest".into()) 30 | .spawn(move || { 31 | if nat_test.can_update() { 32 | let local_ipv4 = if nat_test.update_local_ipv4 { 33 | nat::local_ipv4() 34 | } else { 35 | None 36 | }; 37 | let local_ipv6 = nat::local_ipv6(); 38 | match nat_test.re_test(local_ipv4, local_ipv6, context.default_interface()) { 39 | Ok(nat_info) => { 40 | log::info!("当前nat信息:{:?}", nat_info); 41 | if let Err(e) = context.switch(nat_info.nat_type, &udp_socket_sender) { 42 | log::warn!("{:?}", e); 43 | } 44 | } 45 | Err(e) => { 46 | log::warn!("nat re_test {:?}", e); 47 | } 48 | }; 49 | #[cfg(feature = "upnp")] 50 | nat_test.reset_upnp(); 51 | log::info!("刷新nat结束") 52 | } 53 | }) 54 | .expect("natTest"); 55 | } 56 | -------------------------------------------------------------------------------- /vnt/src/handle/maintain/up_status.rs: -------------------------------------------------------------------------------- 1 | use crate::channel::context::ChannelContext; 2 | use crate::handle::CurrentDeviceInfo; 3 | use crate::proto::message::{ClientStatusInfo, PunchNatType, RouteItem}; 4 | use crate::protocol::body::ENCRYPTION_RESERVED; 5 | use crate::protocol::{service_packet, NetPacket, Protocol, HEAD_LEN, MAX_TTL}; 6 | use crate::util::Scheduler; 7 | use crossbeam_utils::atomic::AtomicCell; 8 | use protobuf::Message; 9 | use std::io; 10 | use std::sync::Arc; 11 | use std::time::Duration; 12 | 13 | /// 上报状态给服务器 14 | pub fn up_status( 15 | scheduler: &Scheduler, 16 | context: ChannelContext, 17 | current_device_info: Arc>, 18 | ) { 19 | let _ = scheduler.timeout(Duration::from_secs(60), move |x| { 20 | up_status0(x, context, current_device_info) 21 | }); 22 | } 23 | 24 | fn up_status0( 25 | scheduler: &Scheduler, 26 | context: ChannelContext, 27 | current_device_info: Arc>, 28 | ) { 29 | if let Err(e) = send_up_status_packet(&context, ¤t_device_info) { 30 | log::warn!("{:?}", e) 31 | } 32 | let rs = scheduler.timeout(Duration::from_secs(10 * 60), move |x| { 33 | up_status0(x, context, current_device_info) 34 | }); 35 | if !rs { 36 | log::info!("定时任务停止"); 37 | } 38 | } 39 | 40 | fn send_up_status_packet( 41 | context: &ChannelContext, 42 | current_device_info: &AtomicCell, 43 | ) -> io::Result<()> { 44 | let device_info = current_device_info.load(); 45 | if device_info.status.offline() { 46 | return Ok(()); 47 | } 48 | let routes = context.route_table.route_table_p2p(); 49 | if routes.is_empty() { 50 | return Ok(()); 51 | } 52 | let mut message = ClientStatusInfo::new(); 53 | message.source = device_info.virtual_ip.into(); 54 | for (ip, _) in routes { 55 | let mut item = RouteItem::new(); 56 | item.next_ip = ip.into(); 57 | message.p2p_list.push(item); 58 | } 59 | message.up_stream = context.up_traffic_meter.as_ref().map_or(0, |v| v.total()); 60 | message.down_stream = context.down_traffic_meter.as_ref().map_or(0, |v| v.total()); 61 | message.nat_type = protobuf::EnumOrUnknown::new(if context.is_cone() { 62 | PunchNatType::Cone 63 | } else { 64 | PunchNatType::Symmetric 65 | }); 66 | let buf = message 67 | .write_to_bytes() 68 | .map_err(|e| io::Error::new(io::ErrorKind::Other, format!("up_status_packet {:?}", e)))?; 69 | let mut net_packet = 70 | NetPacket::new_encrypt(vec![0; HEAD_LEN + buf.len() + ENCRYPTION_RESERVED])?; 71 | net_packet.set_default_version(); 72 | net_packet.set_gateway_flag(true); 73 | net_packet.set_protocol(Protocol::Service); 74 | net_packet.set_transport_protocol_into(service_packet::Protocol::ClientStatusInfo); 75 | net_packet.first_set_ttl(MAX_TTL); 76 | net_packet.set_source(device_info.virtual_ip); 77 | net_packet.set_destination(device_info.virtual_gateway); 78 | net_packet.set_payload(&buf)?; 79 | context.send_default(&net_packet, device_info.connect_server)?; 80 | Ok(()) 81 | } 82 | -------------------------------------------------------------------------------- /vnt/src/handle/recv_data/turn.rs: -------------------------------------------------------------------------------- 1 | use crate::channel::context::ChannelContext; 2 | use crate::channel::RouteKey; 3 | use crate::handle::recv_data::PacketHandler; 4 | use crate::handle::CurrentDeviceInfo; 5 | use crate::protocol::NetPacket; 6 | use anyhow::Context; 7 | 8 | /// 处理客户端中转包 9 | #[derive(Clone)] 10 | pub struct TurnPacketHandler {} 11 | 12 | impl TurnPacketHandler { 13 | pub fn new() -> Self { 14 | Self {} 15 | } 16 | } 17 | 18 | impl PacketHandler for TurnPacketHandler { 19 | fn handle( 20 | &self, 21 | mut net_packet: NetPacket<&mut [u8]>, 22 | _extend: NetPacket<&mut [u8]>, 23 | route_key: RouteKey, 24 | context: &ChannelContext, 25 | _current_device: &CurrentDeviceInfo, 26 | ) -> anyhow::Result<()> { 27 | // ttl减一 28 | let ttl = net_packet.incr_ttl(); 29 | if ttl > 0 { 30 | if net_packet.is_gateway() { 31 | // 暂时不转发服务端包 32 | return Ok(()); 33 | } 34 | let destination = net_packet.destination(); 35 | if let Some(route) = context.route_table.route_one(&destination) { 36 | if route.addr == route_key.addr { 37 | //防止环路 38 | log::warn!("来源和目标相同 {:?},{:?}", route_key, net_packet.head()); 39 | return Ok(()); 40 | } 41 | if route.metric <= ttl { 42 | return context 43 | .send_by_key(&net_packet, route.route_key()) 44 | .context("转发失败"); 45 | } 46 | } 47 | //其他没有路由的不转发 48 | } 49 | log::info!("没有路由 {:?},{:?}", route_key, net_packet.head()); 50 | Ok(()) 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /vnt/src/handle/registrar.rs: -------------------------------------------------------------------------------- 1 | use anyhow::anyhow; 2 | use std::net::Ipv4Addr; 3 | 4 | use protobuf::Message; 5 | 6 | use crate::cipher::Cipher; 7 | use crate::handle::{GATEWAY_IP, SELF_IP}; 8 | use crate::proto::message::RegistrationRequest; 9 | use crate::protocol::body::ENCRYPTION_RESERVED; 10 | use crate::protocol::{service_packet, NetPacket, Protocol, MAX_TTL}; 11 | 12 | /// 注册数据 13 | pub fn registration_request_packet( 14 | server_cipher: &Cipher, 15 | token: String, 16 | device_id: String, 17 | name: String, 18 | ip: Option, 19 | is_fast: bool, 20 | allow_ip_change: bool, 21 | client_secret_hash: Option<&[u8]>, 22 | ) -> anyhow::Result>> { 23 | let mut request = RegistrationRequest::new(); 24 | request.token = token; 25 | request.device_id = device_id; 26 | request.name = name; 27 | if let Some(ip) = ip { 28 | request.virtual_ip = ip.into(); 29 | } 30 | request.allow_ip_change = allow_ip_change; 31 | request.is_fast = is_fast; 32 | request.version = crate::VNT_VERSION.to_string(); 33 | if let Some(client_secret_hash) = client_secret_hash { 34 | request.client_secret = true; 35 | request 36 | .client_secret_hash 37 | .extend_from_slice(client_secret_hash); 38 | } 39 | let bytes = request 40 | .write_to_bytes() 41 | .map_err(|e| anyhow!("RegistrationRequest {:?}", e))?; 42 | let buf = vec![0u8; 12 + bytes.len() + ENCRYPTION_RESERVED]; 43 | let mut net_packet = NetPacket::new_encrypt(buf)?; 44 | net_packet.set_destination(GATEWAY_IP); 45 | net_packet.set_source(SELF_IP); 46 | net_packet.set_default_version(); 47 | net_packet.set_gateway_flag(true); 48 | net_packet.set_protocol(Protocol::Service); 49 | net_packet.set_transport_protocol(service_packet::Protocol::RegistrationRequest.into()); 50 | net_packet.first_set_ttl(MAX_TTL); 51 | net_packet.set_payload(&bytes)?; 52 | server_cipher.encrypt_ipv4(&mut net_packet)?; 53 | Ok(net_packet) 54 | } 55 | -------------------------------------------------------------------------------- /vnt/src/handle/tun_tap/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod tun_handler; 2 | 3 | use crossbeam_utils::atomic::AtomicCell; 4 | use parking_lot::Mutex; 5 | use std::sync::Arc; 6 | mod platform; 7 | 8 | pub(crate) use platform::*; 9 | 10 | /// 仅仅是停止tun,不停止vnt 11 | #[derive(Clone, Default)] 12 | pub struct DeviceStop { 13 | f: Arc>>>, 14 | stopped: Arc>, 15 | } 16 | 17 | impl DeviceStop { 18 | pub fn set_stop_fn(&self, f: F) 19 | where 20 | F: FnOnce() + Send + 'static, 21 | { 22 | self.f.lock().replace(Box::new(f)); 23 | } 24 | pub fn stop(&self) { 25 | if let Some(f) = self.f.lock().take() { 26 | f() 27 | } 28 | } 29 | pub fn stopped(&self) { 30 | self.stopped.store(true); 31 | } 32 | pub fn is_stopped(&self) -> bool { 33 | self.stopped.load() 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /vnt/src/handle/tun_tap/platform.rs: -------------------------------------------------------------------------------- 1 | use crate::channel::context::ChannelContext; 2 | use crate::channel::BUFFER_SIZE; 3 | use crate::cipher::Cipher; 4 | use crate::compression::Compressor; 5 | use crate::external_route::ExternalRoute; 6 | use crate::handle::tun_tap::DeviceStop; 7 | use crate::handle::{CurrentDeviceInfo, PeerDeviceInfo}; 8 | #[cfg(feature = "ip_proxy")] 9 | use crate::ip_proxy::IpProxyMap; 10 | use crate::util::StopManager; 11 | use crossbeam_utils::atomic::AtomicCell; 12 | use parking_lot::Mutex; 13 | use std::collections::HashMap; 14 | use std::net::Ipv4Addr; 15 | use std::sync::Arc; 16 | use tun_rs::SyncDevice; 17 | 18 | pub(crate) fn start_simple( 19 | stop_manager: StopManager, 20 | context: &ChannelContext, 21 | device: Arc, 22 | current_device: Arc>, 23 | ip_route: ExternalRoute, 24 | #[cfg(feature = "ip_proxy")] ip_proxy_map: Option, 25 | client_cipher: Cipher, 26 | server_cipher: Cipher, 27 | device_map: Arc)>>, 28 | compressor: Compressor, 29 | device_stop: DeviceStop, 30 | allow_wire_guard: bool, 31 | ) -> anyhow::Result<()> { 32 | let worker = { 33 | let device = device.clone(); 34 | stop_manager.add_listener("tun_device".into(), move || { 35 | if let Err(e) = device.shutdown() { 36 | log::warn!("{:?}", e); 37 | } 38 | })? 39 | }; 40 | let worker_cell = Arc::new(AtomicCell::new(Some(worker))); 41 | 42 | { 43 | let worker_cell = worker_cell.clone(); 44 | device_stop.set_stop_fn(move || { 45 | if let Some(worker) = worker_cell.take() { 46 | worker.stop_self() 47 | } 48 | }); 49 | } 50 | if let Err(e) = start_simple0( 51 | context, 52 | device, 53 | current_device, 54 | ip_route, 55 | #[cfg(feature = "ip_proxy")] 56 | ip_proxy_map, 57 | client_cipher, 58 | server_cipher, 59 | device_map, 60 | compressor, 61 | allow_wire_guard, 62 | ) { 63 | log::error!("{:?}", e); 64 | } 65 | device_stop.stopped(); 66 | if let Some(worker) = worker_cell.take() { 67 | worker.stop_all(); 68 | } 69 | Ok(()) 70 | } 71 | 72 | fn start_simple0( 73 | context: &ChannelContext, 74 | device: Arc, 75 | current_device: Arc>, 76 | ip_route: ExternalRoute, 77 | #[cfg(feature = "ip_proxy")] ip_proxy_map: Option, 78 | client_cipher: Cipher, 79 | server_cipher: Cipher, 80 | device_map: Arc)>>, 81 | compressor: Compressor, 82 | allow_wire_guard: bool, 83 | ) -> anyhow::Result<()> { 84 | let mut buf = [0; BUFFER_SIZE]; 85 | let mut extend = [0; BUFFER_SIZE]; 86 | loop { 87 | let len = device.recv(&mut buf[12..])? + 12; 88 | // buf是重复利用的,需要重置头部 89 | buf[..12].fill(0); 90 | match crate::handle::tun_tap::tun_handler::handle( 91 | context, 92 | &mut buf, 93 | len, 94 | &mut extend, 95 | &device, 96 | current_device.load(), 97 | &ip_route, 98 | #[cfg(feature = "ip_proxy")] 99 | &ip_proxy_map, 100 | &client_cipher, 101 | &server_cipher, 102 | &device_map, 103 | &compressor, 104 | allow_wire_guard, 105 | ) { 106 | Ok(_) => {} 107 | Err(e) => { 108 | log::warn!("tun/tap {:?}", e) 109 | } 110 | } 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /vnt/src/ip_proxy/mod.rs: -------------------------------------------------------------------------------- 1 | use std::net::Ipv4Addr; 2 | use std::sync::Arc; 3 | use std::{io, thread}; 4 | 5 | use crossbeam_utils::atomic::AtomicCell; 6 | 7 | use packet::ip::ipv4; 8 | use packet::ip::ipv4::packet::IpV4Packet; 9 | 10 | use crate::channel::context::ChannelContext; 11 | use crate::cipher::Cipher; 12 | use crate::handle::CurrentDeviceInfo; 13 | #[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))] 14 | use crate::ip_proxy::icmp_proxy::IcmpProxy; 15 | use crate::ip_proxy::tcp_proxy::TcpProxy; 16 | use crate::ip_proxy::udp_proxy::UdpProxy; 17 | use crate::util::StopManager; 18 | 19 | #[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))] 20 | pub mod icmp_proxy; 21 | pub mod tcp_proxy; 22 | pub mod udp_proxy; 23 | 24 | pub trait ProxyHandler { 25 | fn recv_handle( 26 | &self, 27 | ipv4: &mut IpV4Packet<&mut [u8]>, 28 | source: Ipv4Addr, 29 | destination: Ipv4Addr, 30 | ) -> io::Result; 31 | fn send_handle(&self, ipv4: &mut IpV4Packet<&mut [u8]>) -> io::Result<()>; 32 | } 33 | 34 | #[derive(Clone)] 35 | pub struct IpProxyMap { 36 | #[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))] 37 | icmp_proxy: IcmpProxy, 38 | tcp_proxy: TcpProxy, 39 | udp_proxy: UdpProxy, 40 | } 41 | 42 | pub fn init_proxy( 43 | context: ChannelContext, 44 | stop_manager: StopManager, 45 | current_device: Arc>, 46 | client_cipher: Cipher, 47 | ) -> anyhow::Result { 48 | let runtime = tokio::runtime::Builder::new_multi_thread() 49 | .enable_all() 50 | .thread_name("ipProxy") 51 | .build()?; 52 | let proxy_map = runtime.block_on(init_proxy0(context, current_device, client_cipher))?; 53 | let (sender, receiver) = tokio::sync::oneshot::channel::<()>(); 54 | let worker = stop_manager.add_listener("ipProxy".into(), move || { 55 | let _ = sender.send(()); 56 | })?; 57 | thread::Builder::new() 58 | .name("ipProxy".into()) 59 | .spawn(move || { 60 | runtime.block_on(async { 61 | let _ = receiver.await; 62 | }); 63 | runtime.shutdown_background(); 64 | drop(worker); 65 | })?; 66 | 67 | return Ok(proxy_map); 68 | } 69 | 70 | async fn init_proxy0( 71 | context: ChannelContext, 72 | _current_device: Arc>, 73 | _client_cipher: Cipher, 74 | ) -> anyhow::Result { 75 | let default_interface = context.default_interface().clone(); 76 | #[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))] 77 | let icmp_proxy = 78 | IcmpProxy::new(context, _current_device, _client_cipher, &default_interface).await?; 79 | let tcp_proxy = TcpProxy::new(default_interface.clone()).await?; 80 | let udp_proxy = UdpProxy::new(default_interface.clone()).await?; 81 | 82 | Ok(IpProxyMap { 83 | #[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))] 84 | icmp_proxy, 85 | tcp_proxy, 86 | udp_proxy, 87 | }) 88 | } 89 | 90 | impl ProxyHandler for IpProxyMap { 91 | fn recv_handle( 92 | &self, 93 | ipv4: &mut IpV4Packet<&mut [u8]>, 94 | source: Ipv4Addr, 95 | destination: Ipv4Addr, 96 | ) -> io::Result { 97 | match ipv4.protocol() { 98 | ipv4::protocol::Protocol::Tcp => self.tcp_proxy.recv_handle(ipv4, source, destination), 99 | ipv4::protocol::Protocol::Udp => self.udp_proxy.recv_handle(ipv4, source, destination), 100 | #[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))] 101 | ipv4::protocol::Protocol::Icmp => { 102 | self.icmp_proxy.recv_handle(ipv4, source, destination) 103 | } 104 | _ => { 105 | log::warn!( 106 | "不支持的ip代理ipv4协议{:?}:{}->{}->{}", 107 | ipv4.protocol(), 108 | source, 109 | destination, 110 | ipv4.destination_ip() 111 | ); 112 | Ok(false) 113 | } 114 | } 115 | } 116 | 117 | fn send_handle(&self, ipv4: &mut IpV4Packet<&mut [u8]>) -> io::Result<()> { 118 | match ipv4.protocol() { 119 | ipv4::protocol::Protocol::Tcp => self.tcp_proxy.send_handle(ipv4), 120 | ipv4::protocol::Protocol::Udp => self.udp_proxy.send_handle(ipv4), 121 | #[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))] 122 | ipv4::protocol::Protocol::Icmp => self.icmp_proxy.send_handle(ipv4), 123 | _ => Ok(()), 124 | } 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /vnt/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub const VNT_VERSION: &'static str = env!("CARGO_PKG_VERSION"); 2 | 3 | pub mod channel; 4 | pub mod cipher; 5 | pub mod core; 6 | mod external_route; 7 | pub mod handle; 8 | #[cfg(feature = "ip_proxy")] 9 | mod ip_proxy; 10 | pub mod nat; 11 | #[cfg(feature = "port_mapping")] 12 | mod port_mapping; 13 | mod proto; 14 | pub mod protocol; 15 | mod tun_tap_device; 16 | pub use tun_tap_device::*; 17 | pub mod util; 18 | 19 | pub use handle::callback::*; 20 | 21 | pub mod compression; 22 | pub use packet; 23 | 24 | pub(crate) fn ignore_io_interrupted(e: std::io::Error) -> std::io::Result<()> { 25 | if e.kind() == std::io::ErrorKind::Interrupted { 26 | log::warn!("ignore_io_interrupted"); 27 | Ok(()) 28 | } else { 29 | Err(e) 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /vnt/src/port_mapping/mod.rs: -------------------------------------------------------------------------------- 1 | use std::net::SocketAddr; 2 | use std::str::FromStr; 3 | use std::thread; 4 | 5 | use anyhow::Context; 6 | 7 | use crate::util::StopManager; 8 | 9 | mod tcp_mapping; 10 | 11 | mod udp_mapping; 12 | 13 | pub fn convert(vec: Vec) -> anyhow::Result> { 14 | let mut rs = Vec::with_capacity(vec.len()); 15 | for x in vec { 16 | let string = x.trim().to_lowercase(); 17 | if let Some(udp_mapping) = string.strip_prefix("udp:") { 18 | let mut split = udp_mapping.split("-"); 19 | let bind_addr = split.next().with_context(|| { 20 | format!( 21 | "udp_mapping error {:?},eg: udp:127.0.0.1:80-10.26.0.10:8080", 22 | x 23 | ) 24 | })?; 25 | let bind_addr = SocketAddr::from_str(bind_addr) 26 | .with_context(|| format!("udp_mapping error {}", bind_addr))?; 27 | let dest = split.next().with_context(|| { 28 | format!( 29 | "udp_mapping error {:?},eg: udp:127.0.0.1:80-10.26.0.10:8080", 30 | x 31 | ) 32 | })?; 33 | rs.push((false, bind_addr, dest.to_string())); 34 | continue; 35 | } 36 | if let Some(tcp_mapping) = string.strip_prefix("tcp:") { 37 | let mut split = tcp_mapping.split("-"); 38 | let bind_addr = split.next().with_context(|| { 39 | format!( 40 | "tcp_mapping error {:?},eg: tcp:127.0.0.1:80-10.26.0.10:8080", 41 | x 42 | ) 43 | })?; 44 | let bind_addr = SocketAddr::from_str(bind_addr) 45 | .with_context(|| format!("udp_mapping error {}", bind_addr))?; 46 | let dest = split.next().with_context(|| { 47 | format!( 48 | "tcp_mapping error {:?},eg: tcp:127.0.0.1:80-10.26.0.10:8080", 49 | x 50 | ) 51 | })?; 52 | rs.push((true, bind_addr, dest.to_string())); 53 | continue; 54 | } 55 | Err(anyhow::anyhow!( 56 | "port_mapping error {:?},eg: tcp:127.0.0.1:80-10.26.0.10:8080", 57 | x 58 | ))?; 59 | } 60 | Ok(rs) 61 | } 62 | pub fn start_port_mapping( 63 | stop_manager: StopManager, 64 | vec: Vec<(bool, SocketAddr, String)>, 65 | ) -> anyhow::Result<()> { 66 | if vec.is_empty() { 67 | return Ok(()); 68 | } 69 | let runtime = tokio::runtime::Builder::new_multi_thread() 70 | .enable_all() 71 | .thread_name("portMapping") 72 | .build()?; 73 | runtime.block_on(start_port_mapping0(vec))?; 74 | let (sender, receiver) = tokio::sync::oneshot::channel::<()>(); 75 | let worker = stop_manager.add_listener("portMapping".into(), move || { 76 | let _ = sender.send(()); 77 | })?; 78 | thread::Builder::new() 79 | .name("portMapping".into()) 80 | .spawn(move || { 81 | runtime.block_on(async { 82 | let _ = receiver.await; 83 | }); 84 | runtime.shutdown_background(); 85 | drop(worker); 86 | })?; 87 | 88 | Ok(()) 89 | } 90 | 91 | async fn start_port_mapping0(vec: Vec<(bool, SocketAddr, String)>) -> anyhow::Result<()> { 92 | for (is_tcp, bind_addr, destination) in vec { 93 | if is_tcp { 94 | tcp_mapping::tcp_mapping(bind_addr, destination).await?; 95 | } else { 96 | udp_mapping::udp_mapping(bind_addr, destination).await?; 97 | } 98 | } 99 | Ok(()) 100 | } 101 | -------------------------------------------------------------------------------- /vnt/src/port_mapping/tcp_mapping.rs: -------------------------------------------------------------------------------- 1 | use anyhow::Context; 2 | use std::net::SocketAddr; 3 | use tokio::net::{TcpListener, TcpStream}; 4 | 5 | pub async fn tcp_mapping(bind_addr: SocketAddr, destination: String) -> anyhow::Result<()> { 6 | let tcp_listener = TcpListener::bind(bind_addr) 7 | .await 8 | .with_context(|| format!("TCP binding {:?} failed", bind_addr))?; 9 | tokio::spawn(async move { 10 | if let Err(e) = tcp_mapping_(bind_addr, tcp_listener, destination).await { 11 | log::warn!("tcp_mapping {:?}", e); 12 | } 13 | }); 14 | Ok(()) 15 | } 16 | 17 | async fn tcp_mapping_( 18 | bind_addr: SocketAddr, 19 | tcp_listener: TcpListener, 20 | destination: String, 21 | ) -> anyhow::Result<()> { 22 | loop { 23 | let (tcp_stream, _) = tcp_listener.accept().await?; 24 | 25 | let destination = destination.clone(); 26 | tokio::spawn(async move { 27 | if let Err(e) = copy(tcp_stream, &destination).await { 28 | log::warn!("tcp port mapping {}->{} {:?}", bind_addr, destination, e); 29 | } 30 | }); 31 | } 32 | } 33 | 34 | async fn copy(source_tcp: TcpStream, destination: &String) -> anyhow::Result<()> { 35 | // 或许这里也应该绑定最匹配的网卡,不然全局代理会影响映射 36 | let dest_tcp = TcpStream::connect(destination) 37 | .await 38 | .with_context(|| format!("TCP connection target failed {:?}", destination))?; 39 | let _ = source_tcp.set_nodelay(true); 40 | let _ = dest_tcp.set_nodelay(true); 41 | 42 | let destination = dest_tcp.peer_addr()?; 43 | let (mut client_read, mut client_write) = source_tcp.into_split(); 44 | let (mut server_read, mut server_write) = dest_tcp.into_split(); 45 | tokio::spawn(async move { 46 | if let Err(e) = tokio::io::copy(&mut client_read, &mut server_write).await { 47 | log::warn!("client tcp proxy ->{:},{:?}", destination, e); 48 | } 49 | }); 50 | if let Err(e) = tokio::io::copy(&mut server_read, &mut client_write).await { 51 | log::warn!("server tcp proxy ->{:?},{:?}", destination, e); 52 | } 53 | Ok(()) 54 | } 55 | -------------------------------------------------------------------------------- /vnt/src/port_mapping/udp_mapping.rs: -------------------------------------------------------------------------------- 1 | use anyhow::Context; 2 | use crossbeam_utils::atomic::AtomicCell; 3 | use parking_lot::Mutex; 4 | use std::collections::HashMap; 5 | use std::net::SocketAddr; 6 | use std::sync::Arc; 7 | use std::time::{Duration, Instant}; 8 | use tokio::net::UdpSocket; 9 | 10 | pub async fn udp_mapping(bind_addr: SocketAddr, destination: String) -> anyhow::Result<()> { 11 | let udp = UdpSocket::bind(bind_addr) 12 | .await 13 | .with_context(|| format!("port proxy UDP binding {:?} failed", bind_addr))?; 14 | let udp = Arc::new(udp); 15 | 16 | let inner_map: Arc, Arc>)>>> = 17 | Arc::new(Mutex::new(HashMap::with_capacity(64))); 18 | 19 | tokio::spawn(async move { 20 | let mut buf = [0; 65536]; 21 | loop { 22 | match udp.recv_from(&mut buf).await { 23 | Ok((len, src_addr)) => { 24 | if let Err(e) = 25 | udp_mapping0(&buf[..len], src_addr, &inner_map, &udp, &destination).await 26 | { 27 | log::warn!("udp port mapping {}->{} {:?}", src_addr, destination, e); 28 | } 29 | } 30 | Err(e) => { 31 | log::warn!("port proxy UDP {:?}", e); 32 | } 33 | } 34 | } 35 | }); 36 | Ok(()) 37 | } 38 | 39 | async fn udp_mapping0( 40 | buf: &[u8], 41 | src_addr: SocketAddr, 42 | inner_map: &Arc, Arc>)>>>, 43 | udp_socket: &Arc, 44 | destination: &String, 45 | ) -> anyhow::Result<()> { 46 | let option = inner_map.lock().get(&src_addr).cloned(); 47 | if let Some((udp, time)) = option { 48 | time.store(Instant::now()); 49 | udp.send(buf).await?; 50 | } else { 51 | let dest_udp = UdpSocket::bind("0.0.0.0:0").await?; 52 | dest_udp.connect(destination).await?; 53 | dest_udp.send(buf).await?; 54 | let destination_addr = dest_udp.peer_addr()?; 55 | let udp_socket = udp_socket.clone(); 56 | let inner_map = inner_map.clone(); 57 | let dest_udp = Arc::new(dest_udp); 58 | let time = Arc::new(AtomicCell::new(Instant::now())); 59 | inner_map 60 | .lock() 61 | .insert(src_addr, (dest_udp.clone(), time.clone())); 62 | tokio::spawn(async move { 63 | let mut buf = [0u8; 65536]; 64 | loop { 65 | match tokio::time::timeout(Duration::from_secs(600), dest_udp.recv(&mut buf)).await 66 | { 67 | Ok(rs) => match rs { 68 | Ok(len) => match udp_socket.send_to(&buf[..len], src_addr).await { 69 | Ok(_) => {} 70 | Err(e) => { 71 | log::warn!( 72 | "udp port mapping {}->{} {:?}", 73 | src_addr, 74 | destination_addr, 75 | e 76 | ); 77 | break; 78 | } 79 | }, 80 | Err(e) => { 81 | log::warn!( 82 | "udp port mapping {}->{} {:?}", 83 | src_addr, 84 | destination_addr, 85 | e 86 | ); 87 | break; 88 | } 89 | }, 90 | Err(_) => { 91 | if time.load().elapsed() > Duration::from_secs(580) { 92 | //超时关闭 93 | log::warn!( 94 | "udp port mapping timeout {}->{} ", 95 | src_addr, 96 | destination_addr 97 | ); 98 | break; 99 | } 100 | } 101 | } 102 | } 103 | inner_map.lock().remove(&src_addr); 104 | }); 105 | } 106 | Ok(()) 107 | } 108 | -------------------------------------------------------------------------------- /vnt/src/protocol/error_packet.rs: -------------------------------------------------------------------------------- 1 | use std::io; 2 | 3 | #[derive(Eq, PartialEq, Copy, Clone, Debug)] 4 | pub enum Protocol { 5 | TokenError, 6 | Disconnect, 7 | AddressExhausted, 8 | IpAlreadyExists, 9 | InvalidIp, 10 | NoKey, 11 | Other(u8), 12 | } 13 | 14 | impl From for Protocol { 15 | fn from(value: u8) -> Self { 16 | match value { 17 | 1 => Self::TokenError, 18 | 2 => Self::Disconnect, 19 | 3 => Self::AddressExhausted, 20 | 4 => Self::IpAlreadyExists, 21 | 5 => Self::InvalidIp, 22 | 6 => Self::NoKey, 23 | val => Self::Other(val), 24 | } 25 | } 26 | } 27 | 28 | impl Into for Protocol { 29 | fn into(self) -> u8 { 30 | match self { 31 | Protocol::TokenError => 1, 32 | Protocol::Disconnect => 2, 33 | Protocol::AddressExhausted => 3, 34 | Protocol::IpAlreadyExists => 4, 35 | Protocol::InvalidIp => 5, 36 | Protocol::NoKey => 6, 37 | Protocol::Other(val) => val, 38 | } 39 | } 40 | } 41 | 42 | pub enum InErrorPacket { 43 | TokenError, 44 | Disconnect, 45 | AddressExhausted, 46 | IpAlreadyExists, 47 | InvalidIp, 48 | NoKey, 49 | OtherError(ErrorPacket), 50 | } 51 | 52 | impl> InErrorPacket { 53 | pub fn new(protocol: u8, buffer: B) -> io::Result> { 54 | match Protocol::from(protocol) { 55 | Protocol::TokenError => Ok(InErrorPacket::TokenError), 56 | Protocol::Disconnect => Ok(InErrorPacket::Disconnect), 57 | Protocol::AddressExhausted => Ok(InErrorPacket::AddressExhausted), 58 | Protocol::IpAlreadyExists => Ok(InErrorPacket::IpAlreadyExists), 59 | Protocol::InvalidIp => Ok(InErrorPacket::InvalidIp), 60 | Protocol::NoKey => Ok(InErrorPacket::NoKey), 61 | Protocol::Other(_) => Ok(InErrorPacket::OtherError(ErrorPacket::new(buffer)?)), 62 | } 63 | } 64 | } 65 | 66 | pub struct ErrorPacket { 67 | buffer: B, 68 | } 69 | 70 | impl> ErrorPacket { 71 | pub fn new(buffer: B) -> io::Result> { 72 | Ok(Self { buffer }) 73 | } 74 | } 75 | 76 | impl> ErrorPacket { 77 | pub fn message(&self) -> io::Result { 78 | match String::from_utf8(self.buffer.as_ref().to_vec()) { 79 | Ok(str) => Ok(str), 80 | Err(_) => Err(io::Error::new(io::ErrorKind::Other, "Utf8Error")), 81 | } 82 | } 83 | } 84 | 85 | impl + AsMut<[u8]>> ErrorPacket { 86 | pub fn set_message(&mut self, message: &str) { 87 | self.buffer.as_mut().copy_from_slice(message.as_bytes()) 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /vnt/src/protocol/extension.rs: -------------------------------------------------------------------------------- 1 | /* 扩展协议 2 | 0 15 31 3 | 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 4 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 5 | | 扩展数据(n) | 6 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 7 | | 扩展数据(n) | type(8) | 8 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 9 | 注:扩展数据的长度由type决定 10 | */ 11 | 12 | use anyhow::anyhow; 13 | use std::io; 14 | 15 | use crate::protocol::NetPacket; 16 | 17 | #[derive(Eq, PartialEq, Copy, Clone, Debug)] 18 | pub enum ExtensionTailType { 19 | Compression, 20 | Unknown(u8), 21 | } 22 | 23 | impl From for ExtensionTailType { 24 | fn from(value: u8) -> Self { 25 | if value == 0 { 26 | ExtensionTailType::Compression 27 | } else { 28 | ExtensionTailType::Unknown(value) 29 | } 30 | } 31 | } 32 | 33 | pub enum ExtensionTailPacket { 34 | Compression(CompressionExtensionTail), 35 | Unknown, 36 | } 37 | 38 | impl + AsMut<[u8]>> NetPacket { 39 | /// 分离尾部数据 40 | pub fn split_tail_packet(&mut self) -> anyhow::Result> { 41 | if self.is_extension() { 42 | let payload = self.payload(); 43 | if let Some(v) = payload.last() { 44 | return match ExtensionTailType::from(*v) { 45 | ExtensionTailType::Compression => { 46 | let data_len = self.data_len - 4; 47 | self.set_data_len(data_len)?; 48 | self.set_extension_flag(false); 49 | Ok(ExtensionTailPacket::Compression( 50 | CompressionExtensionTail::new( 51 | &self.raw_buffer()[data_len..data_len + 4], 52 | ), 53 | )) 54 | } 55 | ExtensionTailType::Unknown(e) => Err(anyhow!("unknown extension {}", e)), 56 | }; 57 | } 58 | } 59 | Err(anyhow!("not extension")) 60 | } 61 | /// 追加压缩扩展 62 | pub fn append_compression_extension_tail( 63 | &mut self, 64 | ) -> io::Result> { 65 | let len = self.data_len; 66 | //增加数据长度 67 | self.set_data_len(self.data_len + 4)?; 68 | self.set_extension_flag(true); 69 | let mut tail = CompressionExtensionTail::new(&mut self.buffer_mut()[len..]); 70 | tail.init(); 71 | return Ok(tail); 72 | } 73 | } 74 | 75 | /* 扩展协议 76 | 0 15 31 77 | 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 78 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 79 | | algorithm(8) | | type(8) | 80 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 81 | 注:扩展数据的长度由type决定 82 | */ 83 | /// 压缩扩展 84 | pub struct CompressionExtensionTail { 85 | buffer: B, 86 | } 87 | 88 | impl> CompressionExtensionTail { 89 | pub fn new(buffer: B) -> CompressionExtensionTail { 90 | assert_eq!(buffer.as_ref().len(), 4); 91 | CompressionExtensionTail { buffer } 92 | } 93 | } 94 | 95 | impl> CompressionExtensionTail { 96 | pub fn algorithm(&self) -> CompressionAlgorithm { 97 | self.buffer.as_ref()[0].into() 98 | } 99 | } 100 | 101 | impl + AsMut<[u8]>> CompressionExtensionTail { 102 | pub fn init(&mut self) { 103 | self.buffer.as_mut().fill(0); 104 | } 105 | pub fn set_algorithm(&mut self, algorithm: CompressionAlgorithm) { 106 | self.buffer.as_mut()[0] = algorithm.into() 107 | } 108 | } 109 | 110 | #[derive(Eq, PartialEq, Copy, Clone, Debug)] 111 | pub enum CompressionAlgorithm { 112 | #[cfg(feature = "lz4_compress")] 113 | Lz4, 114 | #[cfg(feature = "zstd_compress")] 115 | Zstd, 116 | Unknown(u8), 117 | } 118 | 119 | impl From for CompressionAlgorithm { 120 | fn from(value: u8) -> Self { 121 | match value { 122 | #[cfg(feature = "lz4_compress")] 123 | 1 => CompressionAlgorithm::Lz4, 124 | #[cfg(feature = "zstd_compress")] 125 | 2 => CompressionAlgorithm::Zstd, 126 | v => CompressionAlgorithm::Unknown(v), 127 | } 128 | } 129 | } 130 | 131 | impl From for u8 { 132 | fn from(value: CompressionAlgorithm) -> Self { 133 | match value { 134 | #[cfg(feature = "lz4_compress")] 135 | CompressionAlgorithm::Lz4 => 1, 136 | #[cfg(feature = "zstd_compress")] 137 | CompressionAlgorithm::Zstd => 2, 138 | CompressionAlgorithm::Unknown(val) => val, 139 | } 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /vnt/src/protocol/ip_turn_packet.rs: -------------------------------------------------------------------------------- 1 | #![allow(dead_code)] 2 | 3 | use std::io; 4 | use std::net::Ipv4Addr; 5 | 6 | #[derive(Copy, Clone, Eq, PartialEq, Debug)] 7 | pub enum Protocol { 8 | Ipv4, 9 | WGIpv4, 10 | Ipv4Broadcast, 11 | Unknown(u8), 12 | } 13 | 14 | impl From for Protocol { 15 | fn from(value: u8) -> Self { 16 | match value { 17 | 4 => Protocol::Ipv4, 18 | 5 => Protocol::WGIpv4, 19 | 201 => Protocol::Ipv4Broadcast, 20 | val => Protocol::Unknown(val), 21 | } 22 | } 23 | } 24 | 25 | impl From for u8 { 26 | fn from(val: Protocol) -> Self { 27 | match val { 28 | Protocol::Ipv4 => 4, 29 | Protocol::WGIpv4 => 5, 30 | Protocol::Ipv4Broadcast => 201, 31 | Protocol::Unknown(val) => val, 32 | } 33 | } 34 | } 35 | 36 | pub struct BroadcastPacket { 37 | buffer: B, 38 | } 39 | 40 | impl> BroadcastPacket { 41 | pub fn unchecked(buffer: B) -> Self { 42 | Self { buffer } 43 | } 44 | pub fn new(buffer: B) -> io::Result { 45 | let len = buffer.as_ref().len(); 46 | let packet = Self::unchecked(buffer); 47 | if len < 2 + 4 || packet.addr_num() == 0 { 48 | Err(io::Error::new( 49 | io::ErrorKind::InvalidData, 50 | "BroadcastPacket InvalidData", 51 | )) 52 | } else { 53 | Ok(packet) 54 | } 55 | } 56 | } 57 | 58 | impl> BroadcastPacket { 59 | pub fn addr_num(&self) -> u8 { 60 | self.buffer.as_ref()[0] 61 | } 62 | /// 已经发送给了这些地址 63 | pub fn addresses(&self) -> Vec { 64 | let num = self.addr_num() as usize; 65 | let mut list = Vec::with_capacity(num); 66 | let buf = self.buffer.as_ref(); 67 | let mut offset = 1; 68 | for _ in 0..num { 69 | list.push(Ipv4Addr::new( 70 | buf[offset], 71 | buf[offset + 1], 72 | buf[offset + 2], 73 | buf[offset + 3], 74 | )); 75 | offset += 4; 76 | } 77 | list 78 | } 79 | pub fn data(&self) -> io::Result<&[u8]> { 80 | let start = 1 + self.addr_num() as usize * 4; 81 | if start > self.buffer.as_ref().len() { 82 | Err(io::Error::new(io::ErrorKind::InvalidData, "InvalidData")) 83 | } else { 84 | Ok(&self.buffer.as_ref()[start..]) 85 | } 86 | } 87 | } 88 | 89 | impl + AsMut<[u8]>> BroadcastPacket { 90 | pub fn set_address(&mut self, addr: &[Ipv4Addr]) -> io::Result<()> { 91 | let buf = self.buffer.as_mut(); 92 | if buf.len() < 1 + addr.len() * 4 || addr.len() > u8::MAX as usize { 93 | Err(io::Error::new( 94 | io::ErrorKind::InvalidData, 95 | "addr invalid data", 96 | )) 97 | } else { 98 | buf[0] = addr.len() as u8; 99 | let mut offset = 1; 100 | for ip in addr { 101 | buf[offset..offset + 4].copy_from_slice(&ip.octets()); 102 | offset += 4; 103 | } 104 | Ok(()) 105 | } 106 | } 107 | pub fn set_data(&mut self, data: &[u8]) -> io::Result<()> { 108 | let num = self.addr_num() as usize; 109 | let start = 1 + 4 * num; 110 | let buf = self.buffer.as_mut(); 111 | if start >= buf.len() || start + data.len() != buf.len() { 112 | return Err(io::Error::new( 113 | io::ErrorKind::InvalidData, 114 | "data invalid data", 115 | )); 116 | } 117 | buf[start..].copy_from_slice(data); 118 | Ok(()) 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /vnt/src/protocol/other_turn_packet.rs: -------------------------------------------------------------------------------- 1 | #[derive(Copy, Clone, Eq, PartialEq, Debug)] 2 | pub enum Protocol { 3 | Punch, 4 | Unknown(u8), 5 | } 6 | 7 | impl From for Protocol { 8 | fn from(value: u8) -> Self { 9 | match value { 10 | 1 => Protocol::Punch, 11 | val => Protocol::Unknown(val), 12 | } 13 | } 14 | } 15 | 16 | impl Into for Protocol { 17 | fn into(self) -> u8 { 18 | match self { 19 | Protocol::Punch => 1, 20 | Protocol::Unknown(val) => val, 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /vnt/src/protocol/service_packet.rs: -------------------------------------------------------------------------------- 1 | #[derive(Eq, PartialEq, Copy, Clone, Debug)] 2 | pub enum Protocol { 3 | /// 注册请求 4 | RegistrationRequest, 5 | /// 注册响应 6 | RegistrationResponse, 7 | /// 拉取设备列表 8 | PullDeviceList, 9 | /// 推送设备列表 10 | PushDeviceList, 11 | /// 和服务端握手 12 | HandshakeRequest, 13 | HandshakeResponse, 14 | SecretHandshakeRequest, 15 | SecretHandshakeResponse, 16 | /// 客户端上报状态 17 | ClientStatusInfo, 18 | Unknown(u8), 19 | } 20 | 21 | impl From for Protocol { 22 | fn from(value: u8) -> Self { 23 | match value { 24 | 1 => Self::RegistrationRequest, 25 | 2 => Self::RegistrationResponse, 26 | 3 => Self::PullDeviceList, 27 | 4 => Self::PushDeviceList, 28 | 5 => Self::HandshakeRequest, 29 | 6 => Self::HandshakeResponse, 30 | 7 => Self::SecretHandshakeRequest, 31 | 8 => Self::SecretHandshakeResponse, 32 | 9 => Self::ClientStatusInfo, 33 | val => Self::Unknown(val), 34 | } 35 | } 36 | } 37 | 38 | impl Into for Protocol { 39 | fn into(self) -> u8 { 40 | match self { 41 | Self::RegistrationRequest => 1, 42 | Self::RegistrationResponse => 2, 43 | Self::PullDeviceList => 3, 44 | Self::PushDeviceList => 4, 45 | Self::HandshakeRequest => 5, 46 | Self::HandshakeResponse => 6, 47 | Self::SecretHandshakeRequest => 7, 48 | Self::SecretHandshakeResponse => 8, 49 | Self::ClientStatusInfo => 9, 50 | Self::Unknown(val) => val, 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /vnt/src/tun_tap_device/create_device.rs: -------------------------------------------------------------------------------- 1 | use std::io; 2 | use std::net::Ipv4Addr; 3 | use std::sync::Arc; 4 | use tun_rs::SyncDevice; 5 | 6 | use crate::{DeviceConfig, ErrorInfo, ErrorType, VntCallback}; 7 | 8 | #[cfg(any(target_os = "windows", target_os = "linux"))] 9 | const DEFAULT_TUN_NAME: &str = "vnt-tun"; 10 | 11 | pub fn create_device( 12 | config: DeviceConfig, 13 | call: &Call, 14 | ) -> Result, ErrorInfo> { 15 | let device = match create_device0(&config) { 16 | Ok(device) => device, 17 | Err(e) => { 18 | return Err(ErrorInfo::new_msg( 19 | ErrorType::FailedToCrateDevice, 20 | format!("create device {:?}", e), 21 | )); 22 | } 23 | }; 24 | #[cfg(windows)] 25 | let index = device.if_index().unwrap(); 26 | #[cfg(unix)] 27 | let index = &device.name().unwrap(); 28 | if let Err(e) = add_route(index, Ipv4Addr::BROADCAST, Ipv4Addr::BROADCAST) { 29 | log::warn!("添加广播路由失败 ={:?}", e); 30 | } 31 | 32 | if let Err(e) = add_route( 33 | index, 34 | Ipv4Addr::from([224, 0, 0, 0]), 35 | Ipv4Addr::from([240, 0, 0, 0]), 36 | ) { 37 | log::warn!("添加组播路由失败 ={:?}", e); 38 | } 39 | 40 | for (dest, mask) in config.external_route { 41 | if let Err(e) = add_route(index, dest, mask) { 42 | log::warn!("添加路由失败,请检查-i参数是否和现有路由冲突 ={:?}", e); 43 | call.error(ErrorInfo::new_msg( 44 | ErrorType::Warn, 45 | format!( 46 | "警告! 添加路由失败,请检查-i参数是否和现有路由冲突 ={:?}", 47 | e 48 | ), 49 | )) 50 | } 51 | } 52 | Ok(device) 53 | } 54 | 55 | fn create_device0(config: &DeviceConfig) -> io::Result> { 56 | let mut tun_builder = tun_rs::DeviceBuilder::default(); 57 | tun_builder = tun_builder.ipv4(config.virtual_ip, config.virtual_netmask, None); 58 | 59 | match &config.device_name { 60 | None => { 61 | #[cfg(any(target_os = "windows", target_os = "linux"))] 62 | { 63 | tun_builder = tun_builder.name(DEFAULT_TUN_NAME); 64 | } 65 | } 66 | Some(name) => { 67 | tun_builder = tun_builder.name(name); 68 | } 69 | } 70 | 71 | #[cfg(target_os = "windows")] 72 | { 73 | tun_builder = tun_builder.metric(0).ring_capacity(4 * 1024 * 1024); 74 | } 75 | 76 | #[cfg(target_os = "linux")] 77 | { 78 | let device_name = config 79 | .device_name 80 | .clone() 81 | .unwrap_or(DEFAULT_TUN_NAME.to_string()); 82 | if &device_name == DEFAULT_TUN_NAME { 83 | delete_device(DEFAULT_TUN_NAME); 84 | } 85 | } 86 | 87 | let device = tun_builder.mtu(config.mtu as u16).build_sync()?; 88 | Ok(Arc::new(device)) 89 | } 90 | 91 | #[cfg(target_os = "linux")] 92 | fn delete_device(name: &str) { 93 | // 删除默认网卡,此操作有风险,后续可能去除 94 | use std::process::Command; 95 | let cmd = format!("ip link delete {}", name); 96 | let delete_tun = Command::new("sh") 97 | .arg("-c") 98 | .arg(&cmd) 99 | .output() 100 | .expect("sh exec error!"); 101 | if !delete_tun.status.success() { 102 | log::warn!("删除网卡失败:{:?}", delete_tun); 103 | } 104 | } 105 | 106 | #[cfg(target_os = "windows")] 107 | pub fn add_route(index: u32, dest: Ipv4Addr, netmask: Ipv4Addr) -> io::Result<()> { 108 | let cmd = format!( 109 | "route add {:?} mask {:?} {:?} metric {} if {}", 110 | dest, 111 | netmask, 112 | Ipv4Addr::UNSPECIFIED, 113 | 1, 114 | index 115 | ); 116 | exe_cmd(&cmd) 117 | } 118 | #[cfg(target_os = "windows")] 119 | pub fn exe_cmd(cmd: &str) -> io::Result<()> { 120 | use std::os::windows::process::CommandExt; 121 | 122 | println!("exe cmd: {}", cmd); 123 | let out = std::process::Command::new("cmd") 124 | .creation_flags(windows_sys::Win32::System::Threading::CREATE_NO_WINDOW) 125 | .arg("/C") 126 | .arg(&cmd) 127 | .output()?; 128 | if !out.status.success() { 129 | return Err(io::Error::new( 130 | io::ErrorKind::Other, 131 | format!("cmd={},out={:?}", cmd, String::from_utf8(out.stderr)), 132 | )); 133 | } 134 | Ok(()) 135 | } 136 | 137 | #[cfg(target_os = "macos")] 138 | pub fn add_route(name: &str, address: Ipv4Addr, netmask: Ipv4Addr) -> io::Result<()> { 139 | let cmd = format!( 140 | "route -n add {} -netmask {} -interface {}", 141 | address, netmask, name 142 | ); 143 | exe_cmd(&cmd)?; 144 | Ok(()) 145 | } 146 | #[cfg(target_os = "linux")] 147 | pub fn add_route(name: &str, address: Ipv4Addr, netmask: Ipv4Addr) -> io::Result<()> { 148 | let cmd = if netmask.is_broadcast() { 149 | format!("route add -host {:?} {}", address, name) 150 | } else { 151 | format!( 152 | "route add -net {}/{} {}", 153 | address, 154 | u32::from(netmask).count_ones(), 155 | name 156 | ) 157 | }; 158 | exe_cmd(&cmd)?; 159 | Ok(()) 160 | } 161 | #[cfg(any(target_os = "macos", target_os = "linux"))] 162 | pub fn exe_cmd(cmd: &str) -> io::Result { 163 | use std::process::Command; 164 | println!("exe cmd: {}", cmd); 165 | let out = Command::new("sh") 166 | .arg("-c") 167 | .arg(cmd) 168 | .output() 169 | .expect("sh exec error!"); 170 | if !out.status.success() { 171 | return Err(io::Error::new( 172 | io::ErrorKind::Other, 173 | format!("cmd={},out={:?}", cmd, out), 174 | )); 175 | } 176 | Ok(out) 177 | } 178 | -------------------------------------------------------------------------------- /vnt/src/tun_tap_device/mod.rs: -------------------------------------------------------------------------------- 1 | #[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))] 2 | #[cfg(feature = "integrated_tun")] 3 | pub use create_device::create_device; 4 | 5 | #[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))] 6 | #[cfg(feature = "integrated_tun")] 7 | mod create_device; 8 | #[cfg(feature = "integrated_tun")] 9 | pub mod tun_create_helper; 10 | 11 | pub mod vnt_device; 12 | -------------------------------------------------------------------------------- /vnt/src/tun_tap_device/tun_create_helper.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashMap; 2 | use std::io; 3 | use std::net::Ipv4Addr; 4 | use std::sync::Arc; 5 | 6 | use crate::channel::context::ChannelContext; 7 | use crate::cipher::Cipher; 8 | use crate::compression::Compressor; 9 | use crate::external_route::ExternalRoute; 10 | use crate::handle::tun_tap::DeviceStop; 11 | use crate::handle::{CurrentDeviceInfo, PeerDeviceInfo}; 12 | #[cfg(feature = "ip_proxy")] 13 | use crate::ip_proxy::IpProxyMap; 14 | use crate::tun_tap_device::vnt_device::DeviceWrite; 15 | use crate::util::StopManager; 16 | use crossbeam_utils::atomic::AtomicCell; 17 | use parking_lot::Mutex; 18 | use tun_rs::SyncDevice; 19 | 20 | #[repr(transparent)] 21 | #[derive(Clone, Default)] 22 | pub struct DeviceAdapter { 23 | tun: Arc>>>, 24 | } 25 | 26 | impl DeviceAdapter { 27 | pub fn insert(&self, device: Arc) { 28 | let r = self.tun.lock().replace(device); 29 | assert!(r.is_none()); 30 | } 31 | /// 要保证先remove 再insert 32 | pub fn remove(&self) { 33 | drop(self.tun.lock().take()); 34 | } 35 | } 36 | 37 | impl DeviceWrite for DeviceAdapter { 38 | #[inline] 39 | fn write(&self, buf: &[u8]) -> io::Result { 40 | if let Some(tun) = self.tun.lock().as_ref() { 41 | tun.send(buf) 42 | } else { 43 | Err(io::Error::new(io::ErrorKind::NotFound, "not tun device")) 44 | } 45 | } 46 | 47 | fn into_device_adapter(self) -> DeviceAdapter { 48 | self 49 | } 50 | } 51 | 52 | #[derive(Clone)] 53 | pub struct TunDeviceHelper { 54 | inner: Arc>, 55 | device_adapter: DeviceAdapter, 56 | device_stop: Arc>>, 57 | } 58 | 59 | #[derive(Clone)] 60 | struct TunDeviceHelperInner { 61 | stop_manager: StopManager, 62 | context: ChannelContext, 63 | current_device: Arc>, 64 | ip_route: ExternalRoute, 65 | #[cfg(feature = "ip_proxy")] 66 | ip_proxy_map: Option, 67 | client_cipher: Cipher, 68 | server_cipher: Cipher, 69 | device_map: Arc)>>, 70 | compressor: Compressor, 71 | } 72 | 73 | impl TunDeviceHelper { 74 | pub fn new( 75 | stop_manager: StopManager, 76 | context: ChannelContext, 77 | current_device: Arc>, 78 | ip_route: ExternalRoute, 79 | #[cfg(feature = "ip_proxy")] ip_proxy_map: Option, 80 | client_cipher: Cipher, 81 | server_cipher: Cipher, 82 | device_map: Arc)>>, 83 | compressor: Compressor, 84 | device_adapter: DeviceAdapter, 85 | ) -> Self { 86 | let inner = TunDeviceHelperInner { 87 | stop_manager, 88 | context, 89 | current_device, 90 | ip_route, 91 | #[cfg(feature = "ip_proxy")] 92 | ip_proxy_map, 93 | client_cipher, 94 | server_cipher, 95 | device_map, 96 | compressor, 97 | }; 98 | Self { 99 | inner: Arc::new(Mutex::new(inner)), 100 | device_adapter, 101 | device_stop: Default::default(), 102 | } 103 | } 104 | pub fn stop(&self) { 105 | //先停止旧的,再启动新的,改变旧网卡的IP太麻烦 106 | if let Some(device_stop) = self.device_stop.lock().take() { 107 | self.device_adapter.remove(); 108 | loop { 109 | device_stop.stop(); 110 | std::thread::sleep(std::time::Duration::from_millis(300)); 111 | //确保停止了 112 | if device_stop.is_stopped() { 113 | break; 114 | } 115 | } 116 | } 117 | } 118 | /// 要保证先stop 再start 119 | pub fn start(&self, device: Arc, allow_wire_guard: bool) -> io::Result<()> { 120 | self.device_adapter.insert(device.clone()); 121 | let device_stop = DeviceStop::default(); 122 | let s = self.device_stop.lock().replace(device_stop.clone()); 123 | assert!(s.is_none()); 124 | let inner = self.inner.lock().clone(); 125 | crate::handle::tun_tap::tun_handler::start( 126 | inner.stop_manager, 127 | inner.context, 128 | device, 129 | inner.current_device, 130 | inner.ip_route, 131 | #[cfg(feature = "ip_proxy")] 132 | inner.ip_proxy_map, 133 | inner.client_cipher, 134 | inner.server_cipher, 135 | inner.device_map, 136 | inner.compressor, 137 | device_stop, 138 | allow_wire_guard, 139 | ) 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /vnt/src/tun_tap_device/vnt_device.rs: -------------------------------------------------------------------------------- 1 | use std::io; 2 | 3 | pub trait DeviceWrite: Clone + Send + Sync + 'static { 4 | fn write(&self, buf: &[u8]) -> io::Result; 5 | #[cfg(feature = "integrated_tun")] 6 | fn into_device_adapter(self) -> crate::tun_tap_device::tun_create_helper::DeviceAdapter; 7 | } 8 | -------------------------------------------------------------------------------- /vnt/src/util/counter/adder.rs: -------------------------------------------------------------------------------- 1 | use std::sync::Arc; 2 | 3 | use crossbeam_utils::atomic::AtomicCell; 4 | 5 | #[derive(Clone, Default)] 6 | pub struct U64Adder { 7 | count: Arc>, 8 | } 9 | 10 | impl U64Adder { 11 | pub fn add(&self, num: u64) { 12 | self.count.fetch_add(num); 13 | } 14 | pub fn get(&self) -> u64 { 15 | self.count.load() 16 | } 17 | pub fn watch(&self) -> WatchU64Adder { 18 | WatchU64Adder { 19 | count: self.count.clone(), 20 | } 21 | } 22 | } 23 | 24 | #[derive(Clone)] 25 | pub struct WatchU64Adder { 26 | count: Arc>, 27 | } 28 | 29 | impl WatchU64Adder { 30 | pub fn get(&self) -> u64 { 31 | self.count.load() 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /vnt/src/util/counter/mod.rs: -------------------------------------------------------------------------------- 1 | mod adder; 2 | pub use adder::*; 3 | -------------------------------------------------------------------------------- /vnt/src/util/limit/mod.rs: -------------------------------------------------------------------------------- 1 | mod rate_limiter; 2 | pub use rate_limiter::*; 3 | 4 | mod traffic_meter; 5 | pub use traffic_meter::*; 6 | -------------------------------------------------------------------------------- /vnt/src/util/limit/rate_limiter.rs: -------------------------------------------------------------------------------- 1 | use parking_lot::Mutex; 2 | use std::sync::Arc; 3 | use std::time::Instant; 4 | 5 | #[derive(Clone)] 6 | pub struct ConcurrentRateLimiter { 7 | inner: Arc>, 8 | } 9 | 10 | impl ConcurrentRateLimiter { 11 | pub fn new(capacity: usize, refill_rate: usize) -> Self { 12 | let inner = RateLimiter::new(capacity, refill_rate); 13 | Self { 14 | inner: Arc::new(Mutex::new(inner)), 15 | } 16 | } 17 | pub fn try_acquire(&self) -> bool { 18 | self.inner.lock().try_acquire() 19 | } 20 | } 21 | 22 | pub struct RateLimiter { 23 | capacity: usize, 24 | tokens: usize, 25 | refill_rate: usize, 26 | last_refill: Instant, 27 | } 28 | 29 | impl RateLimiter { 30 | // 初始化限流器 31 | pub fn new(capacity: usize, refill_rate: usize) -> Self { 32 | Self { 33 | capacity, 34 | tokens: capacity, 35 | refill_rate, 36 | last_refill: Instant::now(), 37 | } 38 | } 39 | 40 | // 尝试获取一个令牌 41 | pub fn try_acquire(&mut self) -> bool { 42 | self.refill(); 43 | if self.tokens > 0 { 44 | self.tokens -= 1; 45 | true 46 | } else { 47 | false 48 | } 49 | } 50 | 51 | // 补充令牌 52 | fn refill(&mut self) { 53 | let now = Instant::now(); 54 | let elapsed = now.duration_since(self.last_refill).as_secs() as usize; 55 | let new_tokens = elapsed * self.refill_rate; 56 | 57 | if new_tokens > 0 { 58 | self.tokens = std::cmp::min(self.capacity, self.tokens + new_tokens); 59 | self.last_refill = now; 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /vnt/src/util/limit/traffic_meter.rs: -------------------------------------------------------------------------------- 1 | use parking_lot::Mutex; 2 | use std::collections::{HashMap, VecDeque}; 3 | use std::net::Ipv4Addr; 4 | use std::sync::Arc; 5 | use std::time::{Duration, Instant}; 6 | 7 | #[derive(Clone)] 8 | pub struct TrafficMeterMultiAddress { 9 | history_capacity: usize, 10 | inner: Arc)>>, 11 | } 12 | 13 | impl Default for TrafficMeterMultiAddress { 14 | fn default() -> Self { 15 | TrafficMeterMultiAddress::new(100) 16 | } 17 | } 18 | 19 | impl TrafficMeterMultiAddress { 20 | pub fn new(history_capacity: usize) -> Self { 21 | let inner = Arc::new(Mutex::new((0, HashMap::new()))); 22 | Self { 23 | inner, 24 | history_capacity, 25 | } 26 | } 27 | pub fn add_traffic(&self, ip: Ipv4Addr, amount: usize) { 28 | let mut guard = self.inner.lock(); 29 | guard.0 += amount as u64; 30 | guard 31 | .1 32 | .entry(ip) 33 | .or_insert(TrafficMeter::new(self.history_capacity)) 34 | .add_traffic(amount) 35 | } 36 | pub fn total(&self) -> u64 { 37 | self.inner.lock().0 38 | } 39 | pub fn get_all(&self) -> (u64, HashMap) { 40 | let guard = self.inner.lock(); 41 | ( 42 | guard.0, 43 | guard.1.iter().map(|(ip, t)| (*ip, t.total())).collect(), 44 | ) 45 | } 46 | pub fn get_all_history(&self) -> (u64, HashMap)>) { 47 | let guard = self.inner.lock(); 48 | ( 49 | guard.0, 50 | guard 51 | .1 52 | .iter() 53 | .map(|(ip, t)| (*ip, (t.total(), t.get_history()))) 54 | .collect(), 55 | ) 56 | } 57 | pub fn get_history(&self, ip: &Ipv4Addr) -> Option<(u64, Vec)> { 58 | self.inner 59 | .lock() 60 | .1 61 | .get(ip) 62 | .map(|t| (t.total(), t.get_history())) 63 | } 64 | } 65 | 66 | #[derive(Clone)] 67 | pub struct ConcurrentTrafficMeter { 68 | inner: Arc>, 69 | } 70 | 71 | impl ConcurrentTrafficMeter { 72 | pub fn new(history_capacity: usize) -> Self { 73 | let inner = Arc::new(Mutex::new(TrafficMeter::new(history_capacity))); 74 | Self { inner } 75 | } 76 | pub fn add_traffic(&self, amount: usize) { 77 | self.inner.lock().add_traffic(amount) 78 | } 79 | pub fn get_history(&self) -> Vec { 80 | self.inner.lock().get_history() 81 | } 82 | } 83 | 84 | pub struct TrafficMeter { 85 | start_time: Instant, 86 | total: u64, 87 | count: usize, 88 | history_capacity: usize, 89 | history: VecDeque, 90 | } 91 | 92 | impl TrafficMeter { 93 | // 初始化一个新的 TrafficMeter 94 | pub fn new(history_capacity: usize) -> Self { 95 | Self { 96 | start_time: Instant::now(), 97 | total: 0, 98 | count: 0, 99 | history: VecDeque::with_capacity(history_capacity), 100 | history_capacity, 101 | } 102 | } 103 | 104 | // 增加流量计数 105 | pub fn add_traffic(&mut self, amount: usize) { 106 | self.total += amount as u64; 107 | self.count += amount; 108 | self.check_time(); 109 | } 110 | 111 | // 检查时间是否超过一秒,如果是,记录流量并重置计数器和时间 112 | fn check_time(&mut self) { 113 | if self.start_time.elapsed() >= Duration::new(1, 0) { 114 | // 将当前计数添加到历史记录 115 | if self.history.len() >= self.history_capacity { 116 | self.history.pop_front(); // 保持历史记录不超过capacity 117 | } 118 | self.history.push_back(self.count); 119 | 120 | // 重置计数器和时间 121 | self.count = 0; 122 | self.start_time = Instant::now(); 123 | } 124 | } 125 | pub fn total(&self) -> u64 { 126 | self.total 127 | } 128 | // 获取流量记录 129 | pub fn get_history(&self) -> Vec { 130 | self.history.iter().cloned().collect() 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /vnt/src/util/mod.rs: -------------------------------------------------------------------------------- 1 | mod notify; 2 | mod scheduler; 3 | pub use notify::{StopManager, Worker}; 4 | pub use scheduler::Scheduler; 5 | 6 | // mod counter; 7 | // pub use counter::*; 8 | 9 | mod dns_query; 10 | pub use dns_query::*; 11 | 12 | #[cfg(feature = "upnp")] 13 | mod upnp; 14 | #[cfg(feature = "upnp")] 15 | pub use upnp::*; 16 | 17 | pub mod limit; 18 | -------------------------------------------------------------------------------- /vnt/src/util/notify.rs: -------------------------------------------------------------------------------- 1 | use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering}; 2 | use std::sync::Arc; 3 | use std::thread; 4 | use std::thread::Thread; 5 | use std::time::Duration; 6 | 7 | use anyhow::anyhow; 8 | use parking_lot::Mutex; 9 | 10 | #[derive(Clone)] 11 | pub struct StopManager { 12 | inner: Arc, 13 | } 14 | 15 | impl StopManager { 16 | pub fn new(f: F) -> Self 17 | where 18 | F: FnOnce() + Send + 'static, 19 | { 20 | Self { 21 | inner: Arc::new(StopManagerInner::new(f)), 22 | } 23 | } 24 | pub fn add_listener(&self, name: String, f: F) -> anyhow::Result 25 | where 26 | F: FnOnce() + Send + 'static, 27 | { 28 | self.inner.add_listener(name, f) 29 | } 30 | pub fn stop(&self) { 31 | self.inner.stop(); 32 | } 33 | pub fn wait(&self) { 34 | self.inner.wait(); 35 | } 36 | pub fn wait_timeout(&self, dur: Duration) -> bool { 37 | self.inner.wait_timeout(dur) 38 | } 39 | pub fn is_stopped(&self) -> bool { 40 | self.inner.is_stopped() 41 | } 42 | } 43 | 44 | struct StopManagerInner { 45 | listeners: Mutex<(bool, Vec<(String, Box)>)>, 46 | park_threads: Mutex>, 47 | worker_num: AtomicUsize, 48 | state: AtomicBool, 49 | stop_call: Mutex>>, 50 | } 51 | 52 | impl StopManagerInner { 53 | fn new(f: F) -> Self 54 | where 55 | F: FnOnce() + Send + 'static, 56 | { 57 | Self { 58 | listeners: Mutex::new((false, Vec::with_capacity(32))), 59 | park_threads: Mutex::new(Vec::with_capacity(4)), 60 | worker_num: AtomicUsize::new(0), 61 | state: AtomicBool::new(false), 62 | stop_call: Mutex::new(Some(Box::new(f))), 63 | } 64 | } 65 | fn add_listener(self: &Arc, name: String, f: F) -> anyhow::Result 66 | where 67 | F: FnOnce() + Send + 'static, 68 | { 69 | if name.is_empty() { 70 | return Err(anyhow!("name cannot be empty")); 71 | } 72 | let mut guard = self.listeners.lock(); 73 | if guard.0 { 74 | return Err(anyhow!("stopped")); 75 | } 76 | for (n, _) in &guard.1 { 77 | if &name == n { 78 | return Err(anyhow!("stop add_listener {:?} name already exists", name)); 79 | } 80 | } 81 | guard.1.push((name.clone(), Box::new(f))); 82 | Ok(Worker::new(name, self.clone())) 83 | } 84 | fn stop(&self) { 85 | self.state.store(true, Ordering::Release); 86 | let mut guard = self.listeners.lock(); 87 | guard.0 = true; 88 | for (_name, listener) in guard.1.drain(..) { 89 | listener(); 90 | } 91 | } 92 | pub fn is_stopped(&self) -> bool { 93 | self.worker_num.load(Ordering::Acquire) == 0 94 | } 95 | fn wait(&self) { 96 | { 97 | let mut guard = self.park_threads.lock(); 98 | guard.push(thread::current()); 99 | drop(guard); 100 | } 101 | loop { 102 | if self.worker_num.load(Ordering::Acquire) == 0 { 103 | return; 104 | } 105 | thread::park() 106 | } 107 | } 108 | fn wait_timeout(&self, dur: Duration) -> bool { 109 | { 110 | let mut guard = self.park_threads.lock(); 111 | guard.push(thread::current()); 112 | drop(guard); 113 | } 114 | if self.worker_num.load(Ordering::Acquire) == 0 { 115 | return true; 116 | } 117 | thread::park_timeout(dur); 118 | self.worker_num.load(Ordering::Acquire) == 0 119 | } 120 | fn stop_call(&self) { 121 | self.stop(); 122 | if let Some(call) = self.stop_call.lock().take() { 123 | call(); 124 | } 125 | } 126 | } 127 | 128 | pub struct Worker { 129 | name: String, 130 | inner: Arc, 131 | } 132 | 133 | impl Worker { 134 | fn new(name: String, inner: Arc) -> Self { 135 | let _ = inner.worker_num.fetch_add(1, Ordering::AcqRel); 136 | Self { name, inner } 137 | } 138 | fn release0(&self) { 139 | let inner = &self.inner; 140 | let worker_name = &self.name; 141 | { 142 | let mut mutex_guard = inner.listeners.lock(); 143 | if let Some(pos) = mutex_guard 144 | .1 145 | .iter() 146 | .position(|(name, _)| name == worker_name) 147 | { 148 | let (_, listener) = mutex_guard.1.remove(pos); 149 | listener(); 150 | } 151 | } 152 | 153 | let count = inner.worker_num.fetch_sub(1, Ordering::AcqRel); 154 | if count == 1 { 155 | for x in inner.park_threads.lock().drain(..) { 156 | x.unpark(); 157 | } 158 | self.inner.stop_call(); 159 | } 160 | } 161 | pub fn stop_all(self) { 162 | self.inner.stop() 163 | } 164 | pub fn stop_self(self) { 165 | drop(self) 166 | } 167 | } 168 | 169 | impl Drop for Worker { 170 | fn drop(&mut self) { 171 | self.release0(); 172 | log::info!("stop {}", self.name); 173 | } 174 | } 175 | -------------------------------------------------------------------------------- /vnt/src/util/upnp.rs: -------------------------------------------------------------------------------- 1 | use igd::{search_gateway, PortMappingProtocol}; 2 | use std::net::{Ipv4Addr, SocketAddrV4}; 3 | use std::ops::Deref; 4 | use std::sync::Arc; 5 | 6 | use parking_lot::Mutex; 7 | 8 | #[derive(Clone, Default)] 9 | pub struct UPnP { 10 | inner: Arc, 11 | } 12 | 13 | impl Deref for UPnP { 14 | type Target = UpnpInner; 15 | 16 | fn deref(&self) -> &Self::Target { 17 | &self.inner 18 | } 19 | } 20 | 21 | #[derive(Default)] 22 | pub struct UpnpInner { 23 | list: Mutex>, 24 | } 25 | 26 | impl UpnpInner { 27 | pub fn add_tcp_port(&self, port: u16) { 28 | self.list.lock().push((PortMappingProtocol::TCP, port)); 29 | } 30 | pub fn add_udp_port(&self, port: u16) { 31 | self.list.lock().push((PortMappingProtocol::UDP, port)); 32 | } 33 | pub fn reset(&self, local_ip: Ipv4Addr) { 34 | let gateway = match search_gateway(Default::default()) { 35 | Ok(gateway) => gateway, 36 | Err(e) => { 37 | log::warn!("search_gateway {:?}", e); 38 | return; 39 | } 40 | }; 41 | let guard = self.list.lock(); 42 | 43 | // 不支持upnp的情况会阻塞30秒,之后再改这个库 44 | for (protocol, port) in guard.iter() { 45 | let local_addr = SocketAddrV4::new(local_ip, *port); 46 | log::info!("add upnp protocol={} {}", protocol, local_addr); 47 | if let Err(e) = gateway.add_port(*protocol, *port, local_addr, 700, "upnp") { 48 | log::warn!( 49 | "add upnp failed protocol={},port={} err:{:?}", 50 | protocol, 51 | port, 52 | e 53 | ); 54 | } 55 | } 56 | } 57 | } 58 | 59 | impl Drop for UpnpInner { 60 | fn drop(&mut self) { 61 | // let gateway = match search_gateway(Default::default()) { 62 | // Ok(gateway) => gateway, 63 | // Err(e) => { 64 | // log::warn!("search_gateway {:?}", e); 65 | // return; 66 | // } 67 | // }; 68 | // 69 | // let guard = self.list.lock(); 70 | // for (protocol, port) in guard.iter() { 71 | // if let Err(e) = gateway.remove_port(*protocol, *port) { 72 | // log::warn!( 73 | // "remove upnp failed protocol={},port={} err:{:?}", 74 | // protocol, 75 | // port, 76 | // e 77 | // ); 78 | // } 79 | // } 80 | } 81 | } 82 | --------------------------------------------------------------------------------