增加精简客户端模块,适用于服务端、路由器

This commit is contained in:
lubeilin
2023-07-05 23:38:02 +08:00
parent a6050e5f59
commit 24140c2145
2 changed files with 268 additions and 0 deletions
+12
View File
@@ -0,0 +1,12 @@
[package]
name = "switch-mini"
version = "1.0.7"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
switch = {path="../switch"}
tokio = { version = "1.28.1", features = ["full"] }
getopts = "0.2.21"
ansi_term = "0.12.1"
+256
View File
@@ -0,0 +1,256 @@
use std::net::{Ipv4Addr, ToSocketAddrs};
use ansi_term::Colour;
use ansi_term::Colour::{Green, Yellow};
use getopts::Options;
use tokio::io::{AsyncBufReadExt, BufReader};
use switch::core::{Config, SwitchUtil};
use switch::handle::PeerDeviceStatus;
use switch::handle::registration_handler::ReqEnum;
#[tokio::main]
async fn main() {
let args: Vec<String> = std::env::args().collect();
let program = args[0].clone();
let mut opts = Options::new();
opts.optopt("", "token", "必选,使用相同的token,就能组建一个局域网络", "");
opts.optopt("", "device-id", "必选,设备唯一标识符,凭id分配ip", "");
opts.optopt("", "name", "必选,给设备一个名字", "");
opts.optflag("", "unused-cmd", "关闭交互式命令");
opts.optopt("", "server", "注册和中继服务器地址", "");
opts.optopt("", "nat-test-server", "NAT探测服务器地址,使用逗号分隔", "");
opts.optflag("", "tap", "使用tap模式");
opts.optmulti("", "in-ip", "配置点对网(IP代理)时使用,--in-ip 192.168.10.0/24,10.26.0.3,表示允许接收网段192.168.10.0/24的数据并转 发到10.26.0.3", "");
opts.optmulti("", "out-ip", "配置点对网时使用,--out-ip 192.168.10.0/24,192.168.1.10,表示允许目标为192.168.10.0/24的数据从网卡192.168.1.10转发出去", "");
opts.optopt("", "password", "使用该密码生成的密钥对客户端数据进行加密,并且服务端无法解密。使用相同密码的客户端才能通信", "");
opts.optflag("", "simulate-multicast", "模拟组播,默认情况下组播数据会被当作广播发送,兼容性更强,但是会造成流量浪费。开启后会模拟真实组播的数据发送");
opts.optflag("h", "help", "帮助");
let matches = match opts.parse(&args[1..]) {
Ok(m) => { m }
Err(f) => {
print_usage(&program, opts);
println!();
println!("{}", f.to_string());
return;
}
};
if matches.opt_present("h") {
print_usage(&program, opts);
return;
}
if !matches.opt_present("token") || !matches.opt_present("device-id") || !matches.opt_present("name") {
print_usage(&program, opts);
return;
}
let tap = matches.opt_present("tap");
let token: String = matches.opt_get("token").unwrap().unwrap();
let device_id: String = matches.opt_get("device-id").unwrap().unwrap();
let name: String = matches.opt_get("name").unwrap().unwrap();
let server_address = matches.opt_get_default("server", "nat1.wherewego.top:29871".to_string()).unwrap();
let server_address = server_address.to_socket_addrs().unwrap().next().unwrap();
let nat_test_server = matches.opt_get_default("nat-test-server",
"nat1.wherewego.top:35061,nat1.wherewego.top:35062,nat2.wherewego.top:35061,nat2.wherewego.top:35062".to_string()).unwrap();
let nat_test_server = nat_test_server.split(",").flat_map(|a| a.to_socket_addrs()).flatten()
.collect::<Vec<_>>();
let in_ip = matches.opt_strs("in-ip");
let in_ip = match ips_parse(&in_ip) {
Ok(in_ip) => { in_ip }
Err(e) => {
print_usage(&program, opts);
println!();
println!("--in-ip {}", e);
return;
}
};
let out_ip = matches.opt_strs("out-ip");
let out_ip = match ips_parse(&out_ip) {
Ok(out_ip) => { out_ip }
Err(e) => {
print_usage(&program, opts);
println!();
println!("--out-ip {}", e);
return;
}
};
let password: Option<String> = matches.opt_get("password").unwrap();
let simulate_multicast = matches.opt_present("simulate-multicast");
let unused_cmd = matches.opt_present("unused-cmd");
let config = Config::new(tap,
token, device_id, name,
server_address,
nat_test_server, in_ip,
out_ip, password, simulate_multicast, );
let mut switch_util = SwitchUtil::new(config).await.unwrap();
let response = loop {
match switch_util.connect().await {
Ok(response) => {
break response;
}
Err(e) => {
match e {
ReqEnum::TokenError => {
println!("token error");
}
ReqEnum::AddressExhausted => {
println!("address exhausted");
}
ReqEnum::Timeout => {
println!("timeout...");
continue;
}
ReqEnum::ServerError(str) => {
println!("error:{}", str);
}
ReqEnum::Other(str) => {
println!("error:{}", str);
}
}
return;
}
}
};
println!(" ====== Connect Successfully ====== ");
println!("virtual_gateway:{}", response.virtual_gateway);
println!("virtual_ip:{}", Green.paint(response.virtual_ip.to_string()));
let driver_info = switch_util.create_iface().unwrap();
println!(" ====== Create Network Interface Successfully ====== ");
println!("name:{}", driver_info.name);
println!("version:{}", driver_info.version);
let mut switch = match switch_util.build().await {
Ok(switch) => {
switch
}
Err(e) => {
println!("error:{}", e);
return;
}
};
println!(" ====== Start Successfully ====== ");
if unused_cmd {
switch.wait_stop().await;
} else {
let stdin = tokio::io::stdin();
let mut cmd = String::new();
let mut reader = BufReader::new(stdin);
loop {
cmd.clear();
println!("input:list,exit");
tokio::select! {
_ = switch.wait_stop()=>{
break;
}
rs = reader.read_line(&mut cmd)=>{
match rs {
Ok(len) => {
if len ==0 {
break;
}
match cmd[..len].trim() {
"list" => {
let mut list = switch.device_list();
if list.is_empty(){
println!("No other devices found");
continue;
}
list.sort_by_key(|v|{(v.virtual_ip,v.status)});
for x in list {
match x.status {
PeerDeviceStatus::Online => {
println!(" {}",Green.paint(x.virtual_ip.to_string()));
println!(" name:{}",x.name);
println!(" status:Online");
if let Some(route) = switch.route(&x.virtual_ip){
if route.is_p2p() {
println!(" connect:{}",Green.paint("p2p"));
}else {
println!(" connect:{}",Yellow.paint("relay"));
}
println!(" rt:{}",route.rt);
println!(" ->:{}",route.addr);
}
}
PeerDeviceStatus::Offline => {
println!(" {}",x.virtual_ip);
println!(" name:{}",x.name);
println!(" status:{}",Colour::RGB(150,150,150).paint("Offline"));
}
}
}
println!();
}
"exit" =>{
let _ = switch.stop();
break;
}
_ => {
}
}
}
Err(e) => {
println!("input err:{}",e);
break;
}
}
}
}
}
switch.wait_stop().await;
}
}
fn print_usage(program: &str, opts: Options) {
let brief = format!("Usage: {} [options]", program);
println!("version:1.0.7");
print!("{}", opts.usage(&brief));
}
fn ips_parse(ips: &Vec<String>) -> Result<Vec<(u32, u32, Ipv4Addr)>, String> {
let mut in_ips_c = vec![];
for x in ips {
let mut split = x.split(",");
let net = if let Some(net) = split.next() {
net
} else {
return Err("参数错误".to_string());
};
let ip = if let Some(ip) = split.next() {
ip
} else {
return Err("参数错误".to_string());
};
let ip = if let Ok(ip) = ip.parse::<Ipv4Addr>() {
ip
} else {
return Err("参数错误".to_string());
};
let mut split = net.split("/");
let dest = if let Some(dest) = split.next() {
dest
} else {
return Err("参数错误".to_string());
};
let mask = if let Some(mask) = split.next() {
mask
} else {
return Err("参数错误".to_string());
};
let dest = if let Ok(dest) = dest.parse::<Ipv4Addr>() {
dest
} else {
return Err("参数错误".to_string());
};
let mask = if let Ok(m) = mask.parse::<u32>() {
let mut mask = 0 as u32;
for i in 0..m {
mask = mask | (1 << (31 - i));
}
mask
} else {
return Err("参数错误".to_string());
};
in_ips_c.push((u32::from_be_bytes(dest.octets()), mask, ip));
}
Ok(in_ips_c)
}