去除重复代码
This commit is contained in:
+24
-31
@@ -6,21 +6,11 @@ edition = "2021"
|
|||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
vnt = { path = "../vnt", package = "vnt", default-features = false }
|
vnt = { path = "../vnt", package = "vnt", default-features = false, features = ["integrated_tun"] }
|
||||||
common = { path = "../common" }
|
common = { path = "../common", default-features = false, features = ["integrated_tun"] }
|
||||||
getopts = "0.2.21"
|
|
||||||
console = "0.15.2"
|
|
||||||
os_info = "3.7.0"
|
|
||||||
serde = "1.0"
|
|
||||||
serde_yaml = "0.9.32"
|
|
||||||
log = "0.4.17"
|
log = "0.4.17"
|
||||||
log4rs = { version = "1.2.0", optional = true }
|
|
||||||
anyhow = "1.0.82"
|
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]
|
[target.'cfg(any(target_os = "linux",target_os = "macos"))'.dependencies]
|
||||||
sudo = "0.6.0"
|
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"] }
|
winapi = { version = "0.3.9", features = ["handleapi", "processthreadsapi", "winnt", "securitybaseapi", "impl-default"] }
|
||||||
|
|
||||||
[features]
|
[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"]
|
default = ["default-feature"]
|
||||||
openssl = ["vnt/openssl"]
|
default-feature = ["server_encrypt", "aes_gcm", "aes_cbc", "aes_ecb", "sm4_cbc", "chacha20_poly1305", "ip_proxy", "port_mapping", "log", "command", "file_config", "lz4"]
|
||||||
openssl-vendored = ["vnt/openssl-vendored"]
|
|
||||||
ring-cipher = ["vnt/ring-cipher"]
|
openssl = ["vnt/openssl", "common/openssl"]
|
||||||
aes_cbc = ["vnt/aes_cbc"]
|
openssl-vendored = ["vnt/openssl-vendored", "common/openssl-vendored"]
|
||||||
aes_ecb = ["vnt/aes_ecb"]
|
ring-cipher = ["vnt/ring-cipher", "common/ring-cipher"]
|
||||||
sm4_cbc = ["vnt/sm4_cbc"]
|
aes_cbc = ["vnt/aes_cbc", "common/aes_cbc"]
|
||||||
aes_gcm = ["vnt/aes_gcm"]
|
aes_ecb = ["vnt/aes_ecb", "common/aes_ecb"]
|
||||||
chacha20_poly1305 = ["vnt/chacha20_poly1305"]
|
sm4_cbc = ["vnt/sm4_cbc", "common/sm4_cbc"]
|
||||||
server_encrypt = ["vnt/server_encrypt"]
|
aes_gcm = ["vnt/aes_gcm", "common/aes_gcm"]
|
||||||
ip_proxy = ["vnt/ip_proxy"]
|
chacha20_poly1305 = ["vnt/chacha20_poly1305", "common/chacha20_poly1305"]
|
||||||
port_mapping = ["vnt/port_mapping"]
|
server_encrypt = ["vnt/server_encrypt", "common/server_encrypt"]
|
||||||
lz4 = ["vnt/lz4_compress"]
|
port_mapping = ["vnt/port_mapping", "common/port_mapping"]
|
||||||
zstd = ["vnt/zstd_compress"]
|
lz4 = ["vnt/lz4_compress", "common/lz4"]
|
||||||
log = ["log4rs"]
|
zstd = ["vnt/zstd_compress", "common/zstd"]
|
||||||
command = []
|
ip_proxy = ["vnt/ip_proxy", "common/ip_proxy"]
|
||||||
file_config = []
|
log = ["common/log"]
|
||||||
|
command = ["common/command"]
|
||||||
|
file_config = ["common/file_config"]
|
||||||
|
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
embed-manifest = "1.4.0"
|
|
||||||
rand = "0.8.5"
|
rand = "0.8.5"
|
||||||
chrono = "0.4.23"
|
chrono = "0.4.23"
|
||||||
+5
-5
@@ -143,9 +143,9 @@ aes_gcm/aes_cbc/aes_ecb/sm4_cbc/chacha20_poly1305/chacha20/xor,默认使用aes
|
|||||||
|
|
||||||
当地址解析失败时,会依次尝试后面的dns,直到有A记录、AAAA记录(或TXT记录)的解析结果
|
当地址解析失败时,会依次尝试后面的dns,直到有A记录、AAAA记录(或TXT记录)的解析结果
|
||||||
|
|
||||||
### --mapping `<udp:0.0.0.0:80->10.26.0.10:80>`
|
### --mapping `<udp:0.0.0.0:80-10.26.0.10:80>`
|
||||||
|
|
||||||
端口映射,可以设置多个映射地址,例如 '--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,转发的目的地址可以使用域名+端口
|
表示将本地udp 80端口的数据转发到10.26.0.10:80,将本地tcp 80端口的数据转发到10.26.0.11:81,转发的目的地址可以使用域名+端口
|
||||||
|
|
||||||
### --compressor `<lz4>`
|
### --compressor `<lz4>`
|
||||||
@@ -198,9 +198,9 @@ dns:
|
|||||||
- 223.5.5.5 # 首选dns
|
- 223.5.5.5 # 首选dns
|
||||||
- 8.8.8.8 # 备选dns
|
- 8.8.8.8 # 备选dns
|
||||||
mapping:
|
mapping:
|
||||||
- udp:0.0.0.0:80->10.26.0.10:80 # 映射udp数据
|
- 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:80-10.26.0.10:81 # 映射tcp数据
|
||||||
- tcp:0.0.0.0:82->localhost:83 # 映射tcp数据
|
- tcp:0.0.0.0:82-localhost:83 # 映射tcp数据
|
||||||
```
|
```
|
||||||
|
|
||||||
或者需要哪个配置就加哪个,当然token是必须的
|
或者需要哪个配置就加哪个,当然token是必须的
|
||||||
|
|||||||
@@ -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();
|
|
||||||
}
|
|
||||||
@@ -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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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<u8>,
|
|
||||||
udp: UdpSocket,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CommandClient {
|
|
||||||
pub fn new() -> io::Result<Self> {
|
|
||||||
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<u16> {
|
|
||||||
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<Vec<DeviceItem>> {
|
|
||||||
self.send_cmd(b"list")
|
|
||||||
}
|
|
||||||
pub fn route(&mut self) -> io::Result<Vec<RouteItem>> {
|
|
||||||
self.send_cmd(b"route")
|
|
||||||
}
|
|
||||||
pub fn info(&mut self) -> io::Result<Info> {
|
|
||||||
self.send_cmd(b"info")
|
|
||||||
}
|
|
||||||
fn send_cmd<'a, V: Deserialize<'a>>(&'a mut self, cmd: &[u8]) -> io::Result<V> {
|
|
||||||
self.udp.send(cmd)?;
|
|
||||||
let len = self.udp.recv(&mut self.buf)?;
|
|
||||||
match serde_yaml::from_slice::<V>(&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<String> {
|
|
||||||
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())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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<u8>,
|
|
||||||
pub current_client_secret: bool,
|
|
||||||
pub current_client_secret_hash: Vec<u8>,
|
|
||||||
}
|
|
||||||
@@ -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<RouteItem> {
|
|
||||||
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<DeviceItem> {
|
|
||||||
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<String> =
|
|
||||||
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<String> = 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,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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<String> {
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
@@ -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<String>,
|
|
||||||
pub dns: Vec<String>,
|
|
||||||
pub in_ips: Vec<String>,
|
|
||||||
pub out_ips: Vec<String>,
|
|
||||||
pub password: Option<String>,
|
|
||||||
pub mtu: Option<u32>,
|
|
||||||
pub tcp: bool,
|
|
||||||
pub ip: Option<String>,
|
|
||||||
pub use_channel: String,
|
|
||||||
#[cfg(feature = "ip_proxy")]
|
|
||||||
pub no_proxy: bool,
|
|
||||||
pub server_encrypt: bool,
|
|
||||||
pub cipher_model: Option<String>,
|
|
||||||
pub finger: bool,
|
|
||||||
pub punch_model: String,
|
|
||||||
pub ports: Option<Vec<u16>>,
|
|
||||||
pub cmd: bool,
|
|
||||||
pub first_latency: bool,
|
|
||||||
pub device_name: Option<String>,
|
|
||||||
pub packet_loss: Option<f64>,
|
|
||||||
pub packet_delay: u32,
|
|
||||||
#[cfg(feature = "port_mapping")]
|
|
||||||
pub mapping: Vec<String>,
|
|
||||||
pub compressor: Option<String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
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::<FileConfig>(&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))
|
|
||||||
}
|
|
||||||
@@ -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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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<RouteItem>) {
|
|
||||||
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<DeviceItem>) {
|
|
||||||
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<DeviceItem>) {
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
use console::Style;
|
|
||||||
|
|
||||||
pub fn println_table(table: Vec<Vec<(String, Style)>>) {
|
|
||||||
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!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+14
-481
@@ -1,349 +1,29 @@
|
|||||||
use anyhow::anyhow;
|
use common::callback;
|
||||||
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 vnt::core::{Config, Vnt};
|
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;
|
mod root_check;
|
||||||
|
fn main() {
|
||||||
pub fn app_home() -> io::Result<PathBuf> {
|
let (config, _vnt_link_config, cmd) = match common::cli::parse_args_config() {
|
||||||
let root_path = match std::env::current_exe() {
|
Ok(rs) => {
|
||||||
Ok(path) => {
|
if let Some(rs) = rs {
|
||||||
if let Some(v) = path.as_path().parent() {
|
rs
|
||||||
v.to_path_buf()
|
|
||||||
} else {
|
} else {
|
||||||
log::warn!("current_exe parent none:{:?}", path);
|
return;
|
||||||
PathBuf::new()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
log::warn!("current_exe err:{:?}", e);
|
println!("{}", 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<String> = std::env::args().collect();
|
|
||||||
let program = args[0].clone();
|
|
||||||
let mut opts = Options::new();
|
|
||||||
opts.optopt("k", "", "组网标识", "<token>");
|
|
||||||
opts.optopt("n", "", "设备名称", "<name>");
|
|
||||||
opts.optopt("d", "", "设备标识", "<id>");
|
|
||||||
opts.optflag("c", "", "关闭交互式命令");
|
|
||||||
opts.optopt("s", "", "注册和中继服务器地址", "<server>");
|
|
||||||
opts.optmulti("e", "", "stun服务器", "<stun-server>");
|
|
||||||
opts.optflag("a", "", "使用tap模式");
|
|
||||||
opts.optopt("", "nic", "虚拟网卡名称,windows下使用tap则必填", "<tun0>");
|
|
||||||
opts.optmulti("i", "", "配置点对网(IP代理)入站时使用", "<in-ip>");
|
|
||||||
opts.optmulti("o", "", "配置点对网出站时使用", "<out-ip>");
|
|
||||||
opts.optopt("w", "", "客户端加密", "<password>");
|
|
||||||
opts.optflag("W", "", "服务端加密");
|
|
||||||
opts.optopt("u", "", "自定义mtu(默认为1430)", "<mtu>");
|
|
||||||
opts.optflag("", "tcp", "tcp");
|
|
||||||
opts.optopt("", "ip", "指定虚拟ip", "<ip>");
|
|
||||||
opts.optflag("", "relay", "仅使用服务器转发");
|
|
||||||
opts.optopt("", "par", "任务并行度(必须为正整数)", "<parallel>");
|
|
||||||
opts.optopt("", "model", "加密模式", "<model>");
|
|
||||||
opts.optflag("", "finger", "指纹校验");
|
|
||||||
opts.optopt("", "punch", "取值ipv4/ipv6", "<punch>");
|
|
||||||
opts.optopt("", "ports", "监听的端口", "<port,port>");
|
|
||||||
opts.optflag("", "cmd", "开启窗口输入");
|
|
||||||
opts.optflag("", "no-proxy", "关闭内置代理");
|
|
||||||
opts.optflag("", "first-latency", "优先延迟");
|
|
||||||
opts.optopt("", "use-channel", "使用通道 relay/p2p", "<use-channel>");
|
|
||||||
opts.optopt("", "packet-loss", "丢包率", "<packet-loss>");
|
|
||||||
opts.optopt("", "packet-delay", "延迟", "<packet-delay>");
|
|
||||||
opts.optmulti("", "dns", "dns", "<dns>");
|
|
||||||
opts.optmulti("", "mapping", "mapping", "<mapping>");
|
|
||||||
opts.optopt("f", "", "配置文件", "<conf>");
|
|
||||||
opts.optopt("", "compressor", "压缩算法", "<lz4>");
|
|
||||||
//"后台运行时,查看其他设备列表"
|
|
||||||
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());
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
if matches.opt_present("h") || args.len() == 1 {
|
main0(config, cmd)
|
||||||
print_usage(&program, opts);
|
}
|
||||||
return;
|
fn main0(config: Config, _show_cmd: bool) {
|
||||||
}
|
|
||||||
if !root_check::is_app_elevated() {
|
if !root_check::is_app_elevated() {
|
||||||
println!("Please run it with administrator or root privileges");
|
println!("Please run it with administrator or root privileges");
|
||||||
#[cfg(any(target_os = "linux", target_os = "macos"))]
|
#[cfg(any(target_os = "linux", target_os = "macos"))]
|
||||||
sudo::escalate_if_needed().unwrap();
|
sudo::escalate_if_needed().unwrap();
|
||||||
return;
|
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<String> = 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<String> = 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<String> = 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::<usize>("par").unwrap().unwrap_or(1);
|
|
||||||
if parallel == 0 {
|
|
||||||
println!("'--par {}' invalid", parallel);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let cipher_model = match matches.opt_get::<CipherModel>("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::<PunchModel>("punch")
|
|
||||||
.unwrap()
|
|
||||||
.unwrap_or(PunchModel::All);
|
|
||||||
let use_channel_type = matches
|
|
||||||
.opt_get::<UseChannelType>("use-channel")
|
|
||||||
.unwrap()
|
|
||||||
.unwrap_or_else(|| {
|
|
||||||
if relay {
|
|
||||||
UseChannelType::Relay
|
|
||||||
} else {
|
|
||||||
UseChannelType::All
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
let ports = matches
|
|
||||||
.opt_get::<String>("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::<f64>("packet-loss")
|
|
||||||
.expect("--packet-loss");
|
|
||||||
let packet_delay = matches
|
|
||||||
.opt_get::<u32>("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")]
|
#[cfg(feature = "port_mapping")]
|
||||||
for (is_tcp, addr, dest) in config.port_mapping_list.iter() {
|
for (is_tcp, addr, dest) in config.port_mapping_list.iter() {
|
||||||
if *is_tcp {
|
if *is_tcp {
|
||||||
@@ -388,7 +68,7 @@ fn main0(config: Config, _show_cmd: bool) {
|
|||||||
std::thread::Builder::new()
|
std::thread::Builder::new()
|
||||||
.name("CommandServer".into())
|
.name("CommandServer".into())
|
||||||
.spawn(move || {
|
.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);
|
log::warn!("cmd:{:?}", e);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -398,9 +78,9 @@ fn main0(config: Config, _show_cmd: bool) {
|
|||||||
loop {
|
loop {
|
||||||
cmd.clear();
|
cmd.clear();
|
||||||
println!("======== input:list,info,route,all,stop ========");
|
println!("======== input:list,info,route,all,stop ========");
|
||||||
match io::stdin().read_line(&mut cmd) {
|
match std::io::stdin().read_line(&mut cmd) {
|
||||||
Ok(len) => {
|
Ok(len) => {
|
||||||
if !command(&cmd[..len], &vnt_util) {
|
if !common::command::command_str(&cmd[..len], &vnt_util) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -415,150 +95,3 @@ fn main0(config: Config, _show_cmd: bool) {
|
|||||||
|
|
||||||
vnt_util.wait()
|
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 <token> {}",
|
|
||||||
green("使用相同的token,就能组建一个局域网络".to_string())
|
|
||||||
);
|
|
||||||
println!(" -n <name> 给设备一个名字,便于区分不同设备,默认使用系统版本");
|
|
||||||
println!(" -d <id> 设备唯一标识符,不使用--ip参数时,服务端凭此参数分配虚拟ip,注意不能重复");
|
|
||||||
println!(" -s <server> 注册和中继服务器地址,以'TXT:'开头表示解析TXT记录");
|
|
||||||
println!(" -e <stun-server> 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 <in-ip> 配置点对网(IP代理)时使用,-i 192.168.0.0/24,10.26.0.3表示允许接收网段192.168.0.0/24的数据");
|
|
||||||
println!(" 并转发到10.26.0.3,可指定多个网段");
|
|
||||||
println!(" -o <out-ip> 配置点对网时使用,-o 192.168.0.0/24表示允许将数据转发到192.168.0.0/24,可指定多个网段");
|
|
||||||
|
|
||||||
println!(" -w <password> 使用该密码生成的密钥对客户端数据进行加密,并且服务端无法解密,使用相同密码的客户端才能通信");
|
|
||||||
#[cfg(feature = "server_encrypt")]
|
|
||||||
println!(" -W 加密当前客户端和服务端通信的数据,请留意服务端指纹是否正确");
|
|
||||||
println!(" -u <mtu> 自定义mtu(不加密默认为1450,加密默认为1410)");
|
|
||||||
#[cfg(feature = "file_config")]
|
|
||||||
println!(" -f <conf_file> 读取配置文件中的配置");
|
|
||||||
|
|
||||||
println!(" --tcp 和服务端使用tcp通信,默认使用udp,遇到udp qos时可指定使用tcp");
|
|
||||||
println!(" --ip <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 <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 <punch> 取值ipv4/ipv6/all,ipv4表示仅使用ipv4打洞");
|
|
||||||
println!(" --ports <port,port> 取值0~65535,指定本地监听的一组端口,默认监听两个随机端口,使用过多端口会增加网络负担");
|
|
||||||
#[cfg(feature = "command")]
|
|
||||||
println!(" --cmd 开启交互式命令,使用此参数开启控制台输入");
|
|
||||||
#[cfg(feature = "ip_proxy")]
|
|
||||||
println!(" --no-proxy 关闭内置代理,如需点对网则需要配置网卡NAT转发");
|
|
||||||
println!(" --first-latency 优先低延迟的通道,默认情况优先使用p2p通道");
|
|
||||||
println!(" --use-channel <p2p> 使用通道 relay/p2p/all,默认两者都使用");
|
|
||||||
println!(" --nic <tun0> 指定虚拟网卡名称");
|
|
||||||
println!(" --packet-loss <0> 模拟丢包,取值0~1之间的小数,程序会按设定的概率主动丢包,可用于模拟弱网");
|
|
||||||
println!(
|
|
||||||
" --packet-delay <0> 模拟延迟,整数,单位毫秒(ms),程序会按设定的值延迟发包,可用于模拟弱网"
|
|
||||||
);
|
|
||||||
println!(" --dns <host:port> DNS服务器地址,可使用多个dns,不指定时使用系统解析");
|
|
||||||
#[cfg(feature = "port_mapping")]
|
|
||||||
println!(" --mapping <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> 启用压缩,可选值lz4/zstd<,level>,level为压缩级别,例如 --compressor lz4 或--compressor zstd,10");
|
|
||||||
#[cfg(feature = "lz4")]
|
|
||||||
#[cfg(not(feature = "zstd"))]
|
|
||||||
println!(" --compressor <lz4> 启用压缩,可选值lz4,例如 --compressor lz4");
|
|
||||||
#[cfg(feature = "zstd")]
|
|
||||||
#[cfg(not(feature = "lz4"))]
|
|
||||||
println!(" --compressor <zstd> 启用压缩,可选值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()
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user