diff --git a/README.md b/README.md index 645d536..d879491 100644 --- a/README.md +++ b/README.md @@ -82,10 +82,11 @@ - 客户端中继转发 - IP代理 - p2p组播/广播 +- 客户端数据加密 ### Todo - 支持安卓 -- 数据加密 +- 服务端数据加密 ### 常见问题 #### 问题1: 设置网络地址失败 diff --git a/switch-desktop/locales/en.yml b/switch-desktop/locales/en.yml index 831a2c3..83fde24 100644 --- a/switch-desktop/locales/en.yml +++ b/switch-desktop/locales/en.yml @@ -10,6 +10,7 @@ switch_log_help: "Record the log, the output is in the '${home}/.switch_desktop' switch_tap_help: "Use tap mode, tun mode will be used by default" switch_in_ip_help: "Use when configuring point-to-network (IP proxy), --in-ip 192.168.10.0/24,10.26.0.3, which means it is allowed to receive data from the network segment 192.168.10.0/24 and forward it to 10.26.0.3" switch_out_ip_help: "Use when configuring point-to-network, --out-ip 192.168.10.0/24,192.168.1.10, which means that the data with the target of 192.168.10.0/24 is allowed to be forwarded from the network card 192.168.1.10" +switch_password_help: "Client Data Encryption" switch_config_help: "Read configuration file" switch_stop_about: "Stop background service" switch_route_about: "View route" diff --git a/switch-desktop/locales/zh-CN.yml b/switch-desktop/locales/zh-CN.yml index 7c9e210..7b69724 100644 --- a/switch-desktop/locales/zh-CN.yml +++ b/switch-desktop/locales/zh-CN.yml @@ -10,6 +10,7 @@ switch_log_help: "记录日志,输出在 '${home}/.switch_desktop' 目录下 switch_tap_help: "使用tap模式,默认会使用tun模式" switch_in_ip_help: "配置点对网(IP代理)时使用,--in-ip 192.168.10.0/24,10.26.0.3,表示允许接收网段192.168.10.0/24的数据并转发到10.26.0.3" switch_out_ip_help: "配置点对网时使用,--out-ip 192.168.10.0/24,192.168.1.10,表示允许目标为192.168.10.0/24的数据从网卡192.168.1.10转发出去" +switch_password_help: "使用该密码生成的密钥对客户端数据进行加密,并且服务端无法解密。使用相同密码的客户端才能通信" switch_config_help: "读取配置文件" switch_stop_about: "停止后台服务" switch_route_about: "查看路由" diff --git a/switch-desktop/src/command_args.rs b/switch-desktop/src/command_args.rs index 7b15672..04bb773 100644 --- a/switch-desktop/src/command_args.rs +++ b/switch-desktop/src/command_args.rs @@ -62,6 +62,11 @@ fn common() -> Command { .long("out-ip") .help(switch_out_ip_help()) .action(ArgAction::Append) + ).arg( + Arg::new("password") + .long("password") + .help(switch_password_help()) + .action(ArgAction::Set) ).arg( Arg::new("config") .long("config") diff --git a/switch-desktop/src/config/mod.rs b/switch-desktop/src/config/mod.rs index 9480470..cc24154 100644 --- a/switch-desktop/src/config/mod.rs +++ b/switch-desktop/src/config/mod.rs @@ -38,6 +38,7 @@ pub struct StartConfig { #[cfg(any(unix))] pub off_command_server: bool, pub log: bool, + pub password: Option, } fn ips_parse(ips: &Vec) -> Result, String> { @@ -163,7 +164,7 @@ pub fn default_config(start_args: StartArgs) -> Result { } } Err(e) => { - return Err(format!("{} :{:?}",i18n::switch_relay_server_address_error(), e)); + return Err(format!("{} :{:?}", i18n::switch_relay_server_address_error(), e)); } }; println!("中继服务器:{:?}", server); @@ -187,6 +188,7 @@ pub fn default_config(start_args: StartArgs) -> Result { #[cfg(any(unix))] off_command_server: start_args.off_command_server, log: start_args.log, + password: start_args.password, }; println!("========参数配置========"); Ok(base_config) @@ -268,7 +270,7 @@ pub fn read_config_file(config_path: PathBuf) -> Result { } } Err(e) => { - return Err(format!("{}:{:?}",i18n::switch_relay_server_address_error(), e)); + return Err(format!("{}:{:?}", i18n::switch_relay_server_address_error(), e)); } }; println!("中继服务器:{:?}", server); @@ -294,6 +296,7 @@ pub fn read_config_file(config_path: PathBuf) -> Result { #[cfg(any(unix))] off_command_server: args_config.off_command_server, log, + password:args_config.password }; println!("========参数配置========"); Ok(base_config) @@ -331,6 +334,7 @@ pub struct ArgsConfig { pub off_command_server: bool, #[serde(default = "default_false")] pub log: bool, + pub password: Option, } #[cfg(windows)] @@ -355,6 +359,7 @@ impl ArgsConfig { log: start_config.log, #[cfg(any(unix))] off_command_server: start_config.off_command_server, + password: start_config.password, } } } diff --git a/switch-desktop/src/i18n.rs b/switch-desktop/src/i18n.rs index 3410ec6..d26ce98 100644 --- a/switch-desktop/src/i18n.rs +++ b/switch-desktop/src/i18n.rs @@ -73,6 +73,9 @@ pub fn switch_in_ip_help() -> String { pub fn switch_out_ip_help() -> String { rust_i18n::t!("switch_out_ip_help") } +pub fn switch_password_help() -> String { + rust_i18n::t!("switch_password_help") +} pub fn switch_config_help() -> String { rust_i18n::t!("switch_config_help") diff --git a/switch-desktop/src/main.rs b/switch-desktop/src/main.rs index ec3ccab..52ceac6 100644 --- a/switch-desktop/src/main.rs +++ b/switch-desktop/src/main.rs @@ -107,6 +107,9 @@ pub struct StartArgs { /// Use when configuring peer-to-peer networks #[arg(long)] out_ip: Option>, + /// 客户端数据加密 + #[arg(long)] + password:Option, /// 读取配置文件 --config config_file_path /// Read configuration file #[arg(long)] diff --git a/switch-desktop/src/unix/mod.rs b/switch-desktop/src/unix/mod.rs index 347b080..e588090 100644 --- a/switch-desktop/src/unix/mod.rs +++ b/switch-desktop/src/unix/mod.rs @@ -45,6 +45,7 @@ pub async fn main0(base_args: BaseArgs) { start_config.nat_test_server.clone(), start_config.in_ips.clone(), start_config.out_ips.clone(), + start_config.password.clone(), ); let lock = match config::lock_file() { Ok(lock) => { diff --git a/switch-desktop/src/windows/mod.rs b/switch-desktop/src/windows/mod.rs index b463354..125b483 100644 --- a/switch-desktop/src/windows/mod.rs +++ b/switch-desktop/src/windows/mod.rs @@ -42,7 +42,7 @@ fn not_started() -> bool { if state == ServiceState::Running { return false; } else { - println!("{}",i18n::switch_service_not_start_print()) + println!("{}", i18n::switch_service_not_start_print()) } } Err(e) => { @@ -100,7 +100,7 @@ pub fn main0(base_args: BaseArgs) { } } } else { - println!("{}",i18n::switch_service_not_stopped_print()); + println!("{}", i18n::switch_service_not_stopped_print()); } } Err(e) => { @@ -118,6 +118,7 @@ pub fn main0(base_args: BaseArgs) { start_config.nat_test_server, start_config.in_ips, start_config.out_ips, + start_config.password, ); let lock = match config::lock_file() { Ok(lock) => { @@ -179,7 +180,7 @@ pub fn main0(base_args: BaseArgs) { return; } if service_state().is_ok() { - println!("{}",i18n::switch_server_already_installed_print()); + println!("{}", i18n::switch_server_already_installed_print()); return; } let path: PathBuf = args.path.into(); diff --git a/switch-desktop/src/windows/service.rs b/switch-desktop/src/windows/service.rs index de3eb79..0817199 100644 --- a/switch-desktop/src/windows/service.rs +++ b/switch-desktop/src/windows/service.rs @@ -73,7 +73,6 @@ async fn service_main(arguments: Vec) -> windows_service::Result<()> { match start_switch(arguments).await { Ok(_) => { parker.park(); - } Err(e) => { log::error!("服务启动失败 {:?}",e); @@ -171,12 +170,13 @@ async fn start_switch(arguments: Vec) -> switch::Result<()> { start_config.nat_test_server, start_config.in_ips, start_config.out_ips, + start_config.password, ); log::info!("switch-service服务启动"); - tokio::spawn(async move { - match Switch::start(config).await { + tokio::spawn(async move { + match Switch::start(config).await { Ok(switch) => { let switch = Arc::new(switch); let command_server = crate::command::server::CommandServer::new(); @@ -191,7 +191,6 @@ async fn start_switch(arguments: Vec) -> switch::Result<()> { log::error!("{:?}", e); } }; - }); Ok(()) } diff --git a/switch/Cargo.toml b/switch/Cargo.toml index d12f077..8175ae7 100644 --- a/switch/Cargo.toml +++ b/switch/Cargo.toml @@ -19,6 +19,7 @@ parking_lot = "0.12.1" rsa = "0.7.2" rand = "0.8.5" sha2 = { version = "0.10.6", features = ["oid"] } +aes-gcm = "0.10.2" thiserror = "1.0.37" chrono = "0.4.23" diff --git a/switch/src/channel/channel.rs b/switch/src/channel/channel.rs index 193ae5e..f0220af 100644 --- a/switch/src/channel/channel.rs +++ b/switch/src/channel/channel.rs @@ -330,7 +330,7 @@ impl Channel { #[cfg(any(unix))] let id = udp.as_raw_fd() as usize; context.udp_map.insert(id, udp.clone()); - let mut buf = [0; 65546]; + let mut buf = [0; 65536]; loop { tokio::select! { rs=udp.recv_from(&mut buf[head_reserve..])=>{ diff --git a/switch/src/core/mod.rs b/switch/src/core/mod.rs index d422887..efed388 100644 --- a/switch/src/core/mod.rs +++ b/switch/src/core/mod.rs @@ -1,6 +1,7 @@ use std::{io, thread}; use std::net::{Ipv4Addr, SocketAddr}; use std::sync::Arc; +use aes_gcm::{Aes256Gcm, Key, KeyInit}; use crossbeam::atomic::AtomicCell; use crossbeam_skiplist::SkipMap; @@ -41,6 +42,12 @@ pub struct Switch { impl Switch { pub async fn start(config: Config) -> crate::Result { log::info!("config:{:?}",config); + let cipher = if let Some(key) = &config.key { + let key: &Key = key.into(); + Some(Aes256Gcm::new(&key)) + } else { + None + }; let main_channel = Arc::new(UdpSocket::bind("0.0.0.0:0").await?); let response = registration_handler::registration(&main_channel, config.server_address, config.token.clone(), config.device_id.clone(), config.name.clone()).await?; let (cone_sender, cone_receiver) = channel(3); @@ -62,7 +69,7 @@ impl Switch { let local_port = context.main_local_port()?; // NAT检测 let nat_test = NatTest::new(config.nat_test_server.clone(), Ipv4Addr::from(response.public_ip), response.public_port as u16, local_ip, local_port); - let in_ips = config.in_ips.iter().map(|(dest, mask, _)| { (Ipv4Addr::from(*dest), Ipv4Addr::from(*mask)) }).collect::>(); + let in_ips = config.in_ips.iter().map(|(dest, mask, _)| { (Ipv4Addr::from(*dest & *mask), Ipv4Addr::from(*mask)) }).collect::>(); let out_ips = config.out_ips.iter().map(|(_, _, ip)| *ip).collect::>(); let out_external_route = ExternalRoute::new(config.out_ips); @@ -78,7 +85,8 @@ impl Switch { let (tap_writer, tap_reader) = tun_tap_device::create_device(tun_tap_device::DeviceType::Tap, virtual_ip, virtual_netmask, virtual_gateway, in_ips)?; let igmp_server = IgmpServer::new(tap_writer.clone()); //tap数据处理 - tap_handler::start(channel_sender.clone(), tap_reader.clone(), tap_writer.clone(), igmp_server.clone(), current_device.clone(), in_external_route, ip_proxy_map.clone()); + tap_handler::start(channel_sender.clone(), tap_reader.clone(), tap_writer.clone(), + igmp_server.clone(), current_device.clone(), in_external_route, ip_proxy_map.clone(), cipher.clone()); (tap_writer, igmp_server) } else { #[cfg(windows)] @@ -90,7 +98,8 @@ impl Switch { let (tun_writer, tun_reader) = tun_tap_device::create_device(tun_tap_device::DeviceType::Tun, virtual_ip, virtual_netmask, virtual_gateway, in_ips)?; let igmp_server = IgmpServer::new(tun_writer.clone()); //tun数据接收处理 - tun_handler::start(channel_sender.clone(), tun_reader.clone(), tun_writer.clone(), igmp_server.clone(), current_device.clone(), in_external_route, ip_proxy_map.clone()); + tun_handler::start(channel_sender.clone(), tun_reader.clone(), tun_writer.clone(), + igmp_server.clone(), current_device.clone(), in_external_route, ip_proxy_map.clone(), cipher.clone()); (tun_writer, igmp_server) }; //外部数据接收处理 @@ -98,7 +107,7 @@ impl Switch { register.clone(), nat_test.clone(), igmp_server, device_writer.clone(), connect_status.clone(), peer_nat_info_map.clone(), ip_proxy_map, out_external_route, - cone_sender, symmetric_sender); + cone_sender, symmetric_sender, cipher); let channel = Channel::new(context.clone(), channel_recv_handler); thread::spawn(move || { tokio::runtime::Builder::new_multi_thread() @@ -178,15 +187,26 @@ pub struct Config { pub nat_test_server: Vec, pub in_ips: Vec<(u32, u32, Ipv4Addr)>, pub out_ips: Vec<(u32, u32, Ipv4Addr)>, + pub key: Option<[u8; 32]>, } +use sha2::Digest; + impl Config { pub fn new(tap: bool, token: String, device_id: String, name: String, server_address: SocketAddr, nat_test_server: Vec, - in_ips: Vec<(u32, u32, Ipv4Addr)>, out_ips: Vec<(u32, u32, Ipv4Addr)>, ) -> Self { + in_ips: Vec<(u32, u32, Ipv4Addr)>, out_ips: Vec<(u32, u32, Ipv4Addr)>, password: Option, ) -> Self { + let key = if let Some(password) = password { + let mut hasher = sha2::Sha256::new(); + hasher.update(password.as_bytes()); + let key: [u8; 32] = hasher.finalize().into(); + Some(key) + } else { + None + }; Self { tap, token, @@ -196,6 +216,7 @@ impl Config { nat_test_server, in_ips, out_ips, + key, } } } \ No newline at end of file diff --git a/switch/src/handle/recv_handler.rs b/switch/src/handle/recv_handler.rs index fc47724..8a56bb7 100644 --- a/switch/src/handle/recv_handler.rs +++ b/switch/src/handle/recv_handler.rs @@ -1,5 +1,8 @@ use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4}; use std::sync::Arc; +use aes_gcm::{AeadInPlace, Aes256Gcm, Nonce, Tag}; +use aes_gcm::aead::consts::{U12, U16}; +use aes_gcm::aead::generic_array::GenericArray; use chrono::Local; use crossbeam::atomic::AtomicCell; @@ -45,6 +48,7 @@ pub struct ChannelDataHandler { out_external_route: ExternalRoute, cone_sender: Sender<(Ipv4Addr, NatInfo)>, symmetric_sender: Sender<(Ipv4Addr, NatInfo)>, + cipher: Option, } impl ChannelDataHandler { @@ -59,7 +63,8 @@ impl ChannelDataHandler { ip_proxy_map: IpProxyMap, out_external_route: ExternalRoute, cone_sender: Sender<(Ipv4Addr, NatInfo)>, - symmetric_sender: Sender<(Ipv4Addr, NatInfo)>, ) -> Self { + symmetric_sender: Sender<(Ipv4Addr, NatInfo)>, + cipher: Option, ) -> Self { Self { current_device, device_list, @@ -73,6 +78,7 @@ impl ChannelDataHandler { out_external_route, cone_sender, symmetric_sender, + cipher, } } } @@ -127,8 +133,51 @@ impl ChannelDataHandler { match net_packet.protocol() { Protocol::IpTurn => { match ip_turn_packet::Protocol::from(net_packet.transport_protocol()) { + ip_turn_packet::Protocol::Icmp => { + let ipv4 = IpV4Packet::new(net_packet.payload())?; + if ipv4.protocol() == ipv4::protocol::Protocol::Icmp { + self.device_writer.write_ipv4(&mut buf[12..])?; + return Ok(()); + } + } + ip_turn_packet::Protocol::Igmp => { + let ipv4 = IpV4Packet::new(net_packet.payload())?; + if ipv4.protocol() == ipv4::protocol::Protocol::Igmp { + self.igmp_server.handle(ipv4.payload(), source)?; + } + return Ok(()); + } ip_turn_packet::Protocol::Ipv4 => { - let mut ipv4 = IpV4Packet::new(net_packet.payload_mut())?; + let data = if let Some(cipher) = &self.cipher { + if !net_packet.is_encrypt() { + //未加密的数据之间丢弃 + return Ok(()); + } + if net_packet.payload().len() < 16 { + log::error!("数据异常,长度小于16"); + return Ok(()); + } + //需要解密 + let mut nonce = [0; 12]; + nonce[0..4].copy_from_slice(&source.octets()); + nonce[4..8].copy_from_slice(&destination.octets()); + nonce[8] = Protocol::IpTurn.into(); + nonce[9] = ip_turn_packet::Protocol::Ipv4.into(); + let nonce: &GenericArray = Nonce::from_slice(&nonce); + let data_len = net_packet.payload().len() - 16; + let tag: GenericArray = Tag::clone_from_slice(&net_packet.payload()[data_len..]); + match cipher.decrypt_in_place_detached(nonce, &[], &mut net_packet.payload_mut()[..data_len], &tag) { + Ok(_) => {} + Err(e) => { + log::error!("数据解密异常:{}",e); + return Ok(()); + } + } + &mut net_packet.payload_mut()[..data_len] + } else { + net_packet.payload_mut() + }; + let mut ipv4 = IpV4Packet::new(data)?; match ipv4.protocol() { ipv4::protocol::Protocol::Igmp => { self.igmp_server.handle(ipv4.payload(), source)?; @@ -146,63 +195,87 @@ impl ChannelDataHandler { ipv4.update_checksum(); net_packet.set_source(destination); net_packet.set_destination(source); + if let Some(cipher) = &self.cipher { + //需要加密 + let mut nonce = [0; 12]; + nonce[0..4].copy_from_slice(&destination.octets()); + nonce[4..8].copy_from_slice(&source.octets()); + nonce[8] = Protocol::IpTurn.into(); + nonce[9] = ip_turn_packet::Protocol::Ipv4.into(); + let nonce: &GenericArray = Nonce::from_slice(&nonce); + let data_len = net_packet.payload().len() - 16; + match cipher.encrypt_in_place_detached(nonce, &[], &mut net_packet.payload_mut()[..data_len]) { + Ok(tag) => { + if tag.len() != 16 { + log::error!("加密tag长度错误:{}",tag.len()); + return Ok(()); + } + net_packet.set_encrypt_flag(true); + net_packet.payload_mut()[data_len..data_len + 16].copy_from_slice(tag.as_slice()); + } + Err(e) => { + log::error!("加密失败:{}",e); + return Ok(()); + } + } + } context.send_by_key(net_packet.buffer(), route_key).await?; return Ok(()); } } } - _ => { - if ipv4.destination_ip() != destination { - if let Some(gate_way) = self.out_external_route.route(&ipv4.destination_ip()) { - match ipv4.protocol() { - ipv4::protocol::Protocol::Tcp => { - let dest_ip = ipv4.destination_ip(); - //转发到代理目标地址 - let mut tcp_packet = packet::tcp::tcp::TcpPacket::new(source, destination, ipv4.payload_mut())?; - let source_port = tcp_packet.source_port(); - let dest_port = tcp_packet.destination_port(); - tcp_packet.set_destination_port(self.ip_proxy_map.tcp_proxy_port); - tcp_packet.update_checksum(); - ipv4.set_destination_ip(destination); - ipv4.update_checksum(); - self.ip_proxy_map.tcp_proxy_map.insert(SocketAddrV4::new(source, source_port), - (SocketAddrV4::new(gate_way, 0), SocketAddrV4::new(dest_ip, dest_port))); - } - ipv4::protocol::Protocol::Udp => { - let dest_ip = ipv4.destination_ip(); - //转发到代理目标地址 - let mut udp_packet = packet::udp::udp::UdpPacket::new(source, destination, ipv4.payload_mut())?; - let source_port = udp_packet.source_port(); - let dest_port = udp_packet.destination_port(); - udp_packet.set_destination_port(self.ip_proxy_map.udp_proxy_port); - udp_packet.update_checksum(); - ipv4.set_destination_ip(destination); - ipv4.update_checksum(); - self.ip_proxy_map.udp_proxy_map.insert(SocketAddrV4::new(source, source_port), - (SocketAddrV4::new(gate_way, 0), SocketAddrV4::new(dest_ip, dest_port))); - } - ipv4::protocol::Protocol::Icmp => { - let dest_ip = ipv4.destination_ip(); - //转发到代理目标地址 - let icmp_packet = icmp::IcmpPacket::new(ipv4.payload())?; - match icmp_packet.header_other() { - HeaderOther::Identifier(id, seq) => { - self.ip_proxy_map.icmp_proxy_map.insert((dest_ip, id, seq), source); - self.ip_proxy_map.send_icmp(ipv4.payload(), &gate_way, &dest_ip)?; - } - _ => { - return Ok(()); - } - } + _ => {} + } + if ipv4.destination_ip() != destination { + if let Some(gate_way) = self.out_external_route.route(&ipv4.destination_ip()) { + match ipv4.protocol() { + ipv4::protocol::Protocol::Tcp => { + let dest_ip = ipv4.destination_ip(); + //转发到代理目标地址 + let mut tcp_packet = packet::tcp::tcp::TcpPacket::new(source, destination, ipv4.payload_mut())?; + let source_port = tcp_packet.source_port(); + let dest_port = tcp_packet.destination_port(); + tcp_packet.set_destination_port(self.ip_proxy_map.tcp_proxy_port); + tcp_packet.update_checksum(); + ipv4.set_destination_ip(destination); + ipv4.update_checksum(); + self.ip_proxy_map.tcp_proxy_map.insert(SocketAddrV4::new(source, source_port), + (SocketAddrV4::new(gate_way, 0), SocketAddrV4::new(dest_ip, dest_port))); + } + ipv4::protocol::Protocol::Udp => { + let dest_ip = ipv4.destination_ip(); + //转发到代理目标地址 + let mut udp_packet = packet::udp::udp::UdpPacket::new(source, destination, ipv4.payload_mut())?; + let source_port = udp_packet.source_port(); + let dest_port = udp_packet.destination_port(); + udp_packet.set_destination_port(self.ip_proxy_map.udp_proxy_port); + udp_packet.update_checksum(); + ipv4.set_destination_ip(destination); + ipv4.update_checksum(); + self.ip_proxy_map.udp_proxy_map.insert(SocketAddrV4::new(source, source_port), + (SocketAddrV4::new(gate_way, 0), SocketAddrV4::new(dest_ip, dest_port))); + } + ipv4::protocol::Protocol::Icmp => { + let dest_ip = ipv4.destination_ip(); + //转发到代理目标地址 + let icmp_packet = icmp::IcmpPacket::new(ipv4.payload())?; + match icmp_packet.header_other() { + HeaderOther::Identifier(id, seq) => { + self.ip_proxy_map.icmp_proxy_map.insert((dest_ip, id, seq), source); + self.ip_proxy_map.send_icmp(ipv4.payload(), &gate_way, &dest_ip)?; } _ => { return Ok(()); } } } + _ => { + return Ok(()); + } } } } + //传输协议12字节 self.device_writer.write_ipv4(&mut buf[12..])?; return Ok(()); diff --git a/switch/src/handle/tun_tap/mod.rs b/switch/src/handle/tun_tap/mod.rs index 1e1f30a..36725e5 100644 --- a/switch/src/handle/tun_tap/mod.rs +++ b/switch/src/handle/tun_tap/mod.rs @@ -1,4 +1,8 @@ +use std::io; use std::net::{Ipv4Addr, SocketAddrV4}; +use aes_gcm::{AeadInPlace, Aes256Gcm, Nonce}; +use aes_gcm::aead::consts::U12; +use aes_gcm::aead::generic_array::GenericArray; use packet::ip::ipv4::packet::IpV4Packet; use packet::ip::ipv4::protocol::Protocol; use packet::tcp::tcp::TcpPacket; @@ -42,9 +46,9 @@ async fn multicast(igmp_server: &IgmpServer, multicast_addr: Ipv4Addr, sender: & let mut peer_ips = Vec::with_capacity(8); let vec = sender.direct_route_table_one(); if let Some(members) = igmp_server.load(&multicast_addr) { - let members_guard = members.read(); for (peer_ip, route) in vec { - if members_guard.is_send(&peer_ip) { + let is_send = {members.read().is_send(&peer_ip)}; + if is_send { if sender.send_by_key(&net_packet.buffer()[..data_len], &route.route_key()).await.is_ok() { peer_ips.push(peer_ip); if peer_ips.len() == u8::MAX as usize { @@ -69,42 +73,59 @@ async fn multicast(igmp_server: &IgmpServer, multicast_addr: Ipv4Addr, sender: & } /// 实现一个原地发送,必须保证是如下结构 -/// |12字节开头|ip报文|至少1024字节结尾| +/// |12字节开头|ip报文|至少1024字节+12字节结尾| /// #[inline] pub async fn base_handle(sender: &ChannelSender, buf: &mut [u8], - data_len: usize,//数据总长度=ip长度+12 - igmp_server: &IgmpServer, - current_device: CurrentDeviceInfo, - ip_route: &ExternalRoute, proxy_map: &IpProxyMap) -> Result<()> { + mut data_len: usize,//数据总长度=ip长度+12 + igmp_server: &IgmpServer, + current_device: CurrentDeviceInfo, + ip_route: &ExternalRoute, proxy_map: &IpProxyMap, cipher: &Option) -> Result<()> { let ipv4_packet = IpV4Packet::new(&buf[12..data_len])?; let protocol = ipv4_packet.protocol(); let ip_head_len = ipv4_packet.header_len() as usize * 4; let src_ip = ipv4_packet.source_ip(); let mut dest_ip = ipv4_packet.destination_ip(); let mut net_packet = NetPacket::new(buf)?; - net_packet.set_transport_protocol(ip_turn_packet::Protocol::Ipv4.into()); net_packet.set_version(Version::V1); net_packet.set_protocol(protocol::Protocol::IpTurn); + net_packet.set_transport_protocol(ip_turn_packet::Protocol::Ipv4.into()); net_packet.first_set_ttl(3); net_packet.set_source(src_ip); net_packet.set_destination(dest_ip); + if dest_ip == current_device.virtual_gateway { + if protocol == Protocol::Icmp { + net_packet.set_transport_protocol(ip_turn_packet::Protocol::Icmp.into()); + //发送到服务端的不加密 + sender.send_main(&net_packet.buffer()[..data_len], current_device.connect_server).await?; + } + return Ok(()); + } + if dest_ip.is_multicast() { + if protocol == Protocol::Igmp { + net_packet.set_transport_protocol(ip_turn_packet::Protocol::Igmp.into()); + //发送到服务端 + sender.send_main(&net_packet.buffer()[..data_len], current_device.connect_server).await?; + return Ok(()); + } + } if dest_ip.is_broadcast() || current_device.broadcast_address == dest_ip { // 广播 发送到直连目标 if Protocol::Udp == protocol { + if let Some(cipher) = cipher { + //需要加密 + encrypt(cipher, &mut data_len, &mut net_packet)?; + } broadcast(sender, &mut net_packet, data_len, ¤t_device).await?; } return Ok(()); } else if dest_ip.is_multicast() { - match protocol { - Protocol::Igmp => { - //发送到服务端 - sender.send_main(&net_packet.buffer()[..data_len], current_device.connect_server).await?; + if protocol == Protocol::Udp { + if let Some(cipher) = cipher { + //需要加密 + encrypt(cipher, &mut data_len, &mut net_packet)?; } - Protocol::Udp => { - multicast(igmp_server, dest_ip, sender, &mut net_packet, data_len, ¤t_device).await?; - } - _ => {} + multicast(igmp_server, dest_ip, sender, &mut net_packet, data_len, ¤t_device).await?; } return Ok(()); } else { @@ -158,9 +179,37 @@ pub async fn base_handle(sender: &ChannelSender, buf: &mut [u8], } } } + if let Some(cipher) = cipher { + //需要加密 + encrypt(cipher, &mut data_len, &mut net_packet)?; + } + //优先发到直连到地址 if sender.send_by_id(&net_packet.buffer()[..data_len], &dest_ip).await.is_err() { sender.send_main(&net_packet.buffer()[..data_len], current_device.connect_server).await?; } return Ok(()); +} + +fn encrypt(cipher: &Aes256Gcm, data_len: &mut usize, net_packet: &mut NetPacket<&mut [u8]>) -> io::Result<()> { + let mut nonce = [0; 12]; + nonce[0..4].copy_from_slice(&net_packet.source().octets()); + nonce[4..8].copy_from_slice(&net_packet.destination().octets()); + nonce[8] = protocol::Protocol::IpTurn.into(); + nonce[9] = ip_turn_packet::Protocol::Ipv4.into(); + let nonce: &GenericArray = Nonce::from_slice(&nonce); + return match cipher.encrypt_in_place_detached(nonce, &[], &mut net_packet.payload_mut()[..*data_len - 12]) { + Ok(tag) => { + if tag.len() != 16 { + return Err(io::Error::new(io::ErrorKind::Other, format!("加密tag长度错误:{}", tag.len()))); + } + net_packet.set_encrypt_flag(true); + net_packet.payload_mut()[*data_len - 12..*data_len - 12 + 16].copy_from_slice(tag.as_slice()); + *data_len += 16; + Ok(()) + } + Err(e) => { + Err(io::Error::new(io::ErrorKind::Other, format!("加密失败:{}", e))) + } + }; } \ No newline at end of file diff --git a/switch/src/handle/tun_tap/tap_handler.rs b/switch/src/handle/tun_tap/tap_handler.rs index 7e9dfac..9b17070 100644 --- a/switch/src/handle/tun_tap/tap_handler.rs +++ b/switch/src/handle/tun_tap/tap_handler.rs @@ -1,5 +1,6 @@ use std::sync::Arc; use std::{io, thread}; +use aes_gcm::Aes256Gcm; use crossbeam::atomic::AtomicCell; use packet::arp::arp::ArpPacket; use packet::ethernet; @@ -21,39 +22,41 @@ pub fn start(sender: ChannelSender, igmp_server: IgmpServer, current_device: Arc>, ip_route: ExternalRoute, - ip_proxy_map: IpProxyMap) { + ip_proxy_map: IpProxyMap, + cipher: Option) { thread::Builder::new().name("tap-handler".into()).spawn(move || { tokio::runtime::Builder::new_current_thread() .enable_all().build().unwrap() .block_on(async move { if let Err(e) = start_(sender, device_reader, device_writer, igmp_server, - current_device, ip_route, ip_proxy_map).await { + current_device, ip_route, ip_proxy_map, cipher).await { log::warn!("tap:{:?}",e); } }); - }).unwrap(); } async fn start_(sender: ChannelSender, - device_reader: DeviceReader, - device_writer: DeviceWriter, - igmp_server: IgmpServer, - current_device: Arc>, - ip_route: ExternalRoute, - ip_proxy_map: IpProxyMap) -> io::Result<()> { - let mut buf = [0; 4096]; + device_reader: DeviceReader, + device_writer: DeviceWriter, + igmp_server: IgmpServer, + current_device: Arc>, + ip_route: ExternalRoute, + ip_proxy_map: IpProxyMap, + cipher: Option) -> io::Result<()> { + let mut buf = [0; 2048]; loop { + //ip拆包了会直接丢弃? let len = device_reader.read(&mut buf)?; - if let Err(e) = handle(&mut buf, len, &igmp_server, ¤t_device, &device_writer, &sender, &ip_route, &ip_proxy_map).await { + if let Err(e) = handle(&mut buf, len, &igmp_server, ¤t_device, &device_writer, &sender, &ip_route, &ip_proxy_map, &cipher).await { log::error!("tap handle{:?}",e); } } } async fn handle(buf: &mut [u8], len: usize, igmp_server: &IgmpServer, current_device: &AtomicCell, - device_writer: &DeviceWriter, sender: &ChannelSender, ip_route: &ExternalRoute, proxy_map: &IpProxyMap) -> crate::Result<()> { + device_writer: &DeviceWriter, sender: &ChannelSender, ip_route: &ExternalRoute, proxy_map: &IpProxyMap, cipher: &Option) -> crate::Result<()> { let mut ethernet_packet = EthernetPacket::new(&mut buf[..len])?; let current_device = current_device.load(); match ethernet_packet.protocol() { @@ -68,12 +71,12 @@ async fn handle(buf: &mut [u8], len: usize, igmp_server: &IgmpServer, current_de return Ok(()); } //回复一个虚假的MAC地址 - out_arp_packet.set_sender_hardware_addr(&[target_p[0], target_p[1], target_p[2], target_p[3], 123, 234]); + out_arp_packet.set_sender_hardware_addr(&[target_p[0], target_p[1], target_p[2], target_p[3], !sender_h[5], 234]); out_arp_packet.set_sender_protocol_addr(target_p); out_arp_packet.set_target_hardware_addr(sender_h); out_arp_packet.set_target_protocol_addr(sender_p); out_arp_packet.set_op_code(2); - out_ethernet_packet.set_source(&[target_p[0], target_p[1], target_p[2], target_p[3], 123, 234]); + out_ethernet_packet.set_source(&[target_p[0], target_p[1], target_p[2], target_p[3], !sender_h[5], 234]); out_ethernet_packet.set_destination(sender_h); device_writer.write_ethernet_tap(&out_ethernet_packet.buffer)?; } @@ -105,7 +108,7 @@ async fn handle(buf: &mut [u8], len: usize, igmp_server: &IgmpServer, current_de } // 以太网帧头部14字节,预留12字节 return crate::handle::tun_tap::base_handle(sender, &mut buf[2..], len - 2, igmp_server, current_device, - ip_route, proxy_map).await; + ip_route, proxy_map, cipher).await; } _ => { // log::warn!("不支持的二层协议:{:?}",p) diff --git a/switch/src/handle/tun_tap/tun_handler.rs b/switch/src/handle/tun_tap/tun_handler.rs index 3dd3e9c..73331fa 100644 --- a/switch/src/handle/tun_tap/tun_handler.rs +++ b/switch/src/handle/tun_tap/tun_handler.rs @@ -1,5 +1,6 @@ use std::{io, thread}; use std::sync::Arc; +use aes_gcm::Aes256Gcm; use crossbeam::atomic::AtomicCell; @@ -35,7 +36,7 @@ fn icmp(device_writer: &DeviceWriter, mut ipv4_packet: IpV4Packet<&mut [u8]>) -> /// 接收tun数据,并且转发到udp上 #[inline] async fn handle(sender: &ChannelSender, data: &mut [u8], len: usize, device_writer: &DeviceWriter, igmp_server: &IgmpServer, current_device: CurrentDeviceInfo, - ip_route: &ExternalRoute, proxy_map: &IpProxyMap) -> Result<()> { + ip_route: &ExternalRoute, proxy_map: &IpProxyMap,cipher: &Option) -> Result<()> { let ipv4_packet = if let Ok(ipv4_packet) = IpV4Packet::new(&mut data[12..len]) { ipv4_packet } else { @@ -49,7 +50,7 @@ async fn handle(sender: &ChannelSender, data: &mut [u8], len: usize, device_writ if src_ip == dest_ip { return icmp(&device_writer, ipv4_packet); } - return crate::handle::tun_tap::base_handle(sender, data, len, igmp_server, current_device, ip_route, proxy_map).await; + return crate::handle::tun_tap::base_handle(sender, data, len, igmp_server, current_device, ip_route, proxy_map,cipher).await; } pub fn start(sender: ChannelSender, @@ -58,12 +59,13 @@ pub fn start(sender: ChannelSender, igmp_server: IgmpServer, current_device: Arc>, ip_route: ExternalRoute, - ip_proxy_map: IpProxyMap) { + ip_proxy_map: IpProxyMap, + cipher: Option) { thread::Builder::new().name("tun-handler".into()).spawn(move || { tokio::runtime::Builder::new_current_thread() .enable_all().build().unwrap() .block_on(async move { - if let Err(e) = start_(sender, device_reader, device_writer, igmp_server, current_device, ip_route, ip_proxy_map).await { + if let Err(e) = start_(sender, device_reader, device_writer, igmp_server, current_device, ip_route, ip_proxy_map,cipher).await { log::warn!("tun:{:?}",e); } }) @@ -76,11 +78,12 @@ async fn start_(sender: ChannelSender, igmp_server: IgmpServer, current_device: Arc>, ip_route: ExternalRoute, - ip_proxy_map: IpProxyMap) -> io::Result<()> { + ip_proxy_map: IpProxyMap, + cipher: Option) -> io::Result<()> { let mut buf = [0; 4096]; loop { let len = device_reader.read(&mut buf[12..])? + 12; - match handle(&sender, &mut buf, len, &device_writer, &igmp_server, current_device.load(), &ip_route, &ip_proxy_map).await { + match handle(&sender, &mut buf, len, &device_writer, &igmp_server, current_device.load(), &ip_route, &ip_proxy_map,&cipher).await { Ok(_) => {} Err(e) => { log::warn!("{:?}", e) diff --git a/switch/src/ip_proxy/icmp_proxy.rs b/switch/src/ip_proxy/icmp_proxy.rs index 0dda487..87ff7d9 100644 --- a/switch/src/ip_proxy/icmp_proxy.rs +++ b/switch/src/ip_proxy/icmp_proxy.rs @@ -67,7 +67,7 @@ impl IcmpProxy { let mut net_packet = NetPacket::new([0u8; 4 + 8 + 1500]).unwrap(); net_packet.set_version(Version::V1); net_packet.set_protocol(Protocol::IpTurn); - net_packet.set_transport_protocol(ipv4::protocol::Protocol::Ipv4.into()); + net_packet.set_transport_protocol(ipv4::protocol::Protocol::Icmp.into()); net_packet.set_ttl(MAX_TTL); loop { match self.recv(data) { diff --git a/switch/src/protocol/ip_turn_packet.rs b/switch/src/protocol/ip_turn_packet.rs index 11aa6c8..c2c5a86 100644 --- a/switch/src/protocol/ip_turn_packet.rs +++ b/switch/src/protocol/ip_turn_packet.rs @@ -3,6 +3,8 @@ use std::net::Ipv4Addr; #[derive(Copy, Clone, Eq, PartialEq, Debug)] pub enum Protocol { + Icmp, + Igmp, Ipv4, Ipv4Broadcast, Unknown(u8), @@ -11,6 +13,8 @@ pub enum Protocol { impl From for Protocol { fn from(value: u8) -> Self { match value { + 1 => Protocol::Icmp, + 2 => Protocol::Igmp, 4 => Protocol::Ipv4, 201 => Protocol::Ipv4Broadcast, val => Protocol::Unknown(val), @@ -21,6 +25,8 @@ impl From for Protocol { impl Into for Protocol { fn into(self) -> u8 { match self { + Protocol::Icmp => 1, + Protocol::Igmp => 2, Protocol::Ipv4 => 4, Protocol::Ipv4Broadcast => 201, Protocol::Unknown(val) => val, diff --git a/switch/src/protocol/mod.rs b/switch/src/protocol/mod.rs index 5ee818b..96f4a7a 100644 --- a/switch/src/protocol/mod.rs +++ b/switch/src/protocol/mod.rs @@ -5,7 +5,7 @@ use std::{fmt, io}; 0 15 31 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | 版本(8) | 协议(8) | 上层协议(8) | 初始ttl(4) | 生存时间(4) | + | p|unused| 版本(4) | 协议(8) | 上层协议(8) | 初始ttl(4) | 生存时间(4) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | 源ip地址(32) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ @@ -115,8 +115,11 @@ impl> NetPacket { } impl> NetPacket { + pub fn is_encrypt(&self) -> bool { + self.buffer.as_ref()[0] & 0x80 == 0x80 + } pub fn version(&self) -> Version { - Version::from(self.buffer.as_ref()[0]) + Version::from(self.buffer.as_ref()[0] & 0x0F) } pub fn protocol(&self) -> Protocol { Protocol::from(self.buffer.as_ref()[1]) @@ -144,11 +147,19 @@ impl> NetPacket { } impl + AsMut<[u8]>> NetPacket { - pub fn buffer_mut(&mut self)->&mut [u8]{ + pub fn buffer_mut(&mut self) -> &mut [u8] { self.buffer.as_mut() } + pub fn set_encrypt_flag(&mut self, is_encrypt: bool) { + if is_encrypt { + self.buffer.as_mut()[0] = self.buffer.as_ref()[0] | 0x80 + } else { + self.buffer.as_mut()[0] = self.buffer.as_ref()[0] & 0x7F + }; + } pub fn set_version(&mut self, version: Version) { - self.buffer.as_mut()[0] = version.into(); + let v: u8 = version.into(); + self.buffer.as_mut()[0] = (self.buffer.as_ref()[0] & 0xF0) | (0x0F & v); } pub fn set_protocol(&mut self, protocol: Protocol) { self.buffer.as_mut()[1] = protocol.into(); diff --git a/switch/src/tun_tap_device/unix.rs b/switch/src/tun_tap_device/unix.rs index 4b84242..3e2dd13 100644 --- a/switch/src/tun_tap_device/unix.rs +++ b/switch/src/tun_tap_device/unix.rs @@ -98,7 +98,7 @@ impl DeviceWriter { Self::write(self.packet_information, writer, &buf[14..]) } DeviceW::Tap((writer, mac)) => { - let source_mac = [buf[14 + 12], buf[14 + 13], buf[14 + 14], buf[14 + 15], 123, 234]; + let source_mac = [buf[14 + 12], buf[14 + 13], buf[14 + 14], buf[14 + 15], !mac[5], 234]; let mut ethernet_packet = EthernetPacket::unchecked(buf); ethernet_packet.set_source(&source_mac); ethernet_packet.set_destination(mac); diff --git a/switch/src/tun_tap_device/windows.rs b/switch/src/tun_tap_device/windows.rs index 5c5520b..fff6978 100644 --- a/switch/src/tun_tap_device/windows.rs +++ b/switch/src/tun_tap_device/windows.rs @@ -87,7 +87,7 @@ impl DeviceWriter { dev.send_packet(packet); } Device::Tap((dev, mac)) => { - let source_mac = [buf[14 + 12], buf[14 + 13], buf[14 + 14], buf[14 + 15], 123, 234]; + let source_mac = [buf[14 + 12], buf[14 + 13], buf[14 + 14], buf[14 + 15], !mac[5], 234]; let mut ethernet_packet = EthernetPacket::unchecked(buf); ethernet_packet.set_source(&source_mac); ethernet_packet.set_destination(mac); @@ -128,7 +128,9 @@ impl DeviceWriter { dev.add_route(address, netmask, gateway, 1)?; // 广播和组播路由 dev.add_route(Ipv4Addr::BROADCAST, Ipv4Addr::BROADCAST, gateway, 1)?; - dev.add_route(Ipv4Addr::from([224, 0, 0, 0]), Ipv4Addr::from([240, 0, 0, 0]), gateway, 1) + dev.add_route(Ipv4Addr::from([224, 0, 0, 0]), Ipv4Addr::from([240, 0, 0, 0]), gateway, 1)?; + delete_cache(); + Ok(()) } pub fn ip(&self) -> Ipv4Addr { self.ip.load() @@ -252,6 +254,7 @@ fn create_tun( // 广播和组播路由 tun_device.add_route(Ipv4Addr::BROADCAST, Ipv4Addr::BROADCAST, gateway, 1)?; tun_device.add_route(Ipv4Addr::from([224, 0, 0, 0]), Ipv4Addr::from([240, 0, 0, 0]), gateway, 1)?; + delete_cache(); let device = Arc::new(Device::Tun(tun_device)); println!("========TUN网卡配置========"); Ok(( @@ -260,6 +263,18 @@ fn create_tun( )) } } +fn delete_cache(){ + //清除路由缓存 + let delete_cache = "netsh interface ip delete destinationcache"; + let out = std::process::Command::new("cmd") + .arg("/C") + .arg(delete_cache) + .output() + .unwrap(); + if !out.status.success(){ + log::warn!("删除缓存失败:{:?}",out); + } +} fn delete_tun() { unsafe { @@ -304,6 +319,7 @@ fn create_tap( // 广播和组播路由 tap_device.add_route(Ipv4Addr::BROADCAST, Ipv4Addr::BROADCAST, gateway, 1)?; tap_device.add_route(Ipv4Addr::from([224, 0, 0, 0]), Ipv4Addr::from([240, 0, 0, 0]), gateway, 1)?; + delete_cache(); let tap = Arc::new(Device::Tap((tap_device, mac))); println!("========TAP网卡配置========"); Ok((