支持读取配置文件和自定义端口

This commit is contained in:
lubeilin
2023-09-26 21:53:41 +08:00
parent ca4e8d14f0
commit 3d243fb01d
4 changed files with 327 additions and 144 deletions
+171
View File
@@ -0,0 +1,171 @@
use std::io;
use std::net::{Ipv4Addr, ToSocketAddrs};
use std::str::FromStr;
use serde::{Deserialize, Serialize};
use vnt::channel::punch::PunchModel;
use vnt::cipher::CipherModel;
use vnt::core::Config;
#[derive(Serialize, Deserialize, Debug)]
#[serde(default)]
pub struct FileConfig {
pub tap: bool,
pub token: String,
pub device_id: String,
pub name: String,
pub server_address: String,
pub stun_server: Vec<String>,
pub in_ips: Vec<String>,
pub out_ips: Vec<String>,
pub password: Option<String>,
pub simulate_multicast: bool,
pub mtu: Option<u16>,
pub tcp: bool,
pub ip: Option<String>,
pub relay: bool,
pub server_encrypt: bool,
pub parallel: usize,
pub cipher_model: String,
pub finger: bool,
pub punch_model: String,
pub port: u16,
pub cmd: bool,
}
impl Default for FileConfig {
fn default() -> Self {
Self {
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.qq.com:3478".to_string(),
],
in_ips: vec![],
out_ips: vec![],
password: None,
simulate_multicast: false,
mtu: None,
tcp: false,
ip: None,
relay: false,
server_encrypt: false,
parallel: 1,
cipher_model: "aes_gcm".to_string(),
finger: false,
punch_model: "".to_string(),
port: 0,
cmd: false,
}
}
}
pub fn read_config(file_path: &str) -> io::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(io::Error::new(io::ErrorKind::Other, format!("{}", e)));
}
};
if file_conf.token.is_empty() {
return Err(io::Error::new(io::ErrorKind::Other, "token is_empty"));
}
let server_address = match file_conf.server_address.to_socket_addrs() {
Ok(mut addr) => {
if let Some(addr) = addr.next() {
addr
} else {
return Err(io::Error::new(
io::ErrorKind::Other,
format!("server_address {:?} error", &file_conf.server_address),
));
}
}
Err(e) => {
return Err(io::Error::new(
io::ErrorKind::Other,
format!("server_address {:?} error:{}", &file_conf.server_address, e),
));
}
};
let in_ips = match common::args_parse::ips_parse(&file_conf.in_ips) {
Ok(in_ips) => in_ips,
Err(e) => {
return Err(io::Error::new(
io::ErrorKind::Other,
format!("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(io::Error::new(
io::ErrorKind::Other,
format!("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| {
io::Error::new(
io::ErrorKind::Other,
format!("ip {:?} error:{}", &file_conf.ip, e),
)
})?),
};
let cipher_model = CipherModel::from_str(&file_conf.cipher_model)
.map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
let punch_model = PunchModel::from_str(&file_conf.punch_model)
.map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
let config = Config::new(
file_conf.tap,
file_conf.token,
file_conf.device_id,
file_conf.name,
server_address,
file_conf.server_address,
file_conf.stun_server,
in_ips,
out_ips,
file_conf.password,
file_conf.simulate_multicast,
file_conf.mtu,
file_conf.tcp,
virtual_ip,
file_conf.relay,
file_conf.server_encrypt,
file_conf.parallel,
cipher_model,
file_conf.finger,
punch_model,
file_conf.port,
);
Ok((config, file_conf.cmd))
}
pub fn get_device_id() -> String {
if let Some(id) = common::identifier::get_unique_identifier() {
id
} else {
let path_buf = crate::app_home().unwrap().join("device-id");
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
}
}
}
+149 -142
View File
@@ -16,6 +16,7 @@ use vnt::handle::handshake_handler::HandshakeEnum;
use vnt::handle::registration_handler::ReqEnum; use vnt::handle::registration_handler::ReqEnum;
mod command; mod command;
mod config;
mod console_out; mod console_out;
mod root_check; mod root_check;
@@ -54,12 +55,10 @@ fn main() {
opts.optopt("", "thread", "线程数(必须为正整数)", "<thread>"); opts.optopt("", "thread", "线程数(必须为正整数)", "<thread>");
opts.optopt("", "model", "加密模式", "<model>"); opts.optopt("", "model", "加密模式", "<model>");
opts.optflag("", "finger", "指纹校验"); opts.optflag("", "finger", "指纹校验");
opts.optopt( opts.optopt("", "punch", "取值ipv4/ipv6", "<punch>");
"", opts.optopt("", "port", "监听的端口", "<port>");
"punch", opts.optflag("", "cmd", "开启窗口输入");
"取值ipv4/ipv6,表示仅使用ipv4或ipv6打洞", opts.optopt("f", "", "配置文件", "<conf>");
"<punch>",
);
//"后台运行时,查看其他设备列表" //"后台运行时,查看其他设备列表"
opts.optflag("", "list", "后台运行时,查看其他设备列表"); opts.optflag("", "list", "后台运行时,查看其他设备列表");
opts.optflag("", "all", "后台运行时,查看其他设备完整信息"); opts.optflag("", "all", "后台运行时,查看其他设备完整信息");
@@ -101,156 +100,161 @@ fn main() {
command::command(command::CommandEnum::All); command::command(command::CommandEnum::All);
return; return;
} }
if !matches.opt_present("k") { let conf = matches.opt_str("f");
print_usage(&program, opts); let (config, cmd) = if conf.is_some() {
println!("parameter -k not found ."); match config::read_config(&conf.unwrap()) {
return; Ok(c) => c,
} Err(e) => {
let tap = matches.opt_present("a"); println!("conf err {}", e);
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() {
if let Some(id) = common::identifier::get_unique_identifier() {
id
} else {
let path_buf = app_home().unwrap().join("device-id");
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
}
}
} 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 server_address = match server_address_str.to_socket_addrs() {
Ok(mut addr) => {
if let Some(addr) = addr.next() {
addr
} else {
println!("parameter '-s {}' error .", server_address_str);
return; return;
} }
} }
Err(e) => { } else {
println!("parameter '-s {}' error {}.", server_address_str, e); if !matches.opt_present("k") {
print_usage(&program, opts);
println!("parameter -k not found .");
return; return;
} }
}; let tap = matches.opt_present("a");
let mut stun_server = matches.opt_strs("e"); let token: String = matches.opt_get("k").unwrap().unwrap();
if stun_server.is_empty() { let device_id = matches.opt_get_default("d", String::new()).unwrap();
stun_server.push("stun1.l.google.com:19302".to_string()); let device_id = if device_id.is_empty() {
stun_server.push("stun2.l.google.com:19302".to_string()); config::get_device_id()
stun_server.push("stun.qq.com:3478".to_string()); } 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 server_address = match server_address_str.to_socket_addrs() {
Ok(mut addr) => {
if let Some(addr) = addr.next() {
addr
} else {
println!("parameter '-s {}' error .", server_address_str);
return;
}
}
Err(e) => {
println!("parameter '-s {}' error {}.", server_address_str, e);
return;
}
};
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.qq.com:3478".to_string());
}
let in_ip = matches.opt_strs("i"); let in_ip = matches.opt_strs("i");
let in_ip = match ips_parse(&in_ip) { let in_ip = match ips_parse(&in_ip) {
Ok(in_ip) => 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");
let simulate_multicast = matches.opt_present("m");
let unused_cmd = matches.opt_present("c");
let mtu: Option<String> = matches.opt_get("u").unwrap();
let mtu = if let Some(mtu) = mtu {
match u16::from_str(&mtu) {
Ok(mtu) => Some(mtu),
Err(e) => { Err(e) => {
print_usage(&program, opts); print_usage(&program, opts);
println!(); println!();
println!("'-u {}' {}", mtu, e); 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");
let simulate_multicast = matches.opt_present("m");
let mtu: Option<String> = matches.opt_get("u").unwrap();
let mtu = if let Some(mtu) = mtu {
match u16::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; return;
} }
} }
} else { let tcp_channel = matches.opt_present("tcp");
None let relay = matches.opt_present("relay");
}; let parallel = matches.opt_get::<usize>("par").unwrap().unwrap_or(1);
let virtual_ip: Option<String> = matches.opt_get("ip").unwrap(); if parallel == 0 {
let virtual_ip = println!("'--par {}' invalid", parallel);
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; 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") { let cipher_model = match matches.opt_get::<CipherModel>("model") {
Ok(model) => model.unwrap_or(CipherModel::AesGcm), Ok(model) => model.unwrap_or(CipherModel::AesGcm),
Err(e) => { Err(e) => {
println!("'--model ' invalid,{}", e); println!("'--model ' invalid,{}", e);
return; return;
} }
};
let finger = matches.opt_present("finger");
let punch_model = matches
.opt_get::<PunchModel>("punch")
.unwrap()
.unwrap_or(PunchModel::All);
let port = matches.opt_get::<u16>("port").unwrap_or(None).unwrap_or(0);
let cmd = matches.opt_present("cmd");
let config = Config::new(
tap,
token,
device_id,
name,
server_address,
server_address_str,
stun_server,
in_ip,
out_ip,
password,
simulate_multicast,
mtu,
tcp_channel,
virtual_ip,
relay,
server_encrypt,
parallel,
cipher_model,
finger,
punch_model,
port,
);
(config, cmd)
}; };
let finger = matches.opt_present("finger");
let punch_model = matches
.opt_get::<PunchModel>("punch")
.unwrap()
.unwrap_or(PunchModel::All);
println!("version {}", vnt::VNT_VERSION); println!("version {}", vnt::VNT_VERSION);
let config = Config::new(
tap, main0(config, cmd);
token,
device_id,
name,
server_address,
server_address_str,
stun_server,
in_ip,
out_ip,
password,
simulate_multicast,
mtu,
tcp_channel,
virtual_ip,
relay,
server_encrypt,
parallel,
cipher_model,
finger,
punch_model,
);
main0(config, !unused_cmd);
std::process::exit(0); std::process::exit(0);
} }
@@ -438,11 +442,10 @@ fn print_usage(program: &str, _opts: Options) {
println!("Options:"); println!("Options:");
println!( println!(
" -k <token> {}", " -k <token> {}",
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!(" -c 关闭交互式命令,使用此参数禁用控制台输入");
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模式");
@@ -453,13 +456,17 @@ fn print_usage(program: &str, _opts: Options) {
println!(" -W 加密当前客户端和服务端通信的数据,请留意服务端指纹是否正确"); println!(" -W 加密当前客户端和服务端通信的数据,请留意服务端指纹是否正确");
println!(" -m 模拟组播,默认情况下组播数据会被当作广播发送,开启后会模拟真实组播的数据发送"); println!(" -m 模拟组播,默认情况下组播数据会被当作广播发送,开启后会模拟真实组播的数据发送");
println!(" -u <mtu> 自定义mtu(不加密默认为1450,加密默认为1410)"); println!(" -u <mtu> 自定义mtu(不加密默认为1450,加密默认为1410)");
println!(" -f <conf_file> 读取配置文件中的配置");
println!(" --tcp 和服务端使用tcp通信,默认使用udp,遇到udp qos时可指定使用tcp"); println!(" --tcp 和服务端使用tcp通信,默认使用udp,遇到udp qos时可指定使用tcp");
println!(" --ip <ip> 指定虚拟ip,指定的ip不能和其他设备重复,必须有效并且在服务端所属网段下,默认情况由服务端分配"); println!(" --ip <ip> 指定虚拟ip,指定的ip不能和其他设备重复,必须有效并且在服务端所属网段下,默认情况由服务端分配");
println!(" --relay 仅使用服务器转发,不使用p2p,默认情况允许使用p2p"); println!(" --relay 仅使用服务器转发,不使用p2p,默认情况允许使用p2p");
println!(" --par <parallel> 任务并行度(必须为正整数),默认值为1"); println!(" --par <parallel> 任务并行度(必须为正整数),默认值为1");
println!(" --model <model> 加密模式(默认aes_gcm),可选值aes_gcm/aes_cbc/aes_ecb,一般来说性能:aes_ecb>aes_cbc>aes_gcm"); println!(" --model <model> 加密模式(默认aes_gcm),可选值aes_gcm/aes_cbc/aes_ecb/sm4_cbc");
println!(" --finger 增加数据指纹校验,可增加安全性,如果服务端开启指纹校验,则客户端也必须开启"); println!(" --finger 增加数据指纹校验,可增加安全性,如果服务端开启指纹校验,则客户端也必须开启");
println!(" --punch <punch> 取值ipv4/ipv6ipv4表示仅使用ipv4打洞"); println!(" --punch <punch> 取值ipv4/ipv6ipv4表示仅使用ipv4打洞");
println!(" --port <port> 取值0~65535,指定本地监听的端口,默认取随机端口");
println!(" --cmd 开启交互式命令,使用此参数开启控制台输入");
println!(); println!();
println!( println!(
+2
View File
@@ -68,6 +68,7 @@ fn new_sync(env: &mut JNIEnv, config: JObject) -> Result<VntUtilSync, Error> {
let finger = env.get_field(&config, "finger", "Z")?.z()?; let finger = env.get_field(&config, "finger", "Z")?.z()?;
let in_ips = to_string(env, &config, "inIps")?; let in_ips = to_string(env, &config, "inIps")?;
let out_ips = to_string(env, &config, "outIps")?; let out_ips = to_string(env, &config, "outIps")?;
let port = env.get_field(&config, "port", "I")?.i()? as u16;
let in_ips = if let Some(in_ips) = in_ips { let in_ips = if let Some(in_ips) = in_ips {
let in_ips: Vec<&str> = in_ips.split("\n").collect(); let in_ips: Vec<&str> = in_ips.split("\n").collect();
let in_ips = in_ips.iter().map(|v| v.to_string()).collect(); let in_ips = in_ips.iter().map(|v| v.to_string()).collect();
@@ -149,6 +150,7 @@ fn new_sync(env: &mut JNIEnv, config: JObject) -> Result<VntUtilSync, Error> {
cipher_model, cipher_model,
finger, finger,
PunchModel::All, PunchModel::All,
port,
); );
match VntUtilSync::new(config) { match VntUtilSync::new(config) {
Ok(vnt_util) => Ok(vnt_util), Ok(vnt_util) => Ok(vnt_util),
+5 -2
View File
@@ -69,11 +69,11 @@ pub struct VntUtil {
impl VntUtil { impl VntUtil {
pub async fn new(config: Config) -> io::Result<VntUtil> { pub async fn new(config: Config) -> io::Result<VntUtil> {
//单个udp用同步的性能更好,但是代理和多端口监听用异步更方便,这里将两者结合起来 //单个udp用同步的性能更好,但是代理和多端口监听用异步更方便,这里将两者结合起来
let main_channel = UdpSocket::bind("0.0.0.0:0")?; let main_channel = UdpSocket::bind(format!("0.0.0.0:{}", config.port))?;
main_channel.set_write_timeout(Some(Duration::from_secs(5)))?; main_channel.set_write_timeout(Some(Duration::from_secs(5)))?;
main_channel.set_read_timeout(Some(Duration::from_secs(2)))?; main_channel.set_read_timeout(Some(Duration::from_secs(2)))?;
let main_channel_ipv6 = if config.punch_model != PunchModel::IPv4 { let main_channel_ipv6 = if config.punch_model != PunchModel::IPv4 {
match UdpSocket::bind("[::]:0") { match UdpSocket::bind(format!("[::]:{}", config.port)) {
Ok(main_channel_ipv6) => { Ok(main_channel_ipv6) => {
main_channel_ipv6.set_write_timeout(Some(Duration::from_secs(5)))?; main_channel_ipv6.set_write_timeout(Some(Duration::from_secs(5)))?;
Some(main_channel_ipv6) Some(main_channel_ipv6)
@@ -577,6 +577,7 @@ pub struct Config {
pub cipher_model: CipherModel, pub cipher_model: CipherModel,
pub finger: bool, pub finger: bool,
pub punch_model: PunchModel, pub punch_model: PunchModel,
pub port: u16,
} }
impl Config { impl Config {
@@ -601,6 +602,7 @@ impl Config {
cipher_model: CipherModel, cipher_model: CipherModel,
finger: bool, finger: bool,
punch_model: PunchModel, punch_model: PunchModel,
port: u16,
) -> Self { ) -> Self {
for x in stun_server.iter_mut() { for x in stun_server.iter_mut() {
if !x.contains(":") { if !x.contains(":") {
@@ -628,6 +630,7 @@ impl Config {
cipher_model, cipher_model,
finger, finger,
punch_model, punch_model,
port,
} }
} }
} }