From 755339189dc8f4fc342ea7cfc3744b3a3123d6b9 Mon Sep 17 00:00:00 2001 From: lbl8603 <49143209+lbl8603@users.noreply.github.com> Date: Sat, 15 Jun 2024 20:54:35 +0800 Subject: [PATCH] =?UTF-8?q?=E5=8E=BB=E9=99=A4=E9=87=8D=E5=A4=8D=E4=BB=A3?= =?UTF-8?q?=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- vnt-cli/Cargo.toml | 55 ++-- vnt-cli/README.md | 10 +- vnt-cli/build.rs | 16 - vnt-cli/src/callback.rs | 53 ---- vnt-cli/src/command/client.rs | 81 ----- vnt-cli/src/command/entity.rs | 46 --- vnt-cli/src/command/mod.rs | 211 ------------- vnt-cli/src/command/server.rs | 78 ----- vnt-cli/src/config/file_config.rs | 168 ---------- vnt-cli/src/config/mod.rs | 31 -- vnt-cli/src/console_out/mod.rs | 239 --------------- vnt-cli/src/console_out/table.rs | 23 -- vnt-cli/src/main.rs | 495 +----------------------------- 13 files changed, 43 insertions(+), 1463 deletions(-) delete mode 100644 vnt-cli/build.rs delete mode 100644 vnt-cli/src/callback.rs delete mode 100644 vnt-cli/src/command/client.rs delete mode 100644 vnt-cli/src/command/entity.rs delete mode 100644 vnt-cli/src/command/mod.rs delete mode 100644 vnt-cli/src/command/server.rs delete mode 100644 vnt-cli/src/config/file_config.rs delete mode 100644 vnt-cli/src/config/mod.rs delete mode 100644 vnt-cli/src/console_out/mod.rs delete mode 100644 vnt-cli/src/console_out/table.rs diff --git a/vnt-cli/Cargo.toml b/vnt-cli/Cargo.toml index 96dcfdf..7b099ca 100644 --- a/vnt-cli/Cargo.toml +++ b/vnt-cli/Cargo.toml @@ -6,21 +6,11 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -vnt = { path = "../vnt", package = "vnt", default-features = false } -common = { path = "../common" } -getopts = "0.2.21" -console = "0.15.2" -os_info = "3.7.0" -serde = "1.0" -serde_yaml = "0.9.32" +vnt = { path = "../vnt", package = "vnt", default-features = false, features = ["integrated_tun"] } +common = { path = "../common", default-features = false, features = ["integrated_tun"] } log = "0.4.17" -log4rs = { version = "1.2.0", optional = true } anyhow = "1.0.82" -[dependencies.uuid] -version = "1.4.1" -features = [ - "v4", # Lets you generate random UUIDs -] + [target.'cfg(any(target_os = "linux",target_os = "macos"))'.dependencies] sudo = "0.6.0" @@ -30,24 +20,27 @@ signal-hook = "0.3.17" winapi = { version = "0.3.9", features = ["handleapi", "processthreadsapi", "winnt", "securitybaseapi", "impl-default"] } [features] -default = ["vnt/integrated_tun","server_encrypt", "aes_gcm", "aes_cbc", "aes_ecb", "sm4_cbc", "chacha20_poly1305", "ip_proxy", "port_mapping", "log", "command", "file_config", "lz4"] -openssl = ["vnt/openssl"] -openssl-vendored = ["vnt/openssl-vendored"] -ring-cipher = ["vnt/ring-cipher"] -aes_cbc = ["vnt/aes_cbc"] -aes_ecb = ["vnt/aes_ecb"] -sm4_cbc = ["vnt/sm4_cbc"] -aes_gcm = ["vnt/aes_gcm"] -chacha20_poly1305 = ["vnt/chacha20_poly1305"] -server_encrypt = ["vnt/server_encrypt"] -ip_proxy = ["vnt/ip_proxy"] -port_mapping = ["vnt/port_mapping"] -lz4 = ["vnt/lz4_compress"] -zstd = ["vnt/zstd_compress"] -log = ["log4rs"] -command = [] -file_config = [] +default = ["default-feature"] +default-feature = ["server_encrypt", "aes_gcm", "aes_cbc", "aes_ecb", "sm4_cbc", "chacha20_poly1305", "ip_proxy", "port_mapping", "log", "command", "file_config", "lz4"] + +openssl = ["vnt/openssl", "common/openssl"] +openssl-vendored = ["vnt/openssl-vendored", "common/openssl-vendored"] +ring-cipher = ["vnt/ring-cipher", "common/ring-cipher"] +aes_cbc = ["vnt/aes_cbc", "common/aes_cbc"] +aes_ecb = ["vnt/aes_ecb", "common/aes_ecb"] +sm4_cbc = ["vnt/sm4_cbc", "common/sm4_cbc"] +aes_gcm = ["vnt/aes_gcm", "common/aes_gcm"] +chacha20_poly1305 = ["vnt/chacha20_poly1305", "common/chacha20_poly1305"] +server_encrypt = ["vnt/server_encrypt", "common/server_encrypt"] +port_mapping = ["vnt/port_mapping", "common/port_mapping"] +lz4 = ["vnt/lz4_compress", "common/lz4"] +zstd = ["vnt/zstd_compress", "common/zstd"] +ip_proxy = ["vnt/ip_proxy", "common/ip_proxy"] +log = ["common/log"] +command = ["common/command"] +file_config = ["common/file_config"] + + [build-dependencies] -embed-manifest = "1.4.0" rand = "0.8.5" chrono = "0.4.23" \ No newline at end of file diff --git a/vnt-cli/README.md b/vnt-cli/README.md index dca3c22..92518ae 100644 --- a/vnt-cli/README.md +++ b/vnt-cli/README.md @@ -143,9 +143,9 @@ aes_gcm/aes_cbc/aes_ecb/sm4_cbc/chacha20_poly1305/chacha20/xor,默认使用aes 当地址解析失败时,会依次尝试后面的dns,直到有A记录、AAAA记录(或TXT记录)的解析结果 -### --mapping `10.26.0.10:80>` +### --mapping `` -端口映射,可以设置多个映射地址,例如 '--mapping udp:0.0.0.0:80->10.26.0.10:80 --mapping tcp:0.0.0.0:80->10.26.0.11:81' +端口映射,可以设置多个映射地址,例如 '--mapping udp:0.0.0.0:80-10.26.0.10:80 --mapping tcp:0.0.0.0:80-10.26.0.11:81' 表示将本地udp 80端口的数据转发到10.26.0.10:80,将本地tcp 80端口的数据转发到10.26.0.11:81,转发的目的地址可以使用域名+端口 ### --compressor `` @@ -198,9 +198,9 @@ dns: - 223.5.5.5 # 首选dns - 8.8.8.8 # 备选dns mapping: - - udp:0.0.0.0:80->10.26.0.10:80 # 映射udp数据 - - tcp:0.0.0.0:80->10.26.0.10:81 # 映射tcp数据 - - tcp:0.0.0.0:82->localhost:83 # 映射tcp数据 + - udp:0.0.0.0:80-10.26.0.10:80 # 映射udp数据 + - tcp:0.0.0.0:80-10.26.0.10:81 # 映射tcp数据 + - tcp:0.0.0.0:82-localhost:83 # 映射tcp数据 ``` 或者需要哪个配置就加哪个,当然token是必须的 diff --git a/vnt-cli/build.rs b/vnt-cli/build.rs deleted file mode 100644 index 8970ed9..0000000 --- a/vnt-cli/build.rs +++ /dev/null @@ -1,16 +0,0 @@ -use rand::Rng; -use std::fs::File; -use std::io::Write; - -fn main() { - let now_time = chrono::Local::now(); - let serial_number = format!( - "{}-{}", - &now_time.format("%y%m%d%H%M").to_string(), - rand::thread_rng().gen_range(100..1000) - ); - let generated_code = format!(r#"pub const SERIAL_NUMBER: &str = "{}";"#, serial_number); - let dest_path = "src/generated_serial_number.rs"; - let mut file = File::create(&dest_path).unwrap(); - file.write_all(generated_code.as_bytes()).unwrap(); -} diff --git a/vnt-cli/src/callback.rs b/vnt-cli/src/callback.rs deleted file mode 100644 index 4aed239..0000000 --- a/vnt-cli/src/callback.rs +++ /dev/null @@ -1,53 +0,0 @@ -use std::process; - -use console::style; - -use vnt::{ - ConnectInfo, DeviceInfo, ErrorInfo, ErrorType, HandshakeInfo, RegisterInfo, VntCallback, -}; - -#[derive(Clone)] -pub struct VntHandler {} - -impl VntCallback for VntHandler { - fn success(&self) { - println!(" {} ", style("====== Connect Successfully ======").green()) - } - fn create_tun(&self, info: DeviceInfo) { - println!("create_tun {}", info) - } - - fn connect(&self, info: ConnectInfo) { - println!("connect {}", info) - } - - fn handshake(&self, info: HandshakeInfo) -> bool { - println!("handshake {}", info); - true - } - - fn register(&self, info: RegisterInfo) -> bool { - println!("register {}", style(info).green()); - true - } - - fn error(&self, info: ErrorInfo) { - log::error!("error {:?}", info); - println!("{}", style(format!("error {}", info)).red()); - match info.code { - ErrorType::TokenError - | ErrorType::AddressExhausted - | ErrorType::IpAlreadyExists - | ErrorType::InvalidIp - | ErrorType::LocalIpExists => { - self.stop(); - } - _ => {} - } - } - - fn stop(&self) { - println!("stopped"); - process::exit(0) - } -} diff --git a/vnt-cli/src/command/client.rs b/vnt-cli/src/command/client.rs deleted file mode 100644 index d524653..0000000 --- a/vnt-cli/src/command/client.rs +++ /dev/null @@ -1,81 +0,0 @@ -use serde::Deserialize; -use std::io; -use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4, UdpSocket}; -use std::str::FromStr; -use std::time::Duration; - -use crate::command::entity::{DeviceItem, Info, RouteItem}; - -pub struct CommandClient { - buf: Vec, - udp: UdpSocket, -} - -impl CommandClient { - pub fn new() -> io::Result { - let port = read_command_port().unwrap_or_else(|e| { - log::warn!("read_command_port:{:?}", e); - 39271 - }); - let udp = UdpSocket::bind("127.0.0.1:0")?; - udp.set_read_timeout(Some(Duration::from_secs(5)))?; - udp.connect(SocketAddr::V4(SocketAddrV4::new( - Ipv4Addr::new(127, 0, 0, 1), - port, - )))?; - Ok(Self { - udp, - buf: vec![0; 65536 * 8], - }) - } -} -fn read_command_port() -> io::Result { - let path_buf = crate::app_home()?.join("command-port"); - let port = std::fs::read_to_string(path_buf)?; - match u16::from_str(&port) { - Ok(port) => Ok(port), - Err(_) => { - return Err(io::Error::new( - io::ErrorKind::Other, - "'command-port' file error", - )); - } - } -} - -impl CommandClient { - pub fn list(&mut self) -> io::Result> { - self.send_cmd(b"list") - } - pub fn route(&mut self) -> io::Result> { - self.send_cmd(b"route") - } - pub fn info(&mut self) -> io::Result { - self.send_cmd(b"info") - } - fn send_cmd<'a, V: Deserialize<'a>>(&'a mut self, cmd: &[u8]) -> io::Result { - self.udp.send(cmd)?; - let len = self.udp.recv(&mut self.buf)?; - match serde_yaml::from_slice::(&self.buf[..len]) { - Ok(val) => Ok(val), - Err(e) => { - log::error!( - "send_cmd {:?} {:?},{:?}", - std::str::from_utf8(cmd), - std::str::from_utf8(&self.buf[..len]), - e - ); - Err(io::Error::new( - io::ErrorKind::Other, - format!("data error {:?} buf_len={}", e, len), - )) - } - } - } - pub fn stop(&self) -> io::Result { - self.udp.send(b"stop")?; - let mut buf = [0; 10240]; - let len = self.udp.recv(&mut buf)?; - Ok(String::from_utf8(buf[..len].to_vec()).unwrap()) - } -} diff --git a/vnt-cli/src/command/entity.rs b/vnt-cli/src/command/entity.rs deleted file mode 100644 index 5c06d18..0000000 --- a/vnt-cli/src/command/entity.rs +++ /dev/null @@ -1,46 +0,0 @@ -use serde::{Deserialize, Serialize}; -use std::net::{Ipv4Addr, SocketAddr}; -#[derive(Serialize, Deserialize, Debug)] -pub struct Info { - pub name: String, - pub virtual_ip: String, - pub virtual_gateway: String, - pub virtual_netmask: String, - pub connect_status: String, - pub relay_server: String, - pub nat_type: String, - pub public_ips: String, - pub local_addr: String, - pub ipv6_addr: String, - pub up: u64, - pub down: u64, - pub port_mapping_list: Vec<(bool, SocketAddr, String)>, - pub in_ips: Vec<(u32, u32, Ipv4Addr)>, - pub out_ips: Vec<(u32, u32)>, -} - -#[derive(Serialize, Deserialize, Debug)] -pub struct RouteItem { - pub destination: String, - pub next_hop: String, - pub metric: String, - pub rt: String, - pub interface: String, -} - -#[derive(Serialize, Deserialize, Debug)] -pub struct DeviceItem { - pub name: String, - pub virtual_ip: String, - pub nat_type: String, - pub public_ips: String, - pub local_ip: String, - pub ipv6: String, - pub nat_traversal_type: String, - pub rt: String, - pub status: String, - pub client_secret: bool, - pub client_secret_hash: Vec, - pub current_client_secret: bool, - pub current_client_secret_hash: Vec, -} diff --git a/vnt-cli/src/command/mod.rs b/vnt-cli/src/command/mod.rs deleted file mode 100644 index fc1cd1c..0000000 --- a/vnt-cli/src/command/mod.rs +++ /dev/null @@ -1,211 +0,0 @@ -use std::io; -use vnt::core::Vnt; - -use crate::command::entity::{DeviceItem, Info, RouteItem}; -use crate::console_out; - -pub mod client; -pub mod entity; -pub mod server; - -pub enum CommandEnum { - Route, - List, - All, - Info, - Stop, -} - -pub fn command(cmd: CommandEnum) { - if let Err(e) = command_(cmd) { - println!("cmd: {:?}", e); - } -} - -fn command_(cmd: CommandEnum) -> io::Result<()> { - let mut command_client = client::CommandClient::new()?; - match cmd { - CommandEnum::Route => { - let list = command_client.route()?; - console_out::console_route_table(list); - } - CommandEnum::List => { - let list = command_client.list()?; - console_out::console_device_list(list); - } - CommandEnum::All => { - let list = command_client.list()?; - console_out::console_device_list_all(list); - } - CommandEnum::Info => { - let info = command_client.info()?; - console_out::console_info(info); - } - CommandEnum::Stop => { - command_client.stop()?; - } - } - Ok(()) -} - -pub fn command_route(vnt: &Vnt) -> Vec { - let route_table = vnt.route_table(); - let mut route_list = Vec::with_capacity(route_table.len()); - for (destination, routes) in route_table { - for route in routes { - let next_hop = vnt - .route_key(&route.route_key()) - .map_or(String::new(), |v| v.to_string()); - let metric = route.metric.to_string(); - let rt = if route.rt < 0 { - "".to_string() - } else { - route.rt.to_string() - }; - let interface = if route.is_tcp { - format!("tcp@{}", route.addr) - } else { - route.addr.to_string() - }; - let item = RouteItem { - destination: destination.to_string(), - next_hop, - metric, - rt, - interface, - }; - route_list.push(item); - } - } - route_list -} - -pub fn command_list(vnt: &Vnt) -> Vec { - let info = vnt.current_device(); - let device_list = vnt.device_list(); - let mut list = Vec::new(); - let current_client_secret = vnt.client_encrypt(); - let client_encrypt_hash = vnt.client_encrypt_hash().unwrap_or(&[]); - for peer in device_list { - let name = peer.name; - let virtual_ip = peer.virtual_ip.to_string(); - let (nat_type, public_ips, local_ip, ipv6) = - if let Some(nat_info) = vnt.peer_nat_info(&peer.virtual_ip) { - let nat_type = format!("{:?}", nat_info.nat_type); - let public_ips: Vec = - nat_info.public_ips.iter().map(|v| v.to_string()).collect(); - let public_ips = public_ips.join(","); - let local_ip = nat_info - .local_ipv4() - .map(|v| v.to_string()) - .unwrap_or("None".to_string()); - let ipv6 = nat_info - .ipv6() - .map(|v| v.to_string()) - .unwrap_or("None".to_string()); - (nat_type, public_ips, local_ip, ipv6) - } else { - ( - "".to_string(), - "".to_string(), - "".to_string(), - "".to_string(), - ) - }; - let (nat_traversal_type, rt) = if let Some(route) = vnt.route(&peer.virtual_ip) { - let nat_traversal_type = if route.metric == 1 { - if route.is_tcp { - "tcp-p2p" - } else { - "p2p" - } - } else { - let next_hop = vnt.route_key(&route.route_key()); - if let Some(next_hop) = next_hop { - if info.is_gateway(&next_hop) { - "server-relay" - } else { - "client-relay" - } - } else { - "server-relay" - } - } - .to_string(); - let rt = if route.rt < 0 { - "".to_string() - } else { - route.rt.to_string() - }; - (nat_traversal_type, rt) - } else { - ("relay".to_string(), "".to_string()) - }; - let status = format!("{:?}", peer.status); - let client_secret = peer.client_secret; - let item = DeviceItem { - name, - virtual_ip, - nat_type, - public_ips, - local_ip, - ipv6, - nat_traversal_type, - rt, - status, - client_secret, - client_secret_hash: peer.client_secret_hash, - current_client_secret, - current_client_secret_hash: client_encrypt_hash.to_vec(), - }; - list.push(item); - } - list -} - -pub fn command_info(vnt: &Vnt) -> Info { - let current_device = vnt.current_device(); - let nat_info = vnt.nat_info(); - let name = vnt.name().to_string(); - let virtual_ip = current_device.virtual_ip().to_string(); - let virtual_gateway = current_device.virtual_gateway().to_string(); - let virtual_netmask = current_device.virtual_netmask.to_string(); - let connect_status = format!("{:?}", vnt.connection_status()); - let relay_server = current_device.connect_server.to_string(); - let nat_type = format!("{:?}", nat_info.nat_type); - let public_ips: Vec = nat_info.public_ips.iter().map(|v| v.to_string()).collect(); - let public_ips = public_ips.join(","); - let local_addr = nat_info - .local_ipv4() - .map(|v| v.to_string()) - .unwrap_or("None".to_string()); - let ipv6_addr = nat_info - .ipv6() - .map(|v| v.to_string()) - .unwrap_or("None".to_string()); - let up = vnt.up_stream(); - let down = vnt.down_stream(); - #[cfg(feature = "port_mapping")] - let port_mapping_list = vnt.config().port_mapping_list.clone(); - #[cfg(not(feature = "port_mapping"))] - let port_mapping_list = vec![]; - let in_ips = vnt.config().in_ips.clone(); - let out_ips = vnt.config().out_ips.clone(); - Info { - name, - virtual_ip, - virtual_gateway, - virtual_netmask, - connect_status, - relay_server, - nat_type, - public_ips, - local_addr, - ipv6_addr, - up, - down, - port_mapping_list, - in_ips, - out_ips, - } -} diff --git a/vnt-cli/src/command/server.rs b/vnt-cli/src/command/server.rs deleted file mode 100644 index 4719c73..0000000 --- a/vnt-cli/src/command/server.rs +++ /dev/null @@ -1,78 +0,0 @@ -use std::io; -use std::io::Write; -use std::net::UdpSocket; - -use vnt::core::Vnt; - -pub struct CommandServer {} - -impl CommandServer { - pub fn new() -> Self { - Self {} - } -} - -impl CommandServer { - pub fn start(self, vnt: Vnt) -> io::Result<()> { - let udp = if let Ok(udp) = UdpSocket::bind("127.0.0.1:39271") { - udp - } else { - UdpSocket::bind("127.0.0.1:0")? - }; - let addr = udp.local_addr()?; - log::info!("启动后台cmd:{:?}", addr); - if let Err(e) = save_port(addr.port()) { - log::warn!("保存后台命令端口失败:{:?}", e); - } - - let mut buf = [0u8; 64]; - loop { - let (len, addr) = udp.recv_from(&mut buf)?; - match std::str::from_utf8(&buf[..len]) { - Ok(cmd) => { - if let Ok(out) = command(cmd, &vnt) { - if let Err(e) = udp.send_to(out.as_bytes(), addr) { - log::warn!("cmd={},err={:?}", cmd, e); - } - if "stopped" == &out { - break; - } - } - } - Err(e) => { - log::warn!("{:?}", e); - } - } - } - Ok(()) - } -} -fn save_port(port: u16) -> io::Result<()> { - let path_buf = crate::app_home()?.join("command-port"); - let mut file = std::fs::File::create(path_buf)?; - file.write_all(port.to_string().as_bytes())?; - file.sync_all() -} - -fn command(cmd: &str, vnt: &Vnt) -> io::Result { - let cmd = cmd.trim(); - let out_str = match cmd { - "route" => serde_yaml::to_string(&crate::command::command_route(vnt)) - .unwrap_or_else(|e| format!("error {:?}", e)), - "list" => serde_yaml::to_string(&crate::command::command_list(vnt)) - .unwrap_or_else(|e| format!("error {:?}", e)), - "info" => serde_yaml::to_string(&crate::command::command_info(vnt)) - .unwrap_or_else(|e| format!("error {:?}", e)), - "stop" => { - vnt.stop(); - "stopped".to_string() - } - _ => { - format!( - "command '{}' not found. Try to enter: 'route'/'list'/'stop' \n", - cmd - ) - } - }; - Ok(out_str) -} diff --git a/vnt-cli/src/config/file_config.rs b/vnt-cli/src/config/file_config.rs deleted file mode 100644 index c3429de..0000000 --- a/vnt-cli/src/config/file_config.rs +++ /dev/null @@ -1,168 +0,0 @@ -use anyhow::anyhow; -use std::net::Ipv4Addr; -use std::str::FromStr; - -use serde::{Deserialize, Serialize}; - -use crate::config::get_device_id; -use vnt::channel::punch::PunchModel; -use vnt::channel::UseChannelType; -use vnt::cipher::CipherModel; -use vnt::compression::Compressor; -use vnt::core::Config; - -#[derive(Serialize, Deserialize, Debug)] -#[serde(default)] -pub struct FileConfig { - #[cfg(target_os = "windows")] - pub tap: bool, - pub token: String, - pub device_id: String, - pub name: String, - pub server_address: String, - pub stun_server: Vec, - pub dns: Vec, - pub in_ips: Vec, - pub out_ips: Vec, - pub password: Option, - pub mtu: Option, - pub tcp: bool, - pub ip: Option, - pub use_channel: String, - #[cfg(feature = "ip_proxy")] - pub no_proxy: bool, - pub server_encrypt: bool, - pub cipher_model: Option, - pub finger: bool, - pub punch_model: String, - pub ports: Option>, - pub cmd: bool, - pub first_latency: bool, - pub device_name: Option, - pub packet_loss: Option, - pub packet_delay: u32, - #[cfg(feature = "port_mapping")] - pub mapping: Vec, - pub compressor: Option, -} - -impl Default for FileConfig { - fn default() -> Self { - Self { - #[cfg(target_os = "windows")] - tap: false, - token: "".to_string(), - device_id: get_device_id(), - name: os_info::get().to_string(), - server_address: "nat1.wherewego.top:29872".to_string(), - stun_server: vec![ - "stun1.l.google.com:19302".to_string(), - "stun2.l.google.com:19302".to_string(), - "stun.miwifi.com:3478".to_string(), - ], - dns: vec![], - in_ips: vec![], - out_ips: vec![], - password: None, - mtu: None, - tcp: false, - ip: None, - use_channel: "all".to_string(), - #[cfg(feature = "ip_proxy")] - no_proxy: false, - server_encrypt: false, - cipher_model: None, - finger: false, - punch_model: "all".to_string(), - ports: None, - cmd: false, - first_latency: false, - device_name: None, - packet_loss: None, - packet_delay: 0, - #[cfg(feature = "port_mapping")] - mapping: vec![], - compressor: None, - } - } -} - -pub fn read_config(file_path: &str) -> anyhow::Result<(Config, bool)> { - let conf = std::fs::read_to_string(file_path)?; - let file_conf = match serde_yaml::from_str::(&conf) { - Ok(val) => val, - Err(e) => { - log::error!("{:?}", e); - return Err(anyhow!("{}", e)); - } - }; - if file_conf.token.is_empty() { - return Err(anyhow!("token is_empty")); - } - - let in_ips = match common::args_parse::ips_parse(&file_conf.in_ips) { - Ok(in_ips) => in_ips, - Err(e) => { - return Err(anyhow!("in_ips {:?} error:{}", &file_conf.in_ips, e)); - } - }; - let out_ips = match common::args_parse::out_ips_parse(&file_conf.out_ips) { - Ok(out_ips) => out_ips, - Err(e) => { - return Err(anyhow!("out_ips {:?} error:{}", &file_conf.out_ips, e)); - } - }; - let virtual_ip = match file_conf.ip.clone().map(|v| Ipv4Addr::from_str(&v)) { - None => None, - Some(r) => Some(r.map_err(|e| anyhow!("ip {:?} error:{}", &file_conf.ip, e))?), - }; - let cipher_model = { - #[cfg(not(any(feature = "aes_gcm", feature = "server_encrypt")))] - if file_conf.password.is_some() && file_conf.cipher_model.is_none() { - Err(anyhow!("cipher_model undefined"))? - } - #[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))] - CipherModel::AesGcm - }; - - let punch_model = PunchModel::from_str(&file_conf.punch_model).map_err(|e| anyhow!("{}", e))?; - let use_channel_type = - UseChannelType::from_str(&file_conf.use_channel).map_err(|e| anyhow!("{}", e))?; - let compressor = if let Some(compressor) = file_conf.compressor.as_ref() { - Compressor::from_str(compressor).map_err(|e| anyhow!("{}", e))? - } else { - Compressor::None - }; - let config = Config::new( - #[cfg(target_os = "windows")] - file_conf.tap, - file_conf.token, - file_conf.device_id, - file_conf.name, - file_conf.server_address, - file_conf.dns, - file_conf.stun_server, - in_ips, - out_ips, - file_conf.password, - file_conf.mtu, - file_conf.tcp, - virtual_ip, - #[cfg(feature = "ip_proxy")] - file_conf.no_proxy, - file_conf.server_encrypt, - cipher_model, - file_conf.finger, - punch_model, - file_conf.ports, - file_conf.first_latency, - file_conf.device_name, - use_channel_type, - file_conf.packet_loss, - file_conf.packet_delay, - #[cfg(feature = "port_mapping")] - file_conf.mapping, - compressor, - )?; - Ok((config, file_conf.cmd)) -} diff --git a/vnt-cli/src/config/mod.rs b/vnt-cli/src/config/mod.rs deleted file mode 100644 index 4472e71..0000000 --- a/vnt-cli/src/config/mod.rs +++ /dev/null @@ -1,31 +0,0 @@ -#[cfg(feature = "file_config")] -mod file_config; - -#[cfg(feature = "file_config")] -pub use file_config::read_config; - -#[cfg(not(feature = "file_config"))] -pub fn read_config(_file_path: &str) -> anyhow::Result<(vnt::core::Config, bool)> { - unimplemented!() -} - -pub fn get_device_id() -> String { - if let Some(id) = common::identifier::get_unique_identifier() { - id - } else { - let path_buf = match crate::app_home() { - Ok(path_buf) => path_buf.join("device-id"), - Err(e) => { - log::warn!("{:?}", e); - return String::new(); - } - }; - if let Ok(id) = std::fs::read_to_string(path_buf.as_path()) { - id - } else { - let id = uuid::Uuid::new_v4().to_string(); - let _ = std::fs::write(path_buf, &id); - id - } - } -} diff --git a/vnt-cli/src/console_out/mod.rs b/vnt-cli/src/console_out/mod.rs deleted file mode 100644 index 44bde16..0000000 --- a/vnt-cli/src/console_out/mod.rs +++ /dev/null @@ -1,239 +0,0 @@ -use console::{style, Style}; -use std::net::Ipv4Addr; - -use crate::command::entity::{DeviceItem, Info, RouteItem}; - -pub mod table; - -pub fn console_info(status: Info) { - println!("Name: {}", style(status.name).green()); - println!("Virtual ip: {}", style(status.virtual_ip).green()); - println!("Virtual gateway: {}", style(status.virtual_gateway).green()); - println!("Virtual netmask: {}", style(status.virtual_netmask).green()); - if status.connect_status.eq_ignore_ascii_case("Connected") { - println!( - "Connection status: {}", - style(status.connect_status).green() - ); - } else { - println!("Connection status: {}", style(status.connect_status).red()); - } - - println!("NAT type: {}", style(status.nat_type).green()); - println!("Relay server: {}", style(status.relay_server).green()); - println!("Public ips: {}", style(status.public_ips).green()); - println!("Local addr: {}", style(status.local_addr).green()); - println!("IPv6: {}", style(status.ipv6_addr).green()); - println!("Up: {}", style(convert(status.up)).green()); - println!("Down: {}", style(convert(status.down)).green()); - - if !status.port_mapping_list.is_empty() { - println!("------------------------------------------"); - println!("Port mapping {}", status.port_mapping_list.len()); - for (is_tcp, addr, dest) in status.port_mapping_list { - if is_tcp { - println!(" TCP: {} -> {}", addr, dest) - } else { - println!(" UDP: {} -> {}", addr, dest) - } - } - } - if !status.in_ips.is_empty() || !status.out_ips.is_empty() { - println!("------------------------------------------"); - } - if !status.in_ips.is_empty() { - println!("IP forwarding {}", status.in_ips.len()); - for (dest, mask, ip) in status.in_ips { - println!( - " -- {} --> {}/{}", - ip, - Ipv4Addr::from(dest), - mask.count_ones() - ) - } - } - if !status.out_ips.is_empty() { - println!("Allows network {}", status.out_ips.len()); - for (dest, mask) in status.out_ips { - println!(" {}/{}", Ipv4Addr::from(dest), mask.count_ones()) - } - } -} - -fn convert(num: u64) -> String { - let gigabytes = num / (1024 * 1024 * 1024); - let remaining_bytes = num % (1024 * 1024 * 1024); - let megabytes = remaining_bytes / (1024 * 1024); - let remaining_bytes = remaining_bytes % (1024 * 1024); - let kilobytes = remaining_bytes / 1024; - let remaining_bytes = remaining_bytes % 1024; - let mut s = String::new(); - if gigabytes > 0 { - s.push_str(&format!("{} GB ", gigabytes)); - } - if megabytes > 0 { - s.push_str(&format!("{} MB ", megabytes)); - } - if kilobytes > 0 { - s.push_str(&format!("{} KB ", kilobytes)); - } - if remaining_bytes > 0 { - s.push_str(&format!("{} bytes", remaining_bytes)); - } - s -} - -pub fn console_route_table(mut list: Vec) { - if list.is_empty() { - println!("No route found"); - return; - } - list.sort_by(|t1, t2| t1.destination.cmp(&t2.destination)); - let mut out_list = Vec::with_capacity(list.len()); - - out_list.push(vec![ - ("Destination".to_string(), Style::new()), - ("Next Hop".to_string(), Style::new()), - ("Metric".to_string(), Style::new()), - ("Rt".to_string(), Style::new()), - ("Interface".to_string(), Style::new()), - ]); - for item in list { - out_list.push(vec![ - (item.destination, Style::new().green()), - (item.next_hop, Style::new().green()), - (item.metric, Style::new().green()), - (item.rt, Style::new().green()), - (item.interface, Style::new().green()), - ]); - } - - table::println_table(out_list) -} - -pub fn console_device_list(mut list: Vec) { - if list.is_empty() { - println!("No other devices found"); - return; - } - list.sort_by(|t1, t2| t1.virtual_ip.cmp(&t2.virtual_ip)); - list.sort_by(|t1, t2| t1.status.cmp(&t2.status)); - let mut out_list = Vec::with_capacity(list.len()); - //表头 - out_list.push(vec![ - ("Name".to_string(), Style::new()), - ("Virtual Ip".to_string(), Style::new()), - ("Status".to_string(), Style::new()), - ("P2P/Relay".to_string(), Style::new()), - ("Rt".to_string(), Style::new()), - ]); - for item in list { - if &item.status == "Online" { - if item.client_secret != item.current_client_secret - || (!item.current_client_secret_hash.is_empty() - && !item.client_secret_hash.is_empty() - && item.current_client_secret_hash != item.client_secret_hash) - { - //加密状态不一致,无法通信的 - out_list.push(vec![ - (item.name, Style::new().red()), - (item.virtual_ip, Style::new().red()), - (item.status, Style::new().red()), - ("Mismatch".to_string(), Style::new().red()), - ("".to_string(), Style::new().red()), - ]); - } else { - if item.nat_traversal_type.contains("p2p") { - out_list.push(vec![ - (item.name, Style::new().green()), - (item.virtual_ip, Style::new().green()), - (item.status, Style::new().green()), - (item.nat_traversal_type, Style::new().green()), - (item.rt, Style::new().green()), - ]); - } else { - out_list.push(vec![ - (item.name, Style::new().yellow()), - (item.virtual_ip, Style::new().yellow()), - (item.status, Style::new().yellow()), - (item.nat_traversal_type, Style::new().yellow()), - (item.rt, Style::new().yellow()), - ]); - } - } - } else { - out_list.push(vec![ - (item.name, Style::new().color256(102)), - (item.virtual_ip, Style::new().color256(102)), - (item.status, Style::new().color256(102)), - ("".to_string(), Style::new().color256(102)), - ("".to_string(), Style::new().color256(102)), - ]); - } - } - table::println_table(out_list) -} - -pub fn console_device_list_all(mut list: Vec) { - if list.is_empty() { - println!("No other devices found"); - return; - } - list.sort_by(|t1, t2| t1.virtual_ip.cmp(&t2.virtual_ip)); - list.sort_by(|t1, t2| t1.status.cmp(&t2.status)); - let mut out_list = Vec::with_capacity(list.len()); - //表头 - out_list.push(vec![ - ("Name".to_string(), Style::new()), - ("Virtual Ip".to_string(), Style::new()), - ("Status".to_string(), Style::new()), - ("P2P/Relay".to_string(), Style::new()), - ("Rt".to_string(), Style::new()), - ("NAT Type".to_string(), Style::new()), - ("Public Ips".to_string(), Style::new()), - ("Local Ip".to_string(), Style::new()), - ("IPv6".to_string(), Style::new()), - ]); - for item in list { - if &item.status == "Online" { - if &item.nat_traversal_type == "p2p" { - out_list.push(vec![ - (item.name, Style::new().green()), - (item.virtual_ip, Style::new().green()), - (item.status, Style::new().green()), - (item.nat_traversal_type, Style::new().green()), - (item.rt, Style::new().green()), - (item.nat_type, Style::new().green()), - (item.public_ips, Style::new().green()), - (item.local_ip, Style::new().green()), - (item.ipv6, Style::new().green()), - ]); - } else { - out_list.push(vec![ - (item.name, Style::new().yellow()), - (item.virtual_ip, Style::new().yellow()), - (item.status, Style::new().yellow()), - (item.nat_traversal_type, Style::new().yellow()), - (item.rt, Style::new().yellow()), - (item.nat_type, Style::new().yellow()), - (item.public_ips, Style::new().yellow()), - (item.local_ip, Style::new().yellow()), - (item.ipv6, Style::new().yellow()), - ]); - } - } else { - out_list.push(vec![ - (item.name, Style::new().color256(102)), - (item.virtual_ip, Style::new().color256(102)), - (item.status, Style::new().color256(102)), - ("".to_string(), Style::new().color256(102)), - ("".to_string(), Style::new().color256(102)), - ("".to_string(), Style::new().color256(102)), - ("".to_string(), Style::new().color256(102)), - ("".to_string(), Style::new().color256(102)), - ("".to_string(), Style::new().color256(102)), - ]); - } - } - table::println_table(out_list) -} diff --git a/vnt-cli/src/console_out/table.rs b/vnt-cli/src/console_out/table.rs deleted file mode 100644 index aacc006..0000000 --- a/vnt-cli/src/console_out/table.rs +++ /dev/null @@ -1,23 +0,0 @@ -use console::Style; - -pub fn println_table(table: Vec>) { - if table.is_empty() { - return; - } - let mut width_list = vec![0; table[0].len()]; - for in_list in table.iter() { - for (index, (item, _)) in in_list.iter().enumerate() { - let width = console::measure_text_width(item) + 4; - if width_list[index] < width { - width_list[index] = width; - } - } - } - for in_list in table { - for (col, (item, style)) in in_list.iter().enumerate() { - let str = format!("{:1$}", item, width_list[col]); - print!("{}", style.apply_to(str)); - } - println!() - } -} diff --git a/vnt-cli/src/main.rs b/vnt-cli/src/main.rs index cf8b5d3..6a0dd49 100644 --- a/vnt-cli/src/main.rs +++ b/vnt-cli/src/main.rs @@ -1,349 +1,29 @@ -use anyhow::anyhow; -use std::io; -use std::net::Ipv4Addr; -use std::path::PathBuf; -use std::str::FromStr; - -use console::style; -use getopts::Options; - -use common::args_parse::{ips_parse, out_ips_parse}; -use vnt::channel::punch::PunchModel; -use vnt::channel::UseChannelType; -use vnt::cipher::CipherModel; -use vnt::compression::Compressor; +use common::callback; use vnt::core::{Config, Vnt}; - -#[cfg(feature = "command")] -mod command; -mod config; -#[cfg(feature = "command")] -mod console_out; -mod generated_serial_number; mod root_check; - -pub fn app_home() -> io::Result { - let root_path = match std::env::current_exe() { - Ok(path) => { - if let Some(v) = path.as_path().parent() { - v.to_path_buf() +fn main() { + let (config, _vnt_link_config, cmd) = match common::cli::parse_args_config() { + Ok(rs) => { + if let Some(rs) = rs { + rs } else { - log::warn!("current_exe parent none:{:?}", path); - PathBuf::new() + return; } } Err(e) => { - log::warn!("current_exe err:{:?}", e); - PathBuf::new() - } - }; - let path = root_path.join("env"); - if !path.exists() { - std::fs::create_dir_all(&path)?; - } - Ok(path) -} - -fn main() { - #[cfg(feature = "log")] - let _ = log4rs::init_file("log4rs.yaml", Default::default()); - let args: Vec = std::env::args().collect(); - let program = args[0].clone(); - let mut opts = Options::new(); - opts.optopt("k", "", "组网标识", ""); - opts.optopt("n", "", "设备名称", ""); - opts.optopt("d", "", "设备标识", ""); - opts.optflag("c", "", "关闭交互式命令"); - opts.optopt("s", "", "注册和中继服务器地址", ""); - opts.optmulti("e", "", "stun服务器", ""); - opts.optflag("a", "", "使用tap模式"); - opts.optopt("", "nic", "虚拟网卡名称,windows下使用tap则必填", ""); - opts.optmulti("i", "", "配置点对网(IP代理)入站时使用", ""); - opts.optmulti("o", "", "配置点对网出站时使用", ""); - opts.optopt("w", "", "客户端加密", ""); - opts.optflag("W", "", "服务端加密"); - opts.optopt("u", "", "自定义mtu(默认为1430)", ""); - opts.optflag("", "tcp", "tcp"); - opts.optopt("", "ip", "指定虚拟ip", ""); - opts.optflag("", "relay", "仅使用服务器转发"); - opts.optopt("", "par", "任务并行度(必须为正整数)", ""); - opts.optopt("", "model", "加密模式", ""); - opts.optflag("", "finger", "指纹校验"); - opts.optopt("", "punch", "取值ipv4/ipv6", ""); - opts.optopt("", "ports", "监听的端口", ""); - opts.optflag("", "cmd", "开启窗口输入"); - opts.optflag("", "no-proxy", "关闭内置代理"); - opts.optflag("", "first-latency", "优先延迟"); - opts.optopt("", "use-channel", "使用通道 relay/p2p", ""); - opts.optopt("", "packet-loss", "丢包率", ""); - opts.optopt("", "packet-delay", "延迟", ""); - opts.optmulti("", "dns", "dns", ""); - opts.optmulti("", "mapping", "mapping", ""); - opts.optopt("f", "", "配置文件", ""); - opts.optopt("", "compressor", "压缩算法", ""); - //"后台运行时,查看其他设备列表" - opts.optflag("", "list", "后台运行时,查看其他设备列表"); - opts.optflag("", "all", "后台运行时,查看其他设备完整信息"); - opts.optflag("", "info", "后台运行时,查看当前设备信息"); - opts.optflag("", "route", "后台运行时,查看数据转发路径"); - opts.optflag("", "stop", "停止后台运行"); - opts.optflag("h", "help", "帮助"); - let matches = match opts.parse(&args[1..]) { - Ok(m) => m, - Err(f) => { - print_usage(&program, opts); - println!("{}", f.to_string()); + println!("{}", e); return; } }; - if matches.opt_present("h") || args.len() == 1 { - print_usage(&program, opts); - return; - } + main0(config, cmd) +} +fn main0(config: Config, _show_cmd: bool) { if !root_check::is_app_elevated() { println!("Please run it with administrator or root privileges"); #[cfg(any(target_os = "linux", target_os = "macos"))] sudo::escalate_if_needed().unwrap(); return; } - #[cfg(feature = "command")] - if matches.opt_present("list") { - command::command(command::CommandEnum::List); - return; - } else if matches.opt_present("info") { - command::command(command::CommandEnum::Info); - return; - } else if matches.opt_present("stop") { - command::command(command::CommandEnum::Stop); - return; - } else if matches.opt_present("route") { - command::command(command::CommandEnum::Route); - return; - } else if matches.opt_present("all") { - command::command(command::CommandEnum::All); - return; - } - let conf = matches.opt_str("f"); - let (config, cmd) = if conf.is_some() { - match config::read_config(&conf.unwrap()) { - Ok(c) => c, - Err(e) => { - println!("conf err {}", e); - return; - } - } - } else { - if !matches.opt_present("k") { - print_usage(&program, opts); - println!("parameter -k not found ."); - return; - } - #[cfg(target_os = "windows")] - let tap = matches.opt_present("a"); - let device_name = matches.opt_str("nic"); - let token: String = matches.opt_get("k").unwrap().unwrap(); - let device_id = matches.opt_get_default("d", String::new()).unwrap(); - let device_id = if device_id.is_empty() { - config::get_device_id() - } else { - device_id - }; - if device_id.is_empty() { - print_usage(&program, opts); - println!("parameter -d not found ."); - return; - } - let name = matches - .opt_get_default("n", os_info::get().to_string()) - .unwrap(); - let server_address_str = matches - .opt_get_default("s", "nat1.wherewego.top:29872".to_string()) - .unwrap(); - - let mut stun_server = matches.opt_strs("e"); - if stun_server.is_empty() { - stun_server.push("stun1.l.google.com:19302".to_string()); - stun_server.push("stun2.l.google.com:19302".to_string()); - stun_server.push("stun.miwifi.com:3478".to_string()); - } - let dns = matches.opt_strs("dns"); - let in_ip = matches.opt_strs("i"); - let in_ip = match ips_parse(&in_ip) { - Ok(in_ip) => in_ip, - Err(e) => { - print_usage(&program, opts); - println!(); - println!("-i: {:?} {}", in_ip, e); - println!("example: -i 192.168.0.0/24,10.26.0.3"); - return; - } - }; - let out_ip = matches.opt_strs("o"); - let out_ip = match out_ips_parse(&out_ip) { - Ok(out_ip) => out_ip, - Err(e) => { - print_usage(&program, opts); - println!(); - println!("-o: {:?} {}", out_ip, e); - println!("example: -o 0.0.0.0/0"); - return; - } - }; - let password: Option = matches.opt_get("w").unwrap(); - let server_encrypt = matches.opt_present("W"); - #[cfg(not(feature = "server_encrypt"))] - { - if server_encrypt { - println!("Server encryption not supported"); - return; - } - } - let mtu: Option = matches.opt_get("u").unwrap(); - let mtu = if let Some(mtu) = mtu { - match u32::from_str(&mtu) { - Ok(mtu) => Some(mtu), - Err(e) => { - print_usage(&program, opts); - println!(); - println!("'-u {}' {}", mtu, e); - return; - } - } - } else { - None - }; - let virtual_ip: Option = matches.opt_get("ip").unwrap(); - let virtual_ip = - virtual_ip.map(|v| Ipv4Addr::from_str(&v).expect(&format!("'--ip {}' error", v))); - if let Some(virtual_ip) = virtual_ip { - if virtual_ip.is_unspecified() || virtual_ip.is_broadcast() || virtual_ip.is_multicast() - { - println!("'--ip {}' invalid", virtual_ip); - return; - } - } - let tcp_channel = matches.opt_present("tcp"); - let relay = matches.opt_present("relay"); - - let parallel = matches.opt_get::("par").unwrap().unwrap_or(1); - if parallel == 0 { - println!("'--par {}' invalid", parallel); - return; - } - - let cipher_model = match matches.opt_get::("model") { - Ok(model) => { - #[cfg(not(any(feature = "aes_gcm", feature = "server_encrypt")))] - { - if password.is_some() && model.is_none() { - println!("'--model ' undefined"); - return; - } - model.unwrap_or(CipherModel::None) - } - #[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))] - model.unwrap_or(CipherModel::AesGcm) - } - Err(e) => { - println!("'--model ' invalid,{}", e); - return; - } - }; - - let finger = matches.opt_present("finger"); - let punch_model = matches - .opt_get::("punch") - .unwrap() - .unwrap_or(PunchModel::All); - let use_channel_type = matches - .opt_get::("use-channel") - .unwrap() - .unwrap_or_else(|| { - if relay { - UseChannelType::Relay - } else { - UseChannelType::All - } - }); - - let ports = matches - .opt_get::("ports") - .unwrap_or(None) - .map(|v| v.split(",").map(|x| x.parse().unwrap_or(0)).collect()); - - let cmd = matches.opt_present("cmd"); - #[cfg(feature = "ip_proxy")] - let no_proxy = matches.opt_present("no-proxy"); - let first_latency = matches.opt_present("first-latency"); - let packet_loss = matches - .opt_get::("packet-loss") - .expect("--packet-loss"); - let packet_delay = matches - .opt_get::("packet-delay") - .expect("--packet-delay") - .unwrap_or(0); - #[cfg(feature = "port_mapping")] - let port_mapping_list = matches.opt_strs("mapping"); - let compressor = if let Some(compressor) = matches.opt_str("compressor").as_ref() { - Compressor::from_str(compressor) - .map_err(|e| anyhow!("{}", e)) - .unwrap() - } else { - Compressor::None - }; - let config = match Config::new( - #[cfg(target_os = "windows")] - tap, - token, - device_id, - name, - server_address_str, - dns, - stun_server, - in_ip, - out_ip, - password, - mtu, - tcp_channel, - virtual_ip, - #[cfg(feature = "ip_proxy")] - no_proxy, - server_encrypt, - cipher_model, - finger, - punch_model, - ports, - first_latency, - device_name, - use_channel_type, - packet_loss, - packet_delay, - #[cfg(feature = "port_mapping")] - port_mapping_list, - compressor, - ) { - Ok(config) => config, - Err(e) => { - println!("config.toml error: {}", e); - std::process::exit(1); - } - }; - (config, cmd) - }; - println!("version {}", vnt::VNT_VERSION); - println!("Serial:{}", generated_serial_number::SERIAL_NUMBER); - log::info!( - "version:{},Serial:{}", - vnt::VNT_VERSION, - generated_serial_number::SERIAL_NUMBER - ); - main0(config, cmd); - std::process::exit(0); -} - -mod callback; - -fn main0(config: Config, _show_cmd: bool) { #[cfg(feature = "port_mapping")] for (is_tcp, addr, dest) in config.port_mapping_list.iter() { if *is_tcp { @@ -388,7 +68,7 @@ fn main0(config: Config, _show_cmd: bool) { std::thread::Builder::new() .name("CommandServer".into()) .spawn(move || { - if let Err(e) = command::server::CommandServer::new().start(vnt_c) { + if let Err(e) = common::command::server::CommandServer::new().start(vnt_c) { log::warn!("cmd:{:?}", e); } }) @@ -398,9 +78,9 @@ fn main0(config: Config, _show_cmd: bool) { loop { cmd.clear(); println!("======== input:list,info,route,all,stop ========"); - match io::stdin().read_line(&mut cmd) { + match std::io::stdin().read_line(&mut cmd) { Ok(len) => { - if !command(&cmd[..len], &vnt_util) { + if !common::command::command_str(&cmd[..len], &vnt_util) { break; } } @@ -415,150 +95,3 @@ fn main0(config: Config, _show_cmd: bool) { vnt_util.wait() } - -#[cfg(feature = "command")] -fn command(cmd: &str, vnt: &Vnt) -> bool { - if cmd.is_empty() { - return false; - } - match cmd.to_lowercase().trim() { - "list" => { - let list = command::command_list(&vnt); - console_out::console_device_list(list); - } - "info" => { - let info = command::command_info(&vnt); - console_out::console_info(info); - } - "route" => { - let route = command::command_route(&vnt); - console_out::console_route_table(route); - } - "all" => { - let list = command::command_list(&vnt); - console_out::console_device_list_all(list); - } - "stop" => { - let _ = vnt.stop(); - return false; - } - _ => {} - } - println!(); - return true; -} - -fn print_usage(program: &str, _opts: Options) { - println!("Usage: {} [options]", program); - println!("version:{}", vnt::VNT_VERSION); - println!("Serial:{}", generated_serial_number::SERIAL_NUMBER); - println!("Options:"); - println!( - " -k {}", - green("使用相同的token,就能组建一个局域网络".to_string()) - ); - println!(" -n 给设备一个名字,便于区分不同设备,默认使用系统版本"); - println!(" -d 设备唯一标识符,不使用--ip参数时,服务端凭此参数分配虚拟ip,注意不能重复"); - println!(" -s 注册和中继服务器地址,以'TXT:'开头表示解析TXT记录"); - println!(" -e stun服务器,用于探测NAT类型,可使用多个地址,如-e stun1.l.google.com -e stun2.l.google.com"); - #[cfg(target_os = "windows")] - println!( - " -a 使用tap模式,默认使用tun模式,使用tap时需要配合'--nic'参数指定tap网卡" - ); - println!(" -i 配置点对网(IP代理)时使用,-i 192.168.0.0/24,10.26.0.3表示允许接收网段192.168.0.0/24的数据"); - println!(" 并转发到10.26.0.3,可指定多个网段"); - println!(" -o 配置点对网时使用,-o 192.168.0.0/24表示允许将数据转发到192.168.0.0/24,可指定多个网段"); - - println!(" -w 使用该密码生成的密钥对客户端数据进行加密,并且服务端无法解密,使用相同密码的客户端才能通信"); - #[cfg(feature = "server_encrypt")] - println!(" -W 加密当前客户端和服务端通信的数据,请留意服务端指纹是否正确"); - println!(" -u 自定义mtu(不加密默认为1450,加密默认为1410)"); - #[cfg(feature = "file_config")] - println!(" -f 读取配置文件中的配置"); - - println!(" --tcp 和服务端使用tcp通信,默认使用udp,遇到udp qos时可指定使用tcp"); - println!(" --ip 指定虚拟ip,指定的ip不能和其他设备重复,必须有效并且在服务端所属网段下,默认情况由服务端分配"); - let mut enums = String::new(); - #[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))] - enums.push_str("/aes_gcm"); - #[cfg(feature = "chacha20_poly1305")] - enums.push_str("/chacha20_poly1305/chacha20"); - #[cfg(feature = "aes_cbc")] - enums.push_str("/aes_cbc"); - #[cfg(feature = "aes_ecb")] - enums.push_str("/aes_ecb"); - #[cfg(feature = "sm4_cbc")] - enums.push_str("/sm4_cbc"); - enums.push_str("/xor"); - println!( - " --model 加密模式(默认aes_gcm),可选值{}", - &enums[1..] - ); - #[cfg(any( - feature = "aes_gcm", - feature = "chacha20_poly1305", - feature = "server_encrypt", - feature = "aes_cbc", - feature = "aes_ecb", - feature = "sm4_cbc" - ))] - println!(" --finger 增加数据指纹校验,可增加安全性,如果服务端开启指纹校验,则客户端也必须开启"); - println!(" --punch 取值ipv4/ipv6/all,ipv4表示仅使用ipv4打洞"); - println!(" --ports 取值0~65535,指定本地监听的一组端口,默认监听两个随机端口,使用过多端口会增加网络负担"); - #[cfg(feature = "command")] - println!(" --cmd 开启交互式命令,使用此参数开启控制台输入"); - #[cfg(feature = "ip_proxy")] - println!(" --no-proxy 关闭内置代理,如需点对网则需要配置网卡NAT转发"); - println!(" --first-latency 优先低延迟的通道,默认情况优先使用p2p通道"); - println!(" --use-channel 使用通道 relay/p2p/all,默认两者都使用"); - println!(" --nic 指定虚拟网卡名称"); - println!(" --packet-loss <0> 模拟丢包,取值0~1之间的小数,程序会按设定的概率主动丢包,可用于模拟弱网"); - println!( - " --packet-delay <0> 模拟延迟,整数,单位毫秒(ms),程序会按设定的值延迟发包,可用于模拟弱网" - ); - println!(" --dns DNS服务器地址,可使用多个dns,不指定时使用系统解析"); - #[cfg(feature = "port_mapping")] - println!(" --mapping 端口映射,例如 --mapping udp:0.0.0.0:80->10.26.0.10:80 --mapping tcp:0.0.0.0:80->10.26.0.10:80"); - #[cfg(all(feature = "lz4", feature = "zstd"))] - println!(" --compressor 启用压缩,可选值lz4/zstd<,level>,level为压缩级别,例如 --compressor lz4 或--compressor zstd,10"); - #[cfg(feature = "lz4")] - #[cfg(not(feature = "zstd"))] - println!(" --compressor 启用压缩,可选值lz4,例如 --compressor lz4"); - #[cfg(feature = "zstd")] - #[cfg(not(feature = "lz4"))] - println!(" --compressor 启用压缩,可选值zstd<,level>,level为压缩级别,例如 --compressor zstd,10"); - println!(); - #[cfg(feature = "command")] - { - println!( - " --list {}", - yellow("后台运行时,查看其他设备列表".to_string()) - ); - println!( - " --all {}", - yellow("后台运行时,查看其他设备完整信息".to_string()) - ); - println!( - " --info {}", - yellow("后台运行时,查看当前设备信息".to_string()) - ); - println!( - " --route {}", - yellow("后台运行时,查看数据转发路径".to_string()) - ); - println!( - " --stop {}", - yellow("停止后台运行".to_string()) - ); - } - println!(" -h, --help 帮助"); -} - -fn green(str: String) -> impl std::fmt::Display { - style(str).green() -} - -#[cfg(feature = "command")] -fn yellow(str: String) -> impl std::fmt::Display { - style(str).yellow() -}