From 24140c21450cc4c7d0591e6d569ae5be0a883637 Mon Sep 17 00:00:00 2001 From: lubeilin <1791778603@qq.com> Date: Wed, 5 Jul 2023 23:38:02 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E7=B2=BE=E7=AE=80=E5=AE=A2?= =?UTF-8?q?=E6=88=B7=E7=AB=AF=E6=A8=A1=E5=9D=97=EF=BC=8C=E9=80=82=E7=94=A8?= =?UTF-8?q?=E4=BA=8E=E6=9C=8D=E5=8A=A1=E7=AB=AF=E3=80=81=E8=B7=AF=E7=94=B1?= =?UTF-8?q?=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- switch-mini/Cargo.toml | 12 ++ switch-mini/src/main.rs | 256 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 268 insertions(+) create mode 100644 switch-mini/Cargo.toml create mode 100644 switch-mini/src/main.rs diff --git a/switch-mini/Cargo.toml b/switch-mini/Cargo.toml new file mode 100644 index 0000000..14430ce --- /dev/null +++ b/switch-mini/Cargo.toml @@ -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" diff --git a/switch-mini/src/main.rs b/switch-mini/src/main.rs new file mode 100644 index 0000000..2c2b719 --- /dev/null +++ b/switch-mini/src/main.rs @@ -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 = 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::>(); + + 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 = 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) -> Result, 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::() { + 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::() { + dest + } else { + return Err("参数错误".to_string()); + }; + let mask = if let Ok(m) = mask.parse::() { + 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) +}