[mio] 适配新版vnt

This commit is contained in:
lubeilin
2024-02-29 22:29:14 +08:00
parent e3e2a262e4
commit ceadadee68
9 changed files with 195 additions and 249 deletions
+2 -3
View File
@@ -8,13 +8,12 @@ edition = "2021"
[dependencies] [dependencies]
vnt = { path = "../vnt", package = "vnt",default-features = false } vnt = { path = "../vnt", package = "vnt",default-features = false }
common = { path = "../common" } common = { path = "../common" }
tokio = { version = "1.32.0", features = ["full"] }
getopts = "0.2.21" getopts = "0.2.21"
console = "0.15.2" console = "0.15.2"
os_info = "3.7.0" os_info = "3.7.0"
serde = "1.0" serde = "1.0"
serde_json = "1.0.94" #serde_json = "1.0.94"
serde_yaml = "0.8.26" serde_yaml = "0.9.32"
log = "0.4.17" log = "0.4.17"
log4rs = "1.2.0" log4rs = "1.2.0"
[dependencies.uuid] [dependencies.uuid]
+36
View File
@@ -0,0 +1,36 @@
use std::process;
use vnt::handle::callback::ConnectInfo;
use vnt::{DeviceInfo, ErrorInfo, HandshakeInfo, RegisterInfo, VntCallback};
#[derive(Clone)]
pub struct VntHandler {}
impl VntCallback for VntHandler {
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 {}", info);
true
}
fn error(&self, info: ErrorInfo) {
println!("error {}", info);
}
fn stop(&self) {
println!("stopped");
process::exit(0)
}
}
+18 -29
View File
@@ -1,3 +1,4 @@
use serde::Deserialize;
use std::io; use std::io;
use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4, UdpSocket}; use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4, UdpSocket};
use std::str::FromStr; use std::str::FromStr;
@@ -6,6 +7,7 @@ use std::time::Duration;
use crate::command::entity::{DeviceItem, Info, RouteItem}; use crate::command::entity::{DeviceItem, Info, RouteItem};
pub struct CommandClient { pub struct CommandClient {
buf: [u8; 10240],
udp: UdpSocket, udp: UdpSocket,
} }
@@ -32,43 +34,30 @@ impl CommandClient {
Ipv4Addr::new(127, 0, 0, 1), Ipv4Addr::new(127, 0, 0, 1),
port, port,
)))?; )))?;
Ok(Self { udp }) Ok(Self {
udp,
buf: [0; 10240],
})
} }
} }
impl CommandClient { impl CommandClient {
pub fn list(&self) -> io::Result<Vec<DeviceItem>> { pub fn list(&mut self) -> io::Result<Vec<DeviceItem>> {
self.udp.send(b"list")?; self.send_cmd(b"list")
let mut buf = [0; 10240];
let len = self.udp.recv(&mut buf)?;
match serde_json::from_slice::<Vec<DeviceItem>>(&buf[..len]) {
Ok(val) => Ok(val),
Err(e) => {
log::error!("{:?}", e);
Err(io::Error::new(io::ErrorKind::Other, "data error"))
}
}
} }
pub fn route(&self) -> io::Result<Vec<RouteItem>> { pub fn route(&mut self) -> io::Result<Vec<RouteItem>> {
self.udp.send(b"route")?; self.send_cmd(b"route")
let mut buf = [0; 10240];
let len = self.udp.recv(&mut buf)?;
match serde_json::from_slice::<Vec<RouteItem>>(&buf[..len]) {
Ok(val) => Ok(val),
Err(e) => {
log::error!("{:?}", e);
Err(io::Error::new(io::ErrorKind::Other, "data error"))
}
}
} }
pub fn info(&self) -> io::Result<Info> { pub fn info(&mut self) -> io::Result<Info> {
self.udp.send(b"info")?; self.send_cmd(b"info")
let mut buf = [0; 10240]; }
let len = self.udp.recv(&mut buf)?; fn send_cmd<'a, V: Deserialize<'a>>(&'a mut self, cmd: &[u8]) -> io::Result<V> {
match serde_json::from_slice::<Info>(&buf[..len]) { 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), Ok(val) => Ok(val),
Err(e) => { Err(e) => {
log::error!("{:?},{:?}", &buf[..len], e); log::error!("{:?},{:?}", &self.buf[..len], e);
Err(io::Error::new(io::ErrorKind::Other, "data error")) Err(io::Error::new(io::ErrorKind::Other, "data error"))
} }
} }
+2
View File
@@ -11,6 +11,8 @@ pub struct Info {
pub public_ips: String, pub public_ips: String,
pub local_addr: String, pub local_addr: String,
pub ipv6_addr: String, pub ipv6_addr: String,
pub up: u64,
pub down: u64,
} }
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug)]
+36 -23
View File
@@ -22,7 +22,7 @@ pub fn command(cmd: CommandEnum) {
} }
fn command_(cmd: CommandEnum) -> io::Result<()> { fn command_(cmd: CommandEnum) -> io::Result<()> {
let command_client = client::CommandClient::new()?; let mut command_client = client::CommandClient::new()?;
match cmd { match cmd {
CommandEnum::Route => { CommandEnum::Route => {
let list = command_client.route()?; let list = command_client.route()?;
@@ -50,25 +50,27 @@ fn command_(cmd: CommandEnum) -> io::Result<()> {
pub fn command_route(vnt: &Vnt) -> Vec<RouteItem> { pub fn command_route(vnt: &Vnt) -> Vec<RouteItem> {
let route_table = vnt.route_table(); let route_table = vnt.route_table();
let mut route_list = Vec::with_capacity(route_table.len()); let mut route_list = Vec::with_capacity(route_table.len());
for (destination, route) in route_table { for (destination, routes) in route_table {
let next_hop = vnt for route in routes {
.route_key(&route.route_key()) let next_hop = vnt
.map_or(String::new(), |v| v.to_string()); .route_key(&route.route_key())
let metric = route.metric.to_string(); .map_or(String::new(), |v| v.to_string());
let rt = if route.rt < 0 { let metric = route.metric.to_string();
"".to_string() let rt = if route.rt < 0 {
} else { "".to_string()
route.rt.to_string() } else {
}; route.rt.to_string()
let interface = route.addr.to_string(); };
let item = RouteItem { let interface = route.addr.to_string();
destination: destination.to_string(), let item = RouteItem {
next_hop, destination: destination.to_string(),
metric, next_hop,
rt, metric,
interface, rt,
}; interface,
route_list.push(item); };
route_list.push(item);
}
} }
route_list route_list
} }
@@ -111,10 +113,17 @@ pub fn command_list(vnt: &Vnt) -> Vec<DeviceItem> {
} else { } else {
"p2p" "p2p"
} }
} else if route.addr == info.connect_server {
"server-relay"
} else { } else {
"client-relay" 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(); .to_string();
let rt = if route.rt < 0 { let rt = if route.rt < 0 {
@@ -166,6 +175,8 @@ pub fn command_info(vnt: &Vnt) -> Info {
.ipv6() .ipv6()
.map(|v| v.to_string()) .map(|v| v.to_string())
.unwrap_or("None".to_string()); .unwrap_or("None".to_string());
let up = vnt.up_stream();
let down = vnt.down_stream();
Info { Info {
name, name,
virtual_ip, virtual_ip,
@@ -177,5 +188,7 @@ pub fn command_info(vnt: &Vnt) -> Info {
public_ips, public_ips,
local_addr, local_addr,
ipv6_addr, ipv6_addr,
up,
down,
} }
} }
+23 -29
View File
@@ -1,6 +1,6 @@
use std::io; use std::io;
use std::io::Write; use std::io::Write;
use tokio::net::UdpSocket; use std::net::UdpSocket;
use vnt::core::Vnt; use vnt::core::Vnt;
@@ -13,26 +13,26 @@ impl CommandServer {
} }
impl CommandServer { impl CommandServer {
pub async fn start(self, vnt: Vnt) -> io::Result<()> { pub fn start(self, vnt: Vnt) -> io::Result<()> {
let udp = if let Ok(udp) = UdpSocket::bind("127.0.0.1:39271").await { let udp = if let Ok(udp) = UdpSocket::bind("127.0.0.1:39271") {
udp udp
} else { } else {
UdpSocket::bind("127.0.0.1:0").await? UdpSocket::bind("127.0.0.1:0")?
}; };
let path_buf = crate::app_home()?.join("command-port");
let mut file = std::fs::File::create(path_buf)?;
let addr = udp.local_addr()?; let addr = udp.local_addr()?;
file.write_all(addr.port().to_string().as_bytes())?;
file.sync_all()?;
log::info!("启动后台cmd:{:?}", addr); log::info!("启动后台cmd:{:?}", addr);
if let Err(e) = save_port(addr.port()) {
log::warn!("保存后台命令端口失败:{:?}", e);
}
let mut buf = [0u8; 64]; let mut buf = [0u8; 64];
loop { loop {
let (len, addr) = udp.recv_from(&mut buf).await?; let (len, addr) = udp.recv_from(&mut buf)?;
match std::str::from_utf8(&buf[..len]) { match std::str::from_utf8(&buf[..len]) {
Ok(cmd) => { Ok(cmd) => {
log::info!("收到cmd={:?}", cmd); log::info!("收到cmd={:?}", cmd);
if let Ok(out) = command(cmd, &vnt) { if let Ok(out) = command(cmd, &vnt) {
if let Err(e) = udp.send_to(out.as_bytes(), addr).await { if let Err(e) = udp.send_to(out.as_bytes(), addr) {
log::warn!("cmd={},err={:?}", cmd, e); log::warn!("cmd={},err={:?}", cmd, e);
} }
if "stopped" == &out { if "stopped" == &out {
@@ -48,29 +48,23 @@ impl CommandServer {
Ok(()) 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> { fn command(cmd: &str, vnt: &Vnt) -> io::Result<String> {
let out_str = match cmd { let out_str = match cmd {
"route" => match serde_json::to_string(&crate::command::command_route(vnt)) { "route" => serde_yaml::to_string(&crate::command::command_route(vnt))
Ok(str) => str, .unwrap_or_else(|e| format!("error {:?}", e)),
Err(e) => { "list" => serde_yaml::to_string(&crate::command::command_list(vnt))
format!("{:?}", e) .unwrap_or_else(|e| format!("error {:?}", e)),
} "info" => serde_yaml::to_string(&crate::command::command_info(vnt))
}, .unwrap_or_else(|e| format!("error {:?}", e)),
"list" => match serde_json::to_string(&crate::command::command_list(vnt)) {
Ok(str) => str,
Err(e) => {
format!("{:?}", e)
}
},
"info" => match serde_json::to_string(&crate::command::command_info(vnt)) {
Ok(str) => str,
Err(e) => {
format!("{:?}", e)
}
},
"stop" => { "stop" => {
vnt.stop()?; vnt.stop();
"stopped".to_string() "stopped".to_string()
} }
_ => { _ => {
+12 -7
View File
@@ -11,6 +11,7 @@ use vnt::core::Config;
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug)]
#[serde(default)] #[serde(default)]
pub struct FileConfig { pub struct FileConfig {
#[cfg(any(target_os = "windows", target_os = "linux"))]
pub tap: bool, pub tap: bool,
pub token: String, pub token: String,
pub device_id: String, pub device_id: String,
@@ -20,25 +21,27 @@ pub struct FileConfig {
pub in_ips: Vec<String>, pub in_ips: Vec<String>,
pub out_ips: Vec<String>, pub out_ips: Vec<String>,
pub password: Option<String>, pub password: Option<String>,
pub simulate_multicast: bool, pub mtu: Option<u32>,
pub mtu: Option<u16>,
pub tcp: bool, pub tcp: bool,
pub ip: Option<String>, pub ip: Option<String>,
pub relay: bool, pub relay: bool,
#[cfg(feature = "ip_proxy")]
pub no_proxy: bool, pub no_proxy: bool,
pub server_encrypt: bool, pub server_encrypt: bool,
pub parallel: usize, pub parallel: usize,
pub cipher_model: String, pub cipher_model: String,
pub finger: bool, pub finger: bool,
pub punch_model: String, pub punch_model: String,
pub port: u16, pub ports: Option<Vec<u16>>,
pub cmd: bool, pub cmd: bool,
pub first_latency: bool, pub first_latency: bool,
pub device_name: Option<String>,
} }
impl Default for FileConfig { impl Default for FileConfig {
fn default() -> Self { fn default() -> Self {
Self { Self {
#[cfg(any(target_os = "windows", target_os = "linux"))]
tap: false, tap: false,
token: "".to_string(), token: "".to_string(),
device_id: get_device_id(), device_id: get_device_id(),
@@ -52,20 +55,21 @@ impl Default for FileConfig {
in_ips: vec![], in_ips: vec![],
out_ips: vec![], out_ips: vec![],
password: None, password: None,
simulate_multicast: false,
mtu: None, mtu: None,
tcp: false, tcp: false,
ip: None, ip: None,
relay: false, relay: false,
#[cfg(feature = "ip_proxy")]
no_proxy: false, no_proxy: false,
server_encrypt: false, server_encrypt: false,
parallel: 1, parallel: 1,
cipher_model: "aes_gcm".to_string(), cipher_model: "aes_gcm".to_string(),
finger: false, finger: false,
punch_model: "".to_string(), punch_model: "".to_string(),
port: 0, ports: None,
cmd: false, cmd: false,
first_latency: false, first_latency: false,
device_name: None,
} }
} }
} }
@@ -134,6 +138,7 @@ pub fn read_config(file_path: &str) -> io::Result<(Config, bool)> {
let punch_model = PunchModel::from_str(&file_conf.punch_model) let punch_model = PunchModel::from_str(&file_conf.punch_model)
.map_err(|e| io::Error::new(io::ErrorKind::Other, e))?; .map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
let config = Config::new( let config = Config::new(
#[cfg(any(target_os = "windows", target_os = "linux"))]
file_conf.tap, file_conf.tap,
file_conf.token, file_conf.token,
file_conf.device_id, file_conf.device_id,
@@ -144,7 +149,6 @@ pub fn read_config(file_path: &str) -> io::Result<(Config, bool)> {
in_ips, in_ips,
out_ips, out_ips,
file_conf.password, file_conf.password,
file_conf.simulate_multicast,
file_conf.mtu, file_conf.mtu,
file_conf.tcp, file_conf.tcp,
virtual_ip, virtual_ip,
@@ -156,8 +160,9 @@ pub fn read_config(file_path: &str) -> io::Result<(Config, bool)> {
cipher_model, cipher_model,
file_conf.finger, file_conf.finger,
punch_model, punch_model,
file_conf.port, file_conf.ports,
file_conf.first_latency, file_conf.first_latency,
file_conf.device_name,
) )
.unwrap(); .unwrap();
Ok((config, file_conf.cmd)) Ok((config, file_conf.cmd))
+24
View File
@@ -18,6 +18,30 @@ pub fn console_info(status: Info) {
println!("Public ips: {}", style(status.public_ips).green()); println!("Public ips: {}", style(status.public_ips).green());
println!("Local addr: {}", style(status.local_addr).green()); println!("Local addr: {}", style(status.local_addr).green());
println!("IPv6: {}", style(status.ipv6_addr).green()); println!("IPv6: {}", style(status.ipv6_addr).green());
println!("Up: {}", style(convert(status.up)).green());
println!("Down: {}", style(convert(status.down)).green());
}
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>) { pub fn console_route_table(mut list: Vec<RouteItem>) {
+42 -158
View File
@@ -1,19 +1,15 @@
use std::io;
use std::net::{Ipv4Addr, ToSocketAddrs}; use std::net::{Ipv4Addr, ToSocketAddrs};
use std::path::PathBuf; use std::path::PathBuf;
use std::str::FromStr; use std::str::FromStr;
use std::{io, thread};
use console::style; use console::style;
use getopts::Options; use getopts::Options;
use tokio::io::{AsyncBufReadExt, BufReader};
use tokio::signal;
use common::args_parse::{ips_parse, out_ips_parse}; use common::args_parse::{ips_parse, out_ips_parse};
use vnt::channel::punch::PunchModel; use vnt::channel::punch::PunchModel;
use vnt::cipher::CipherModel; use vnt::cipher::CipherModel;
use vnt::core::{Config, Vnt, VntUtil}; use vnt::core::{Config, Vnt};
use vnt::handle::handshake_handler::HandshakeEnum;
use vnt::handle::registration_handler::ReqEnum;
mod command; mod command;
mod config; mod config;
@@ -44,21 +40,20 @@ fn main() {
opts.optopt("s", "", "注册和中继服务器地址", "<server>"); opts.optopt("s", "", "注册和中继服务器地址", "<server>");
opts.optmulti("e", "", "stun服务器", "<stun-server>"); opts.optmulti("e", "", "stun服务器", "<stun-server>");
opts.optflag("a", "", "使用tap模式"); opts.optflag("a", "", "使用tap模式");
opts.optopt("", "nic", "虚拟网卡名称,windows下使用tap则必填", "<tun0>");
opts.optmulti("i", "", "配置点对网(IP代理)入站时使用", "<in-ip>"); opts.optmulti("i", "", "配置点对网(IP代理)入站时使用", "<in-ip>");
opts.optmulti("o", "", "配置点对网出站时使用", "<out-ip>"); opts.optmulti("o", "", "配置点对网出站时使用", "<out-ip>");
opts.optopt("w", "", "客户端加密", "<password>"); opts.optopt("w", "", "客户端加密", "<password>");
opts.optflag("W", "", "服务端加密"); opts.optflag("W", "", "服务端加密");
opts.optflag("m", "", "模拟组播");
opts.optopt("u", "", "自定义mtu(默认为1430)", "<mtu>"); opts.optopt("u", "", "自定义mtu(默认为1430)", "<mtu>");
opts.optflag("", "tcp", "tcp"); opts.optflag("", "tcp", "tcp");
opts.optopt("", "ip", "指定虚拟ip", "<ip>"); opts.optopt("", "ip", "指定虚拟ip", "<ip>");
opts.optflag("", "relay", "仅使用服务器转发"); opts.optflag("", "relay", "仅使用服务器转发");
opts.optopt("", "par", "任务并行度(必须为正整数)", "<parallel>"); opts.optopt("", "par", "任务并行度(必须为正整数)", "<parallel>");
opts.optopt("", "thread", "线程数(必须为正整数)", "<thread>");
opts.optopt("", "model", "加密模式", "<model>"); opts.optopt("", "model", "加密模式", "<model>");
opts.optflag("", "finger", "指纹校验"); opts.optflag("", "finger", "指纹校验");
opts.optopt("", "punch", "取值ipv4/ipv6", "<punch>"); opts.optopt("", "punch", "取值ipv4/ipv6", "<punch>");
opts.optopt("", "port", "监听的端口", "<port>"); opts.optopt("", "ports", "监听的端口", "<port,port>");
opts.optflag("", "cmd", "开启窗口输入"); opts.optflag("", "cmd", "开启窗口输入");
opts.optflag("", "no-proxy", "关闭内置代理"); opts.optflag("", "no-proxy", "关闭内置代理");
opts.optflag("", "first-latency", "优先延迟"); opts.optflag("", "first-latency", "优先延迟");
@@ -119,7 +114,9 @@ fn main() {
println!("parameter -k not found ."); println!("parameter -k not found .");
return; return;
} }
#[cfg(any(target_os = "windows", target_os = "linux"))]
let tap = matches.opt_present("a"); let tap = matches.opt_present("a");
let device_name = matches.opt_str("nic");
let token: String = matches.opt_get("k").unwrap().unwrap(); let token: String = matches.opt_get("k").unwrap().unwrap();
let device_id = matches.opt_get_default("d", String::new()).unwrap(); let device_id = matches.opt_get_default("d", String::new()).unwrap();
let device_id = if device_id.is_empty() { let device_id = if device_id.is_empty() {
@@ -190,10 +187,9 @@ fn main() {
return; return;
} }
} }
let simulate_multicast = matches.opt_present("m");
let mtu: Option<String> = matches.opt_get("u").unwrap(); let mtu: Option<String> = matches.opt_get("u").unwrap();
let mtu = if let Some(mtu) = mtu { let mtu = if let Some(mtu) = mtu {
match u16::from_str(&mtu) { match u32::from_str(&mtu) {
Ok(mtu) => Some(mtu), Ok(mtu) => Some(mtu),
Err(e) => { Err(e) => {
print_usage(&program, opts); print_usage(&program, opts);
@@ -260,12 +256,17 @@ fn main() {
.opt_get::<PunchModel>("punch") .opt_get::<PunchModel>("punch")
.unwrap() .unwrap()
.unwrap_or(PunchModel::All); .unwrap_or(PunchModel::All);
let port = matches.opt_get::<u16>("port").unwrap_or(None).unwrap_or(0); 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"); let cmd = matches.opt_present("cmd");
#[cfg(feature = "ip_proxy")] #[cfg(feature = "ip_proxy")]
let no_proxy = matches.opt_present("no-proxy"); let no_proxy = matches.opt_present("no-proxy");
let first_latency = matches.opt_present("first-latency"); let first_latency = matches.opt_present("first-latency");
let config = Config::new( let config = Config::new(
#[cfg(any(target_os = "windows", target_os = "linux"))]
tap, tap,
token, token,
device_id, device_id,
@@ -276,7 +277,6 @@ fn main() {
in_ip, in_ip,
out_ip, out_ip,
password, password,
simulate_multicast,
mtu, mtu,
tcp_channel, tcp_channel,
virtual_ip, virtual_ip,
@@ -288,8 +288,9 @@ fn main() {
cipher_model, cipher_model,
finger, finger,
punch_model, punch_model,
port, ports,
first_latency, first_latency,
device_name,
) )
.unwrap(); .unwrap();
(config, cmd) (config, cmd)
@@ -300,151 +301,35 @@ fn main() {
std::process::exit(0); std::process::exit(0);
} }
#[tokio::main] mod callback;
async fn main0(config: Config, show_cmd: bool) {
let server_encrypt = config.server_encrypt; fn main0(config: Config, show_cmd: bool) {
let mut vnt_util = VntUtil::new(config).unwrap(); let vnt_util = Vnt::new(config, callback::VntHandler {}).unwrap();
let mut conn_count = 0; let vnt_c = vnt_util.clone();
let response = loop { thread::spawn(move || {
if conn_count > 0 { if let Err(e) = command::server::CommandServer::new().start(vnt_c) {
tokio::time::sleep(std::time::Duration::from_secs(2)).await;
}
conn_count += 1;
if let Err(e) = vnt_util.connect() {
println!("connect server failed {}", e);
return;
}
match vnt_util.handshake() {
Ok(response) => {
if server_encrypt {
let finger = response.unwrap().finger().unwrap();
println!("{}{}", green("server fingerprint:".to_string()), finger);
match vnt_util.secret_handshake() {
Ok(_) => {}
Err(e) => {
match e {
HandshakeEnum::NotSecret => {}
HandshakeEnum::KeyError => {}
HandshakeEnum::Timeout => {
println!("handshake timeout")
}
HandshakeEnum::ServerError(str) => {
println!("error:{}", str);
}
HandshakeEnum::Other(str) => {
println!("error:{}", str);
}
}
continue;
}
}
}
match vnt_util.register() {
Ok(response) => {
break response;
}
Err(e) => match e {
ReqEnum::TokenError => {
println!("token error");
return;
}
ReqEnum::AddressExhausted => {
println!("address exhausted");
return;
}
ReqEnum::Timeout => {
println!("timeout...");
}
ReqEnum::ServerError(str) => {
println!("error:{}", str);
}
ReqEnum::Other(str) => {
println!("error:{}", str);
}
ReqEnum::IpAlreadyExists => {
println!("ip already exists");
return;
}
ReqEnum::InvalidIp => {
println!("invalid ip");
return;
}
},
}
}
Err(e) => match e {
HandshakeEnum::NotSecret => {
println!("The server does not support encryption");
return;
}
HandshakeEnum::KeyError => {}
HandshakeEnum::Timeout => {
println!("handshake timeout")
}
HandshakeEnum::ServerError(str) => {
println!("error:{}", str);
}
HandshakeEnum::Other(str) => {
println!("error:{}", str);
}
},
}
};
println!(" ====== Connect Successfully ====== ");
println!("virtual_gateway:{}", response.virtual_gateway);
println!("virtual_ip:{}", green(response.virtual_ip.to_string()));
let driver_info = vnt_util.create_iface().unwrap();
println!(" ====== Create Network Interface Successfully ====== ");
println!("name:{}", driver_info.name);
println!("version:{}", driver_info.version);
let mut vnt = match vnt_util.build().await {
Ok(vnt) => vnt,
Err(e) => {
println!("error:{}", e);
return;
}
};
println!(" ====== Start Successfully ====== ");
let vnt_c = vnt.clone();
tokio::spawn(async {
if let Err(e) = command::server::CommandServer::new().start(vnt_c).await {
log::warn!("cmd:{:?}", e); log::warn!("cmd:{:?}", e);
println!("command error :{}", e);
} }
}); });
if show_cmd { if show_cmd {
let stdin = tokio::io::stdin();
let mut cmd = String::new(); let mut cmd = String::new();
let mut reader = BufReader::new(stdin);
loop { loop {
cmd.clear(); cmd.clear();
println!("input:list,info,route,all,stop"); println!("======== input:list,info,route,all,stop ========");
tokio::select! { match io::stdin().read_line(&mut cmd) {
_ = vnt.wait_stop()=>{ Ok(len) => {
return; if !command(&cmd[..len], &vnt_util) {
} break;
_ = signal::ctrl_c()=>{
let _ = vnt.stop();
vnt.wait_stop_ms(std::time::Duration::from_secs(3)).await;
std::process::exit(0);
}
rs = reader.read_line(&mut cmd)=>{
match rs {
Ok(len) => {
if !command(&cmd[..len],&vnt){
break;
}
}
Err(e) => {
println!("input err:{}",e);
break;
}
} }
} }
Err(e) => {
println!("input err:{}", e);
break;
}
} }
} }
} }
vnt.wait_stop().await; vnt_util.wait()
} }
fn command(cmd: &str, vnt: &Vnt) -> bool { fn command(cmd: &str, vnt: &Vnt) -> bool {
@@ -487,15 +372,14 @@ fn print_usage(program: &str, _opts: Options) {
green("使用相同的token,就能组建一个局域网络".to_string()) green("使用相同的token,就能组建一个局域网络".to_string())
); );
println!(" -n <name> 给设备一个名字,便于区分不同设备,默认使用系统版本"); println!(" -n <name> 给设备一个名字,便于区分不同设备,默认使用系统版本");
println!(" -d <id> 设备唯一标识符,不使用--ip参数时,服务端凭此参数分配虚拟ip"); println!(" -d <id> 设备唯一标识符,不使用--ip参数时,服务端凭此参数分配虚拟ip,注意不能重复");
println!(" -s <server> 注册和中继服务器地址"); println!(" -s <server> 注册和中继服务器地址");
println!(" -e <stun-server> stun服务器,用于探测NAT类型,可多次指定,如-e addr1 -e addr2"); println!(" -e <stun-server> stun服务器,用于探测NAT类型,可多次指定,如-e addr1 -e addr2");
println!(" -a 使用tap模式,默认使用tun模式"); println!(" -a 使用tap模式,默认使用tun模式");
println!(" -i <in-ip> 配置点对网(IP代理)时使用,-i 192.168.0.0/24,10.26.0.3表示允许接收网段192.168.0.0/24的数据"); 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!(" 并转发到10.26.0.3,可指定多个网段");
#[cfg(feature = "ip_proxy")]
println!(" -o <out-ip> 配置点对网时使用,-o 192.168.0.0/24表示允许将数据转发到192.168.0.0/24,可指定多个网段"); println!(" -o <out-ip> 配置点对网时使用,-o 192.168.0.0/24表示允许将数据转发到192.168.0.0/24,可指定多个网段");
#[cfg(not(feature = "ip_proxy"))]
println!(" 注意需要在系统配置ip转发才可正常使用");
#[cfg(not(any( #[cfg(not(any(
feature = "aes_gcm", feature = "aes_gcm",
feature = "server_encrypt", feature = "server_encrypt",
@@ -525,7 +409,6 @@ fn print_usage(program: &str, _opts: Options) {
} }
#[cfg(feature = "server_encrypt")] #[cfg(feature = "server_encrypt")]
println!(" -W 加密当前客户端和服务端通信的数据,请留意服务端指纹是否正确"); println!(" -W 加密当前客户端和服务端通信的数据,请留意服务端指纹是否正确");
println!(" -m 模拟组播,默认情况下组播数据会被当作广播发送,开启后会模拟真实组播的数据发送");
println!(" -u <mtu> 自定义mtu(不加密默认为1450,加密默认为1410)"); println!(" -u <mtu> 自定义mtu(不加密默认为1450,加密默认为1410)");
println!(" -f <conf_file> 读取配置文件中的配置"); println!(" -f <conf_file> 读取配置文件中的配置");
@@ -535,19 +418,20 @@ fn print_usage(program: &str, _opts: Options) {
println!(" --par <parallel> 任务并行度(必须为正整数),默认值为1"); println!(" --par <parallel> 任务并行度(必须为正整数),默认值为1");
if !enums.is_empty() { if !enums.is_empty() {
println!( println!(
" --model <model> 加密模式(默认aes_gcm)可选值{}", " --model <model> 加密模式(默认aes_gcm),可选值{}",
&enums[1..] &enums[1..]
); );
} }
if !enums.is_empty() { if !enums.is_empty() {
println!(" --finger 增加数据指纹校验可增加安全性如果服务端开启指纹校验则客户端也必须开启"); println!(" --finger 增加数据指纹校验,可增加安全性,如果服务端开启指纹校验,则客户端也必须开启");
} }
println!(" --punch <punch> 取值ipv4/ipv6ipv4表示仅使用ipv4打洞"); println!(" --punch <punch> 取值ipv4/ipv6,ipv4表示仅使用ipv4打洞");
println!(" --port <port> 取值0~65535指定本地监听的端口默认取随机端口"); println!(" --ports <port,port> 取值0~65535,指定本地监听的一组端口,默认监听两个随机端口,使用过多端口会增加网络负担");
println!(" --cmd 开启交互式命令使用此参数开启控制台输入"); println!(" --cmd 开启交互式命令,使用此参数开启控制台输入");
#[cfg(feature = "ip_proxy")] #[cfg(feature = "ip_proxy")]
println!(" --no-proxy 关闭内置代理如需点对网则需要配置网卡NAT转发"); println!(" --no-proxy 关闭内置代理,如需点对网则需要配置网卡NAT转发");
println!(" --first-latency 优先低延迟的通道默认情况优先使用p2p通道"); println!(" --first-latency 优先低延迟的通道,默认情况优先使用p2p通道");
println!(" --nic <tun0> 虚拟网卡名称,windows下使用tap模式则必须指定此参数");
println!(); println!();
println!( println!(