diff --git a/vnt-cli/src/command/entity.rs b/vnt-cli/src/command/entity.rs index ee10c28..154127f 100644 --- a/vnt-cli/src/command/entity.rs +++ b/vnt-cli/src/command/entity.rs @@ -36,5 +36,7 @@ pub struct DeviceItem { pub rt: String, pub status: String, pub client_secret: bool, + pub client_secret_hash: Vec, pub current_client_secret: bool, + pub current_client_secret_hash: Vec, } diff --git a/vnt-cli/src/command/mod.rs b/vnt-cli/src/command/mod.rs index cb78f55..e059c2c 100644 --- a/vnt-cli/src/command/mod.rs +++ b/vnt-cli/src/command/mod.rs @@ -85,6 +85,7 @@ pub fn command_list(vnt: &Vnt) -> Vec { let device_list = vnt.device_list(); let mut list = Vec::new(); let current_client_secret = vnt.client_encrypt(); + let client_encrypt_hash = vnt.client_encrypt_hash().unwrap_or(&[]); for peer in device_list { let name = peer.name; let virtual_ip = peer.virtual_ip.to_string(); @@ -153,7 +154,9 @@ pub fn command_list(vnt: &Vnt) -> Vec { rt, status, client_secret, + client_secret_hash: peer.client_secret_hash, current_client_secret, + current_client_secret_hash: client_encrypt_hash.to_vec(), }; list.push(item); } diff --git a/vnt-cli/src/console_out/mod.rs b/vnt-cli/src/console_out/mod.rs index dc096ed..557987d 100644 --- a/vnt-cli/src/console_out/mod.rs +++ b/vnt-cli/src/console_out/mod.rs @@ -21,6 +21,7 @@ pub fn console_info(status: Info) { 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); @@ -90,13 +91,17 @@ pub fn console_device_list(mut list: Vec) { ]); for item in list { if &item.status == "Online" { - if item.client_secret != item.current_client_secret { + if item.client_secret != item.current_client_secret + || (!item.current_client_secret_hash.is_empty() + && !item.client_secret_hash.is_empty() + && item.current_client_secret_hash != item.client_secret_hash) + { //加密状态不一致,无法通信的 out_list.push(vec![ (item.name, Style::new().red()), (item.virtual_ip, Style::new().red()), (item.status, Style::new().red()), - ("".to_string(), Style::new().red()), + ("Mismatch".to_string(), Style::new().red()), ("".to_string(), Style::new().red()), ]); } else { diff --git a/vnt/proto/message.proto b/vnt/proto/message.proto index b0073d6..47e9e97 100644 --- a/vnt/proto/message.proto +++ b/vnt/proto/message.proto @@ -24,6 +24,7 @@ message RegistrationRequest { fixed32 virtual_ip = 6; bool allow_ip_change = 7; bool client_secret = 8; + bytes client_secret_hash = 9; } message RegistrationResponse { @@ -41,6 +42,7 @@ message DeviceInfo { fixed32 virtual_ip = 2; uint32 device_status = 3; bool client_secret = 4; + bytes client_secret_hash = 5; } message DeviceList { diff --git a/vnt/src/cipher/cipher.rs b/vnt/src/cipher/cipher.rs index ad416be..5030f78 100644 --- a/vnt/src/cipher/cipher.rs +++ b/vnt/src/cipher/cipher.rs @@ -1,6 +1,7 @@ #[cfg(feature = "aes_ecb")] #[cfg(not(any(feature = "openssl-vendored", feature = "openssl")))] use crate::cipher::aes_ecb::AesEcbCipher; +use std::fmt::Display; #[cfg(feature = "aes_cbc")] use crate::cipher::aes_cbc::AesCbcCipher; @@ -48,6 +49,18 @@ pub enum CipherModel { None, } +impl Display for CipherModel { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let str = match self { + CipherModel::AesGcm => "aes_gcm".to_string(), + CipherModel::AesCbc => "aes_cbc".to_string(), + CipherModel::AesEcb => "aes_ecb".to_string(), + CipherModel::Sm4Cbc => "sm4_cbc".to_string(), + CipherModel::None => "none".to_string(), + }; + write!(f, "{}", str) + } +} impl FromStr for CipherModel { type Err = String; diff --git a/vnt/src/core/conn.rs b/vnt/src/core/conn.rs index f0bb8cf..4110a5a 100644 --- a/vnt/src/core/conn.rs +++ b/vnt/src/core/conn.rs @@ -7,6 +7,7 @@ use std::time::Duration; use crossbeam_utils::atomic::AtomicCell; use parking_lot::{Mutex, RwLock}; use rand::Rng; +use rsa::signature::digest::Digest; #[cfg(not(target_os = "android"))] use tun::device::IFace; @@ -43,6 +44,7 @@ pub struct Vnt { peer_nat_info_map: Arc>>, down_count_watcher: WatchU64Adder, up_count_watcher: WatchSingleU64Adder, + client_secret_hash: Option<[u8; 16]>, } impl Vnt { @@ -79,7 +81,14 @@ impl Vnt { config.name.clone(), config.token.clone(), config.ip, - config.password.is_some(), + config.password.as_ref().map(|v| { + let mut hasher = sha2::Sha256::new(); + hasher.update(config.cipher_model.to_string().as_bytes()); + hasher.update(v.as_bytes()); + hasher.update(config.token.as_bytes()); + let key: [u8; 32] = hasher.finalize().into(); + key[16..].try_into().unwrap() + }), config.server_encrypt, config.device_id.clone(), config.server_address_str.clone(), @@ -222,6 +231,7 @@ impl Vnt { let device_list = device_list.clone(); let down_count_watcher = down_count_watcher.clone(); let up_count_watcher = up_count_watcher.clone(); + let config_info = config_info.clone(); let current_device = current_device.clone(); if !config.use_channel_type.is_only_relay() { // 定时nat探测 @@ -262,6 +272,7 @@ impl Vnt { peer_nat_info_map, down_count_watcher, up_count_watcher, + client_secret_hash: config_info.client_secret_hash, }) } } @@ -350,6 +361,9 @@ impl Vnt { pub fn client_encrypt(&self) -> bool { self.config.password.is_some() } + pub fn client_encrypt_hash(&self) -> Option<&[u8]> { + self.client_secret_hash.as_ref().map(|v| v.as_ref()) + } pub fn current_device(&self) -> CurrentDeviceInfo { self.current_device.load() } diff --git a/vnt/src/handle/mod.rs b/vnt/src/handle/mod.rs index e4e97e6..3f8b9bf 100644 --- a/vnt/src/handle/mod.rs +++ b/vnt/src/handle/mod.rs @@ -32,15 +32,23 @@ pub struct PeerDeviceInfo { pub name: String, pub status: PeerDeviceStatus, pub client_secret: bool, + pub client_secret_hash: Vec, } impl PeerDeviceInfo { - pub fn new(virtual_ip: Ipv4Addr, name: String, status: u8, client_secret: bool) -> Self { + pub fn new( + virtual_ip: Ipv4Addr, + name: String, + status: u8, + client_secret: bool, + client_secret_hash: Vec, + ) -> Self { Self { virtual_ip, name, status: PeerDeviceStatus::from(status), client_secret, + client_secret_hash, } } } @@ -50,7 +58,7 @@ pub struct BaseConfigInfo { pub name: String, pub token: String, pub ip: Option, - pub client_secret: bool, + pub client_secret_hash: Option<[u8; 16]>, pub server_secret: bool, pub device_id: String, pub server_addr: String, @@ -61,7 +69,7 @@ impl BaseConfigInfo { name: String, token: String, ip: Option, - client_secret: bool, + client_secret_hash: Option<[u8; 16]>, server_secret: bool, device_id: String, server_addr: String, @@ -70,7 +78,7 @@ impl BaseConfigInfo { name, token, ip, - client_secret, + client_secret_hash, server_secret, device_id, server_addr, diff --git a/vnt/src/handle/recv_data/server.rs b/vnt/src/handle/recv_data/server.rs index 77bb122..58c6408 100644 --- a/vnt/src/handle/recv_data/server.rs +++ b/vnt/src/handle/recv_data/server.rs @@ -418,6 +418,7 @@ impl ServerPacketHandler { info.name, info.device_status as u8, info.client_secret, + info.client_secret_hash, ) }) .collect(); @@ -442,7 +443,11 @@ impl ServerPacketHandler { let token = self.config_info.token.clone(); let device_id = self.config_info.device_id.clone(); let name = self.config_info.name.clone(); - let client_secret = self.config_info.client_secret; + let client_secret = self + .config_info + .client_secret_hash + .as_ref() + .map(|v| v.as_ref()); let mut ip = self.config_info.ip; if ip.is_none() { ip = Some(current_device.virtual_ip) diff --git a/vnt/src/handle/registrar.rs b/vnt/src/handle/registrar.rs index b230923..641dd26 100644 --- a/vnt/src/handle/registrar.rs +++ b/vnt/src/handle/registrar.rs @@ -18,7 +18,7 @@ pub fn registration_request_packet( ip: Option, is_fast: bool, allow_ip_change: bool, - client_secret: bool, + client_secret_hash: Option<&[u8]>, ) -> io::Result>> { let mut request = RegistrationRequest::new(); request.token = token; @@ -30,7 +30,12 @@ pub fn registration_request_packet( request.allow_ip_change = allow_ip_change; request.is_fast = is_fast; request.version = crate::VNT_VERSION.to_string(); - request.client_secret = client_secret; + if let Some(client_secret_hash) = client_secret_hash { + request.client_secret = true; + request + .client_secret_hash + .extend_from_slice(client_secret_hash); + } let bytes = request.write_to_bytes().map_err(|e| { io::Error::new(io::ErrorKind::Other, format!("RegistrationRequest {:?}", e)) })?;