feat(encrypt): Add XOR and ChaCha20 encryption with low-end device optimization and openssl support. (#1186)
Add ChaCha20 XOR algorithm, extend AES-GCM-256 capabilities, and integrate OpenSSL support. --------- Co-authored-by: Sijie.Sun <sunsijie@buaa.edu.cn>
This commit is contained in:
Generated
+11
@@ -2033,6 +2033,7 @@ dependencies = [
|
|||||||
"network-interface",
|
"network-interface",
|
||||||
"nix 0.29.0",
|
"nix 0.29.0",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
|
"openssl",
|
||||||
"parking_lot",
|
"parking_lot",
|
||||||
"percent-encoding",
|
"percent-encoding",
|
||||||
"petgraph 0.8.1",
|
"petgraph 0.8.1",
|
||||||
@@ -5234,6 +5235,15 @@ version = "0.1.5"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
|
checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "openssl-src"
|
||||||
|
version = "300.5.2+3.5.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d270b79e2926f5150189d475bc7e9d2c69f9c4697b185fa917d5a32b792d21b4"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "openssl-sys"
|
name = "openssl-sys"
|
||||||
version = "0.9.103"
|
version = "0.9.103"
|
||||||
@@ -5242,6 +5252,7 @@ checksum = "7f9e8deee91df40a943c71b917e5874b951d32a802526c85721ce3b776c929d6"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"cc",
|
"cc",
|
||||||
"libc",
|
"libc",
|
||||||
|
"openssl-src",
|
||||||
"pkg-config",
|
"pkg-config",
|
||||||
"vcpkg",
|
"vcpkg",
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -150,6 +150,7 @@ boringtun = { package = "boringtun-easytier", version = "0.6.1", optional = true
|
|||||||
ring = { version = "0.17", optional = true }
|
ring = { version = "0.17", optional = true }
|
||||||
bitflags = "2.5"
|
bitflags = "2.5"
|
||||||
aes-gcm = { version = "0.10.3", optional = true }
|
aes-gcm = { version = "0.10.3", optional = true }
|
||||||
|
openssl = { version = "0.10", optional = true, features = ["vendored"] }
|
||||||
|
|
||||||
# for cli
|
# for cli
|
||||||
tabled = "0.16"
|
tabled = "0.16"
|
||||||
@@ -298,6 +299,7 @@ full = [
|
|||||||
"websocket",
|
"websocket",
|
||||||
"wireguard",
|
"wireguard",
|
||||||
"aes-gcm",
|
"aes-gcm",
|
||||||
|
"openssl-crypto", # need openssl-dev libs
|
||||||
"smoltcp",
|
"smoltcp",
|
||||||
"tun",
|
"tun",
|
||||||
"socks5",
|
"socks5",
|
||||||
@@ -306,6 +308,7 @@ wireguard = ["dep:boringtun", "dep:ring"]
|
|||||||
quic = ["dep:quinn", "dep:rustls", "dep:rcgen"]
|
quic = ["dep:quinn", "dep:rustls", "dep:rcgen"]
|
||||||
mimalloc = ["dep:mimalloc"]
|
mimalloc = ["dep:mimalloc"]
|
||||||
aes-gcm = ["dep:aes-gcm"]
|
aes-gcm = ["dep:aes-gcm"]
|
||||||
|
openssl-crypto = ["dep:openssl"]
|
||||||
tun = ["dep:tun"]
|
tun = ["dep:tun"]
|
||||||
websocket = [
|
websocket = [
|
||||||
"dep:tokio-websockets",
|
"dep:tokio-websockets",
|
||||||
|
|||||||
@@ -95,6 +95,9 @@ core_clap:
|
|||||||
disable_encryption:
|
disable_encryption:
|
||||||
en: "disable encryption for peers communication, default is false, must be same with peers"
|
en: "disable encryption for peers communication, default is false, must be same with peers"
|
||||||
zh-CN: "禁用对等节点通信的加密,默认为false,必须与对等节点相同"
|
zh-CN: "禁用对等节点通信的加密,默认为false,必须与对等节点相同"
|
||||||
|
encryption_algorithm:
|
||||||
|
en: "encryption algorithm to use, supported: '', 'xor', 'chacha20', 'aes-gcm', 'aes-gcm-256', 'openssl-aes128-gcm', 'openssl-aes256-gcm', 'openssl-chacha20'. Empty string means default (aes-gcm)"
|
||||||
|
zh-CN: "要使用的加密算法,支持:''(默认aes-gcm)、'xor'、'chacha20'、'aes-gcm'、'aes-gcm-256'、'openssl-aes128-gcm'、'openssl-aes256-gcm'、'openssl-chacha20'"
|
||||||
multi_thread:
|
multi_thread:
|
||||||
en: "use multi-thread runtime, default is single-thread"
|
en: "use multi-thread runtime, default is single-thread"
|
||||||
zh-CN: "使用多线程运行时,默认为单线程"
|
zh-CN: "使用多线程运行时,默认为单线程"
|
||||||
|
|||||||
@@ -48,9 +48,79 @@ pub fn gen_default_flags() -> Flags {
|
|||||||
disable_quic_input: false,
|
disable_quic_input: false,
|
||||||
foreign_relay_bps_limit: u64::MAX,
|
foreign_relay_bps_limit: u64::MAX,
|
||||||
multi_thread_count: 2,
|
multi_thread_count: 2,
|
||||||
|
encryption_algorithm: "".to_string(), // 空字符串表示使用默认的 AES-GCM
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub enum EncryptionAlgorithm {
|
||||||
|
AesGcm,
|
||||||
|
Aes256Gcm,
|
||||||
|
Xor,
|
||||||
|
#[cfg(feature = "wireguard")]
|
||||||
|
ChaCha20,
|
||||||
|
|
||||||
|
#[cfg(feature = "openssl-crypto")]
|
||||||
|
OpensslAesGcm,
|
||||||
|
#[cfg(feature = "openssl-crypto")]
|
||||||
|
OpensslChacha20,
|
||||||
|
#[cfg(feature = "openssl-crypto")]
|
||||||
|
OpensslAes256Gcm,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Display for EncryptionAlgorithm {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
Self::AesGcm => write!(f, "aes-gcm"),
|
||||||
|
Self::Aes256Gcm => write!(f, "aes-256-gcm"),
|
||||||
|
Self::Xor => write!(f, "xor"),
|
||||||
|
#[cfg(feature = "wireguard")]
|
||||||
|
Self::ChaCha20 => write!(f, "chacha20"),
|
||||||
|
#[cfg(feature = "openssl-crypto")]
|
||||||
|
Self::OpensslAesGcm => write!(f, "openssl-aes-gcm"),
|
||||||
|
#[cfg(feature = "openssl-crypto")]
|
||||||
|
Self::OpensslChacha20 => write!(f, "openssl-chacha20"),
|
||||||
|
#[cfg(feature = "openssl-crypto")]
|
||||||
|
Self::OpensslAes256Gcm => write!(f, "openssl-aes-256-gcm"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<&str> for EncryptionAlgorithm {
|
||||||
|
type Error = anyhow::Error;
|
||||||
|
|
||||||
|
fn try_from(value: &str) -> Result<Self, Self::Error> {
|
||||||
|
match value {
|
||||||
|
"aes-gcm" => Ok(Self::AesGcm),
|
||||||
|
"aes-256-gcm" => Ok(Self::Aes256Gcm),
|
||||||
|
"xor" => Ok(Self::Xor),
|
||||||
|
#[cfg(feature = "wireguard")]
|
||||||
|
"chacha20" => Ok(Self::ChaCha20),
|
||||||
|
#[cfg(feature = "openssl-crypto")]
|
||||||
|
"openssl-aes-gcm" => Ok(Self::OpensslAesGcm),
|
||||||
|
#[cfg(feature = "openssl-crypto")]
|
||||||
|
"openssl-chacha20" => Ok(Self::OpensslChacha20),
|
||||||
|
#[cfg(feature = "openssl-crypto")]
|
||||||
|
"openssl-aes-256-gcm" => Ok(Self::OpensslAes256Gcm),
|
||||||
|
_ => Err(anyhow::anyhow!("invalid encryption algorithm")),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_avaliable_encrypt_methods() -> Vec<&'static str> {
|
||||||
|
let mut r = vec!["aes-gcm", "aes-256-gcm", "xor"];
|
||||||
|
if cfg!(feature = "wireguard") {
|
||||||
|
r.push("chacha20");
|
||||||
|
}
|
||||||
|
if cfg!(feature = "openssl-crypto") {
|
||||||
|
r.extend(vec![
|
||||||
|
"openssl-aes-gcm",
|
||||||
|
"openssl-chacha20",
|
||||||
|
"openssl-aes-256-gcm",
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
r
|
||||||
|
}
|
||||||
|
|
||||||
#[auto_impl::auto_impl(Box, &)]
|
#[auto_impl::auto_impl(Box, &)]
|
||||||
pub trait ConfigLoader: Send + Sync {
|
pub trait ConfigLoader: Send + Sync {
|
||||||
fn get_id(&self) -> uuid::Uuid;
|
fn get_id(&self) -> uuid::Uuid;
|
||||||
|
|||||||
@@ -296,6 +296,29 @@ impl GlobalCtx {
|
|||||||
key
|
key
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_256_key(&self) -> [u8; 32] {
|
||||||
|
let mut key = [0u8; 32];
|
||||||
|
let secret = self
|
||||||
|
.config
|
||||||
|
.get_network_identity()
|
||||||
|
.network_secret
|
||||||
|
.unwrap_or_default();
|
||||||
|
// fill key according to network secret
|
||||||
|
let mut hasher = DefaultHasher::new();
|
||||||
|
hasher.write(secret.as_bytes());
|
||||||
|
hasher.write(b"easytier-256bit-key"); // 添加固定盐值以区分128位和256位密钥
|
||||||
|
|
||||||
|
// 生成32字节密钥
|
||||||
|
for i in 0..4 {
|
||||||
|
let chunk_start = i * 8;
|
||||||
|
let chunk_end = chunk_start + 8;
|
||||||
|
hasher.write(&key[0..chunk_start]);
|
||||||
|
hasher.write(&[i as u8]); // 添加索引以确保每个8字节块都不同
|
||||||
|
key[chunk_start..chunk_end].copy_from_slice(&hasher.finish().to_be_bytes());
|
||||||
|
}
|
||||||
|
key
|
||||||
|
}
|
||||||
|
|
||||||
pub fn enable_exit_node(&self) -> bool {
|
pub fn enable_exit_node(&self) -> bool {
|
||||||
self.enable_exit_node
|
self.enable_exit_node
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,8 +18,9 @@ use clap_complete::Shell;
|
|||||||
use easytier::{
|
use easytier::{
|
||||||
common::{
|
common::{
|
||||||
config::{
|
config::{
|
||||||
ConfigLoader, ConsoleLoggerConfig, FileLoggerConfig, LoggingConfigLoader,
|
get_avaliable_encrypt_methods, ConfigLoader, ConsoleLoggerConfig, FileLoggerConfig,
|
||||||
NetworkIdentity, PeerConfig, PortForwardConfig, TomlConfigLoader, VpnPortalConfig,
|
LoggingConfigLoader, NetworkIdentity, PeerConfig, PortForwardConfig, TomlConfigLoader,
|
||||||
|
VpnPortalConfig,
|
||||||
},
|
},
|
||||||
constants::EASYTIER_VERSION,
|
constants::EASYTIER_VERSION,
|
||||||
global_ctx::GlobalCtx,
|
global_ctx::GlobalCtx,
|
||||||
@@ -283,6 +284,15 @@ struct NetworkOptions {
|
|||||||
)]
|
)]
|
||||||
disable_encryption: Option<bool>,
|
disable_encryption: Option<bool>,
|
||||||
|
|
||||||
|
#[arg(
|
||||||
|
long,
|
||||||
|
env = "ET_ENCRYPTION_ALGORITHM",
|
||||||
|
help = t!("core_clap.encryption_algorithm").to_string(),
|
||||||
|
default_value = "aes-gcm",
|
||||||
|
value_parser = get_avaliable_encrypt_methods()
|
||||||
|
)]
|
||||||
|
encryption_algorithm: Option<String>,
|
||||||
|
|
||||||
#[arg(
|
#[arg(
|
||||||
long,
|
long,
|
||||||
env = "ET_MULTI_THREAD",
|
env = "ET_MULTI_THREAD",
|
||||||
@@ -846,6 +856,9 @@ impl NetworkOptions {
|
|||||||
if let Some(v) = self.disable_encryption {
|
if let Some(v) = self.disable_encryption {
|
||||||
f.enable_encryption = !v;
|
f.enable_encryption = !v;
|
||||||
}
|
}
|
||||||
|
if let Some(algorithm) = &self.encryption_algorithm {
|
||||||
|
f.encryption_algorithm = algorithm.clone();
|
||||||
|
}
|
||||||
if let Some(v) = self.disable_ipv6 {
|
if let Some(v) = self.disable_ipv6 {
|
||||||
f.enable_ipv6 = !v;
|
f.enable_ipv6 = !v;
|
||||||
}
|
}
|
||||||
@@ -894,7 +907,9 @@ impl NetworkOptions {
|
|||||||
.unwrap_or(f.foreign_relay_bps_limit);
|
.unwrap_or(f.foreign_relay_bps_limit);
|
||||||
f.multi_thread_count = self.multi_thread_count.unwrap_or(f.multi_thread_count);
|
f.multi_thread_count = self.multi_thread_count.unwrap_or(f.multi_thread_count);
|
||||||
f.disable_relay_kcp = self.disable_relay_kcp.unwrap_or(f.disable_relay_kcp);
|
f.disable_relay_kcp = self.disable_relay_kcp.unwrap_or(f.disable_relay_kcp);
|
||||||
f.enable_relay_foreign_network_kcp = self.enable_relay_foreign_network_kcp.unwrap_or(f.enable_relay_foreign_network_kcp);
|
f.enable_relay_foreign_network_kcp = self
|
||||||
|
.enable_relay_foreign_network_kcp
|
||||||
|
.unwrap_or(f.enable_relay_foreign_network_kcp);
|
||||||
cfg.set_flags(f);
|
cfg.set_flags(f);
|
||||||
|
|
||||||
if !self.exit_nodes.is_empty() {
|
if !self.exit_nodes.is_empty() {
|
||||||
|
|||||||
@@ -1,11 +1,21 @@
|
|||||||
use crate::tunnel::packet_def::ZCPacket;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use crate::{common::config::EncryptionAlgorithm, tunnel::packet_def::ZCPacket};
|
||||||
|
|
||||||
#[cfg(feature = "wireguard")]
|
#[cfg(feature = "wireguard")]
|
||||||
pub mod ring_aes_gcm;
|
pub mod ring_aes_gcm;
|
||||||
|
|
||||||
|
#[cfg(feature = "wireguard")]
|
||||||
|
pub mod ring_chacha20;
|
||||||
|
|
||||||
#[cfg(feature = "aes-gcm")]
|
#[cfg(feature = "aes-gcm")]
|
||||||
pub mod aes_gcm;
|
pub mod aes_gcm;
|
||||||
|
|
||||||
|
#[cfg(feature = "openssl-crypto")]
|
||||||
|
pub mod openssl_cipher;
|
||||||
|
|
||||||
|
pub mod xor_cipher;
|
||||||
|
|
||||||
#[derive(thiserror::Error, Debug)]
|
#[derive(thiserror::Error, Debug)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
#[error("packet is too short. len: {0}")]
|
#[error("packet is too short. len: {0}")]
|
||||||
@@ -39,3 +49,70 @@ impl Encryptor for NullCipher {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Create an encryptor based on the algorithm name
|
||||||
|
pub fn create_encryptor(
|
||||||
|
algorithm: &str,
|
||||||
|
key_128: [u8; 16],
|
||||||
|
key_256: [u8; 32],
|
||||||
|
) -> Arc<dyn Encryptor> {
|
||||||
|
let algorithm = match EncryptionAlgorithm::try_from(algorithm) {
|
||||||
|
Ok(algorithm) => algorithm,
|
||||||
|
Err(_) => {
|
||||||
|
eprintln!(
|
||||||
|
"Unknown encryption algorithm: {}, falling back to default AES-GCM",
|
||||||
|
algorithm
|
||||||
|
);
|
||||||
|
EncryptionAlgorithm::AesGcm
|
||||||
|
}
|
||||||
|
};
|
||||||
|
match algorithm {
|
||||||
|
EncryptionAlgorithm::AesGcm => {
|
||||||
|
#[cfg(feature = "wireguard")]
|
||||||
|
{
|
||||||
|
Arc::new(ring_aes_gcm::AesGcmCipher::new_128(key_128))
|
||||||
|
}
|
||||||
|
#[cfg(all(feature = "aes-gcm", not(feature = "wireguard")))]
|
||||||
|
{
|
||||||
|
Arc::new(aes_gcm::AesGcmCipher::new_128(key_128))
|
||||||
|
}
|
||||||
|
#[cfg(all(not(feature = "wireguard"), not(feature = "aes-gcm")))]
|
||||||
|
{
|
||||||
|
compile_error!(
|
||||||
|
"wireguard or aes-gcm feature must be enabled for default encryption"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
EncryptionAlgorithm::Aes256Gcm => {
|
||||||
|
#[cfg(feature = "wireguard")]
|
||||||
|
{
|
||||||
|
Arc::new(ring_aes_gcm::AesGcmCipher::new_256(key_256))
|
||||||
|
}
|
||||||
|
#[cfg(all(feature = "aes-gcm", not(feature = "wireguard")))]
|
||||||
|
{
|
||||||
|
Arc::new(aes_gcm::AesGcmCipher::new_256(key_256))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
EncryptionAlgorithm::Xor => Arc::new(xor_cipher::XorCipher::new(&key_128)),
|
||||||
|
|
||||||
|
#[cfg(feature = "wireguard")]
|
||||||
|
EncryptionAlgorithm::ChaCha20 => Arc::new(ring_chacha20::RingChaCha20Cipher::new(key_256)),
|
||||||
|
|
||||||
|
#[cfg(feature = "openssl-crypto")]
|
||||||
|
EncryptionAlgorithm::OpensslAesGcm => {
|
||||||
|
Arc::new(openssl_cipher::OpenSslCipher::new_aes128_gcm(key_128))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "openssl-crypto")]
|
||||||
|
EncryptionAlgorithm::OpensslAes256Gcm => {
|
||||||
|
Arc::new(openssl_cipher::OpenSslCipher::new_aes256_gcm(key_256))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "openssl-crypto")]
|
||||||
|
EncryptionAlgorithm::OpensslChacha20 => {
|
||||||
|
Arc::new(openssl_cipher::OpenSslCipher::new_chacha20(key_256))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,241 @@
|
|||||||
|
use openssl::symm::{Cipher, Crypter, Mode};
|
||||||
|
use rand::RngCore;
|
||||||
|
use zerocopy::{AsBytes, FromBytes, FromZeroes};
|
||||||
|
|
||||||
|
use crate::tunnel::packet_def::ZCPacket;
|
||||||
|
|
||||||
|
use crate::peers::encrypt::{Encryptor, Error};
|
||||||
|
|
||||||
|
// OpenSSL 加密尾部结构
|
||||||
|
#[repr(C, packed)]
|
||||||
|
#[derive(AsBytes, FromBytes, FromZeroes, Clone, Debug, Default)]
|
||||||
|
pub struct OpenSslTail {
|
||||||
|
pub nonce: [u8; 16], // 使用 16 字节的 nonce/IV
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const OPENSSL_ENCRYPTION_RESERVED: usize = std::mem::size_of::<OpenSslTail>();
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct OpenSslCipher {
|
||||||
|
pub(crate) cipher: OpenSslEnum,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum OpenSslEnum {
|
||||||
|
Aes128Gcm([u8; 16]),
|
||||||
|
Aes256Gcm([u8; 32]),
|
||||||
|
Chacha20([u8; 32]),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Clone for OpenSslEnum {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
match &self {
|
||||||
|
OpenSslEnum::Aes128Gcm(key) => OpenSslEnum::Aes128Gcm(*key),
|
||||||
|
OpenSslEnum::Aes256Gcm(key) => OpenSslEnum::Aes256Gcm(*key),
|
||||||
|
OpenSslEnum::Chacha20(key) => OpenSslEnum::Chacha20(*key),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl OpenSslCipher {
|
||||||
|
pub fn new_aes128_gcm(key: [u8; 16]) -> Self {
|
||||||
|
Self {
|
||||||
|
cipher: OpenSslEnum::Aes128Gcm(key),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_aes256_gcm(key: [u8; 32]) -> Self {
|
||||||
|
Self {
|
||||||
|
cipher: OpenSslEnum::Aes256Gcm(key),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_chacha20(key: [u8; 32]) -> Self {
|
||||||
|
Self {
|
||||||
|
cipher: OpenSslEnum::Chacha20(key),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_cipher_and_key(&self) -> (Cipher, &[u8]) {
|
||||||
|
match &self.cipher {
|
||||||
|
OpenSslEnum::Aes128Gcm(key) => (Cipher::aes_128_gcm(), key.as_slice()),
|
||||||
|
OpenSslEnum::Aes256Gcm(key) => (Cipher::aes_256_gcm(), key.as_slice()),
|
||||||
|
OpenSslEnum::Chacha20(key) => (Cipher::chacha20_poly1305(), key.as_slice()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_aead_cipher(&self) -> bool {
|
||||||
|
matches!(
|
||||||
|
self.cipher,
|
||||||
|
OpenSslEnum::Aes128Gcm(_) | OpenSslEnum::Aes256Gcm(_) | OpenSslEnum::Chacha20(_)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_nonce_size(&self) -> usize {
|
||||||
|
match &self.cipher {
|
||||||
|
OpenSslEnum::Aes128Gcm(_) | OpenSslEnum::Aes256Gcm(_) | OpenSslEnum::Chacha20(_) => 12, // GCM and ChaCha20-Poly1305 use 12-byte nonce
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Encryptor for OpenSslCipher {
|
||||||
|
fn decrypt(&self, zc_packet: &mut ZCPacket) -> Result<(), Error> {
|
||||||
|
let pm_header = zc_packet.peer_manager_header().unwrap();
|
||||||
|
if !pm_header.is_encrypted() {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
let payload_len = zc_packet.payload().len();
|
||||||
|
if payload_len < OPENSSL_ENCRYPTION_RESERVED {
|
||||||
|
return Err(Error::PacketTooShort(zc_packet.payload().len()));
|
||||||
|
}
|
||||||
|
|
||||||
|
let (cipher, key) = self.get_cipher_and_key();
|
||||||
|
let is_aead = self.is_aead_cipher();
|
||||||
|
let nonce_size = self.get_nonce_size();
|
||||||
|
|
||||||
|
// 提取 nonce/IV
|
||||||
|
let openssl_tail = OpenSslTail::ref_from_suffix(zc_packet.payload())
|
||||||
|
.unwrap()
|
||||||
|
.clone();
|
||||||
|
|
||||||
|
let text_len = if is_aead {
|
||||||
|
payload_len - OPENSSL_ENCRYPTION_RESERVED - 16 // AEAD 需要减去 tag 长度
|
||||||
|
} else {
|
||||||
|
payload_len - OPENSSL_ENCRYPTION_RESERVED
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut decrypter = Crypter::new(
|
||||||
|
cipher,
|
||||||
|
Mode::Decrypt,
|
||||||
|
key,
|
||||||
|
Some(&openssl_tail.nonce[..nonce_size]),
|
||||||
|
)
|
||||||
|
.map_err(|_| Error::DecryptionFailed)?;
|
||||||
|
|
||||||
|
if is_aead {
|
||||||
|
// 对于 AEAD 模式,需要设置 tag
|
||||||
|
let tag_start = text_len;
|
||||||
|
let tag = &zc_packet.payload()[tag_start..tag_start + 16];
|
||||||
|
decrypter
|
||||||
|
.set_tag(tag)
|
||||||
|
.map_err(|_| Error::DecryptionFailed)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut output = vec![0u8; text_len + cipher.block_size()];
|
||||||
|
let mut count = decrypter
|
||||||
|
.update(&zc_packet.payload()[..text_len], &mut output)
|
||||||
|
.map_err(|_| Error::DecryptionFailed)?;
|
||||||
|
|
||||||
|
count += decrypter
|
||||||
|
.finalize(&mut output[count..])
|
||||||
|
.map_err(|_| Error::DecryptionFailed)?;
|
||||||
|
|
||||||
|
// 更新数据包
|
||||||
|
zc_packet.mut_payload()[..count].copy_from_slice(&output[..count]);
|
||||||
|
let pm_header = zc_packet.mut_peer_manager_header().unwrap();
|
||||||
|
pm_header.set_encrypted(false);
|
||||||
|
let old_len = zc_packet.buf_len();
|
||||||
|
let new_len = old_len - (payload_len - count);
|
||||||
|
zc_packet.mut_inner().truncate(new_len);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn encrypt(&self, zc_packet: &mut ZCPacket) -> Result<(), Error> {
|
||||||
|
let pm_header = zc_packet.peer_manager_header().unwrap();
|
||||||
|
if pm_header.is_encrypted() {
|
||||||
|
tracing::warn!(?zc_packet, "packet is already encrypted");
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
let (cipher, key) = self.get_cipher_and_key();
|
||||||
|
let is_aead = self.is_aead_cipher();
|
||||||
|
let nonce_size = self.get_nonce_size();
|
||||||
|
|
||||||
|
let mut tail = OpenSslTail::default();
|
||||||
|
rand::thread_rng().fill_bytes(&mut tail.nonce[..nonce_size]);
|
||||||
|
|
||||||
|
let mut encrypter =
|
||||||
|
Crypter::new(cipher, Mode::Encrypt, key, Some(&tail.nonce[..nonce_size]))
|
||||||
|
.map_err(|_| Error::EncryptionFailed)?;
|
||||||
|
|
||||||
|
let payload_len = zc_packet.payload().len();
|
||||||
|
let mut output = vec![0u8; payload_len + cipher.block_size()];
|
||||||
|
|
||||||
|
let mut count = encrypter
|
||||||
|
.update(zc_packet.payload(), &mut output)
|
||||||
|
.map_err(|_| Error::EncryptionFailed)?;
|
||||||
|
|
||||||
|
count += encrypter
|
||||||
|
.finalize(&mut output[count..])
|
||||||
|
.map_err(|_| Error::EncryptionFailed)?;
|
||||||
|
|
||||||
|
// 更新数据包内容
|
||||||
|
zc_packet.mut_payload()[..count].copy_from_slice(&output[..count]);
|
||||||
|
|
||||||
|
// 对于 AEAD 模式,添加 tag
|
||||||
|
if is_aead {
|
||||||
|
let mut tag = vec![0u8; 16]; // GCM 标签通常是 16 字节
|
||||||
|
encrypter
|
||||||
|
.get_tag(&mut tag)
|
||||||
|
.map_err(|_| Error::EncryptionFailed)?;
|
||||||
|
zc_packet.mut_inner().extend_from_slice(&tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加 nonce/IV
|
||||||
|
zc_packet.mut_inner().extend_from_slice(tail.as_bytes());
|
||||||
|
|
||||||
|
let pm_header = zc_packet.mut_peer_manager_header().unwrap();
|
||||||
|
pm_header.set_encrypted(true);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use crate::{
|
||||||
|
peers::encrypt::{openssl_cipher::OpenSslCipher, Encryptor},
|
||||||
|
tunnel::packet_def::ZCPacket,
|
||||||
|
};
|
||||||
|
|
||||||
|
use super::OPENSSL_ENCRYPTION_RESERVED;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_openssl_aes128_gcm() {
|
||||||
|
let key = [0u8; 16];
|
||||||
|
let cipher = OpenSslCipher::new_aes128_gcm(key);
|
||||||
|
let text = b"Hello, World! This is a test message for OpenSSL AES-128-GCM.";
|
||||||
|
let mut packet = ZCPacket::new_with_payload(text);
|
||||||
|
packet.fill_peer_manager_hdr(0, 0, 0);
|
||||||
|
|
||||||
|
// 加密
|
||||||
|
cipher.encrypt(&mut packet).unwrap();
|
||||||
|
assert!(packet.payload().len() > text.len() + OPENSSL_ENCRYPTION_RESERVED);
|
||||||
|
assert_eq!(packet.peer_manager_header().unwrap().is_encrypted(), true);
|
||||||
|
|
||||||
|
// 解密
|
||||||
|
cipher.decrypt(&mut packet).unwrap();
|
||||||
|
assert_eq!(packet.payload(), text);
|
||||||
|
assert_eq!(packet.peer_manager_header().unwrap().is_encrypted(), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_openssl_chacha20() {
|
||||||
|
let key = [0u8; 32];
|
||||||
|
let cipher = OpenSslCipher::new_chacha20(key);
|
||||||
|
let text = b"Hello, World! This is a test message for OpenSSL ChaCha20.";
|
||||||
|
let mut packet = ZCPacket::new_with_payload(text);
|
||||||
|
packet.fill_peer_manager_hdr(0, 0, 0);
|
||||||
|
|
||||||
|
// 加密
|
||||||
|
cipher.encrypt(&mut packet).unwrap();
|
||||||
|
assert!(packet.payload().len() > text.len());
|
||||||
|
assert_eq!(packet.peer_manager_header().unwrap().is_encrypted(), true);
|
||||||
|
|
||||||
|
// 解密
|
||||||
|
cipher.decrypt(&mut packet).unwrap();
|
||||||
|
assert_eq!(packet.payload(), text);
|
||||||
|
assert_eq!(packet.peer_manager_header().unwrap().is_encrypted(), false);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,125 @@
|
|||||||
|
use rand::RngCore;
|
||||||
|
use ring::aead::{self, Aad, LessSafeKey, Nonce, UnboundKey};
|
||||||
|
use zerocopy::{AsBytes, FromBytes, FromZeroes};
|
||||||
|
|
||||||
|
use super::{Encryptor, Error};
|
||||||
|
use crate::tunnel::packet_def::ZCPacket;
|
||||||
|
|
||||||
|
#[repr(C, packed)]
|
||||||
|
#[derive(AsBytes, FromBytes, FromZeroes, Clone, Debug, Default)]
|
||||||
|
pub struct ChaCha20Poly1305Tail {
|
||||||
|
pub tag: [u8; 16],
|
||||||
|
pub nonce: [u8; 12],
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const CHACHA20_POLY1305_ENCRYPTION_RESERVED: usize =
|
||||||
|
std::mem::size_of::<ChaCha20Poly1305Tail>();
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct RingChaCha20Cipher {
|
||||||
|
cipher: LessSafeKey,
|
||||||
|
key: [u8; 32],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RingChaCha20Cipher {
|
||||||
|
pub fn new(key: [u8; 32]) -> Self {
|
||||||
|
let unbound_key = UnboundKey::new(&aead::CHACHA20_POLY1305, &key).unwrap();
|
||||||
|
let cipher = LessSafeKey::new(unbound_key);
|
||||||
|
Self { cipher, key }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Encryptor for RingChaCha20Cipher {
|
||||||
|
fn decrypt(&self, zc_packet: &mut ZCPacket) -> Result<(), Error> {
|
||||||
|
let pm_header = zc_packet.peer_manager_header().unwrap();
|
||||||
|
if !pm_header.is_encrypted() {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
let payload_len = zc_packet.payload().len();
|
||||||
|
if payload_len < CHACHA20_POLY1305_ENCRYPTION_RESERVED {
|
||||||
|
return Err(Error::PacketTooShort(zc_packet.payload().len()));
|
||||||
|
}
|
||||||
|
|
||||||
|
let text_and_tag_len = payload_len - CHACHA20_POLY1305_ENCRYPTION_RESERVED + 16;
|
||||||
|
|
||||||
|
let chacha20_tail = ChaCha20Poly1305Tail::ref_from_suffix(zc_packet.payload()).unwrap();
|
||||||
|
let nonce = Nonce::assume_unique_for_key(chacha20_tail.nonce.clone());
|
||||||
|
|
||||||
|
let rs = self.cipher.open_in_place(
|
||||||
|
nonce,
|
||||||
|
Aad::empty(),
|
||||||
|
&mut zc_packet.mut_payload()[..text_and_tag_len],
|
||||||
|
);
|
||||||
|
|
||||||
|
if rs.is_err() {
|
||||||
|
return Err(Error::DecryptionFailed);
|
||||||
|
}
|
||||||
|
|
||||||
|
let pm_header = zc_packet.mut_peer_manager_header().unwrap();
|
||||||
|
pm_header.set_encrypted(false);
|
||||||
|
let old_len = zc_packet.buf_len();
|
||||||
|
zc_packet
|
||||||
|
.mut_inner()
|
||||||
|
.truncate(old_len - CHACHA20_POLY1305_ENCRYPTION_RESERVED);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn encrypt(&self, zc_packet: &mut ZCPacket) -> Result<(), Error> {
|
||||||
|
let pm_header = zc_packet.peer_manager_header().unwrap();
|
||||||
|
if pm_header.is_encrypted() {
|
||||||
|
tracing::warn!(?zc_packet, "packet is already encrypted");
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut tail = ChaCha20Poly1305Tail::default();
|
||||||
|
rand::thread_rng().fill_bytes(&mut tail.nonce);
|
||||||
|
let nonce = Nonce::assume_unique_for_key(tail.nonce.clone());
|
||||||
|
|
||||||
|
let rs =
|
||||||
|
self.cipher
|
||||||
|
.seal_in_place_separate_tag(nonce, Aad::empty(), zc_packet.mut_payload());
|
||||||
|
|
||||||
|
match rs {
|
||||||
|
Ok(tag) => {
|
||||||
|
tail.tag.copy_from_slice(tag.as_ref());
|
||||||
|
let pm_header = zc_packet.mut_peer_manager_header().unwrap();
|
||||||
|
pm_header.set_encrypted(true);
|
||||||
|
zc_packet.mut_inner().extend_from_slice(tail.as_bytes());
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
Err(_) => Err(Error::EncryptionFailed),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use crate::{
|
||||||
|
peers::encrypt::{ring_chacha20::RingChaCha20Cipher, Encryptor},
|
||||||
|
tunnel::packet_def::ZCPacket,
|
||||||
|
};
|
||||||
|
|
||||||
|
use super::CHACHA20_POLY1305_ENCRYPTION_RESERVED;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ring_chacha20_cipher() {
|
||||||
|
let key = [0u8; 32];
|
||||||
|
let cipher = RingChaCha20Cipher::new(key);
|
||||||
|
let text = b"Hello, World! This is a test message for Ring ChaCha20-Poly1305.";
|
||||||
|
let mut packet = ZCPacket::new_with_payload(text);
|
||||||
|
packet.fill_peer_manager_hdr(0, 0, 0);
|
||||||
|
|
||||||
|
cipher.encrypt(&mut packet).unwrap();
|
||||||
|
assert_eq!(
|
||||||
|
packet.payload().len(),
|
||||||
|
text.len() + CHACHA20_POLY1305_ENCRYPTION_RESERVED
|
||||||
|
);
|
||||||
|
assert_eq!(packet.peer_manager_header().unwrap().is_encrypted(), true);
|
||||||
|
|
||||||
|
cipher.decrypt(&mut packet).unwrap();
|
||||||
|
assert_eq!(packet.payload(), text);
|
||||||
|
assert_eq!(packet.peer_manager_header().unwrap().is_encrypted(), false);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,86 @@
|
|||||||
|
use crate::tunnel::packet_def::ZCPacket;
|
||||||
|
|
||||||
|
use super::{Encryptor, Error};
|
||||||
|
|
||||||
|
// XOR 加密不需要额外的尾部数据,因为它是对称的
|
||||||
|
pub const XOR_ENCRYPTION_RESERVED: usize = 0;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct XorCipher {
|
||||||
|
pub(crate) key: Vec<u8>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl XorCipher {
|
||||||
|
pub fn new(key: &[u8]) -> Self {
|
||||||
|
if key.is_empty() {
|
||||||
|
panic!("XOR key cannot be empty");
|
||||||
|
}
|
||||||
|
Self { key: key.to_vec() }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn xor_data(&self, data: &mut [u8]) {
|
||||||
|
for (i, byte) in data.iter_mut().enumerate() {
|
||||||
|
*byte ^= self.key[i % self.key.len()];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Encryptor for XorCipher {
|
||||||
|
fn decrypt(&self, zc_packet: &mut ZCPacket) -> Result<(), Error> {
|
||||||
|
let pm_header = zc_packet.peer_manager_header().unwrap();
|
||||||
|
if !pm_header.is_encrypted() {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
// XOR 解密(XOR是对称的,加密和解密操作相同)
|
||||||
|
self.xor_data(zc_packet.mut_payload());
|
||||||
|
|
||||||
|
let pm_header = zc_packet.mut_peer_manager_header().unwrap();
|
||||||
|
pm_header.set_encrypted(false);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn encrypt(&self, zc_packet: &mut ZCPacket) -> Result<(), Error> {
|
||||||
|
let pm_header = zc_packet.peer_manager_header().unwrap();
|
||||||
|
if pm_header.is_encrypted() {
|
||||||
|
tracing::warn!(?zc_packet, "packet is already encrypted");
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
// XOR 加密
|
||||||
|
self.xor_data(zc_packet.mut_payload());
|
||||||
|
|
||||||
|
let pm_header = zc_packet.mut_peer_manager_header().unwrap();
|
||||||
|
pm_header.set_encrypted(true);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use crate::{
|
||||||
|
peers::encrypt::{xor_cipher::XorCipher, Encryptor},
|
||||||
|
tunnel::packet_def::ZCPacket,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_xor_cipher() {
|
||||||
|
let key = b"test_key_123456";
|
||||||
|
let cipher = XorCipher::new(key);
|
||||||
|
let text = b"Hello, World! This is a test message.";
|
||||||
|
let mut packet = ZCPacket::new_with_payload(text);
|
||||||
|
packet.fill_peer_manager_hdr(0, 0, 0);
|
||||||
|
|
||||||
|
// 加密
|
||||||
|
cipher.encrypt(&mut packet).unwrap();
|
||||||
|
assert_eq!(packet.peer_manager_header().unwrap().is_encrypted(), true);
|
||||||
|
assert_ne!(packet.payload(), text); // 加密后数据应该不同
|
||||||
|
|
||||||
|
// 解密
|
||||||
|
cipher.decrypt(&mut packet).unwrap();
|
||||||
|
assert_eq!(packet.payload(), text);
|
||||||
|
assert_eq!(packet.peer_manager_header().unwrap().is_encrypted(), false);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -71,7 +71,7 @@ struct RpcTransport {
|
|||||||
packet_recv: Mutex<UnboundedReceiver<ZCPacket>>,
|
packet_recv: Mutex<UnboundedReceiver<ZCPacket>>,
|
||||||
peer_rpc_tspt_sender: UnboundedSender<ZCPacket>,
|
peer_rpc_tspt_sender: UnboundedSender<ZCPacket>,
|
||||||
|
|
||||||
encryptor: Arc<Box<dyn Encryptor>>,
|
encryptor: Arc<dyn Encryptor>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
@@ -147,7 +147,7 @@ pub struct PeerManager {
|
|||||||
foreign_network_manager: Arc<ForeignNetworkManager>,
|
foreign_network_manager: Arc<ForeignNetworkManager>,
|
||||||
foreign_network_client: Arc<ForeignNetworkClient>,
|
foreign_network_client: Arc<ForeignNetworkClient>,
|
||||||
|
|
||||||
encryptor: Arc<Box<dyn Encryptor>>,
|
encryptor: Arc<dyn Encryptor + 'static>,
|
||||||
data_compress_algo: CompressorAlgo,
|
data_compress_algo: CompressorAlgo,
|
||||||
|
|
||||||
exit_nodes: Vec<IpAddr>,
|
exit_nodes: Vec<IpAddr>,
|
||||||
@@ -184,25 +184,18 @@ impl PeerManager {
|
|||||||
my_peer_id,
|
my_peer_id,
|
||||||
));
|
));
|
||||||
|
|
||||||
let mut encryptor: Arc<Box<dyn Encryptor>> = Arc::new(Box::new(NullCipher));
|
let encryptor = if global_ctx.get_flags().enable_encryption {
|
||||||
if global_ctx.get_flags().enable_encryption {
|
// 只有在启用加密时才使用工厂函数选择算法
|
||||||
#[cfg(feature = "wireguard")]
|
let algorithm = &global_ctx.get_flags().encryption_algorithm;
|
||||||
{
|
super::encrypt::create_encryptor(
|
||||||
use super::encrypt::ring_aes_gcm::AesGcmCipher;
|
algorithm,
|
||||||
encryptor = Arc::new(Box::new(AesGcmCipher::new_128(global_ctx.get_128_key())));
|
global_ctx.get_128_key(),
|
||||||
}
|
global_ctx.get_256_key(),
|
||||||
|
)
|
||||||
#[cfg(all(feature = "aes-gcm", not(feature = "wireguard")))]
|
} else {
|
||||||
{
|
// disable_encryption = true 时使用 NullCipher
|
||||||
use super::encrypt::aes_gcm::AesGcmCipher;
|
Arc::new(NullCipher)
|
||||||
encryptor = Arc::new(Box::new(AesGcmCipher::new_128(global_ctx.get_128_key())));
|
};
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(all(not(feature = "wireguard"), not(feature = "aes-gcm")))]
|
|
||||||
{
|
|
||||||
compile_error!("wireguard or aes-gcm feature must be enabled for encryption");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if global_ctx
|
if global_ctx
|
||||||
.check_network_in_whitelist(&global_ctx.get_network_name())
|
.check_network_in_whitelist(&global_ctx.get_network_name())
|
||||||
@@ -1110,7 +1103,7 @@ impl PeerManager {
|
|||||||
|
|
||||||
pub async fn try_compress_and_encrypt(
|
pub async fn try_compress_and_encrypt(
|
||||||
compress_algo: CompressorAlgo,
|
compress_algo: CompressorAlgo,
|
||||||
encryptor: &Box<dyn Encryptor>,
|
encryptor: &Arc<dyn Encryptor + 'static>,
|
||||||
msg: &mut ZCPacket,
|
msg: &mut ZCPacket,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
let compressor = DefaultCompressor {};
|
let compressor = DefaultCompressor {};
|
||||||
@@ -1375,9 +1368,12 @@ impl PeerManager {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
let next_hop_policy = Self::get_next_hop_policy( self.global_ctx.get_flags().latency_first);
|
let next_hop_policy = Self::get_next_hop_policy(self.global_ctx.get_flags().latency_first);
|
||||||
// check relay node allow relay kcp.
|
// check relay node allow relay kcp.
|
||||||
let Some(next_hop_id) = route.get_next_hop_with_policy(dst_peer_id, next_hop_policy).await else {
|
let Some(next_hop_id) = route
|
||||||
|
.get_next_hop_with_policy(dst_peer_id, next_hop_policy)
|
||||||
|
.await
|
||||||
|
else {
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1386,7 +1382,11 @@ impl PeerManager {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// check next hop allow kcp relay
|
// check next hop allow kcp relay
|
||||||
if next_hop_info.feature_flag.map(|x| x.no_relay_kcp).unwrap_or(false) {
|
if next_hop_info
|
||||||
|
.feature_flag
|
||||||
|
.map(|x| x.no_relay_kcp)
|
||||||
|
.unwrap_or(false)
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -49,6 +49,9 @@ message FlagsInConfig {
|
|||||||
|
|
||||||
// enable relay foreign network kcp packets
|
// enable relay foreign network kcp packets
|
||||||
bool enable_relay_foreign_network_kcp = 28;
|
bool enable_relay_foreign_network_kcp = 28;
|
||||||
|
|
||||||
|
// encryption algorithm to use, empty string means default (aes-gcm)
|
||||||
|
string encryption_algorithm = 29;
|
||||||
}
|
}
|
||||||
|
|
||||||
message RpcDescriptor {
|
message RpcDescriptor {
|
||||||
|
|||||||
@@ -268,8 +268,40 @@ async fn ping6_test(from_netns: &str, target_ip: &str, payload_size: Option<usiz
|
|||||||
#[rstest::rstest]
|
#[rstest::rstest]
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
#[serial_test::serial]
|
#[serial_test::serial]
|
||||||
pub async fn basic_three_node_test(#[values("tcp", "udp", "wg", "ws", "wss")] proto: &str) {
|
pub async fn basic_three_node_test(
|
||||||
let insts = init_three_node(proto).await;
|
#[values("tcp", "udp", "wg", "ws", "wss")] proto: &str,
|
||||||
|
#[values(
|
||||||
|
["aes-gcm", "aes-gcm"],
|
||||||
|
["aes-256-gcm", "aes-256-gcm"],
|
||||||
|
["chacha20", "chacha20"],
|
||||||
|
["xor", "xor"],
|
||||||
|
["openssl-chacha20", "openssl-chacha20"],
|
||||||
|
["openssl-aes-gcm", "openssl-aes-gcm"],
|
||||||
|
["openssl-aes-256-gcm", "openssl-aes-256-gcm"],
|
||||||
|
["aes-gcm", "openssl-aes-gcm"],
|
||||||
|
["openssl-aes-gcm", "aes-gcm"],
|
||||||
|
["aes-256-gcm", "openssl-aes-256-gcm"],
|
||||||
|
["openssl-aes-256-gcm", "aes-256-gcm"],
|
||||||
|
["chacha20", "openssl-chacha20"],
|
||||||
|
["openssl-chacha20", "chacha20"],
|
||||||
|
)]
|
||||||
|
encrypt_algorithm_pair: [&str; 2],
|
||||||
|
) {
|
||||||
|
let insts = init_three_node_ex(
|
||||||
|
proto,
|
||||||
|
|cfg| {
|
||||||
|
let mut flags = cfg.get_flags();
|
||||||
|
if cfg.get_inst_name() == "inst0" {
|
||||||
|
flags.encryption_algorithm = encrypt_algorithm_pair[0].to_string();
|
||||||
|
} else {
|
||||||
|
flags.encryption_algorithm = encrypt_algorithm_pair[1].to_string();
|
||||||
|
}
|
||||||
|
cfg.set_flags(flags);
|
||||||
|
cfg
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
|
||||||
check_route(
|
check_route(
|
||||||
"10.144.144.2/24",
|
"10.144.144.2/24",
|
||||||
|
|||||||
Reference in New Issue
Block a user