Merge pull request #68 from KKRainbow/mips

Add mips / mipsel support

- mips do not support wireguard.
- mips use aes-gcm crates instead of ring crates for encryption
This commit is contained in:
Sijie.Sun 2024-05-03 17:28:10 +08:00 committed by GitHub
commit 3763c959db
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
20 changed files with 373 additions and 530 deletions

View File

@ -5,3 +5,19 @@ linker = "aarch64-linux-musl-gcc"
rustflags = ["-C", "target-feature=+crt-static"]
[target.'cfg(all(windows, target_env = "msvc"))']
rustflags = ["-C", "target-feature=+crt-static"]
[target.mipsel-unknown-linux-musl]
linker = "mipsel-linux-muslsf-gcc"
rustflags = ["-C", "target-feature=+crt-static",
"-L", "./musl_gcc/mipsel-linux-muslsf-cross/mipsel-linux-muslsf/lib",
"-L", "./musl_gcc/mipsel-linux-muslsf-cross/lib/gcc/mipsel-linux-muslsf/11.2.1",
"-l", "atomic"
]
[target.mips-unknown-linux-musl]
linker = "mips-linux-muslsf-gcc"
rustflags = ["-C", "target-feature=+crt-static",
"-L", "./musl_gcc/mips-linux-muslsf-cross/mips-linux-muslsf/lib",
"-L", "./musl_gcc/mips-linux-muslsf-cross/lib/gcc/mips-linux-muslsf/11.2.1",
"-l", "atomic"
]

View File

@ -26,6 +26,12 @@ jobs:
- TARGET: x86_64-unknown-linux-musl
OS: ubuntu-latest
GUI_TARGET: x86_64-unknown-linux-gnu
- TARGET: mips-unknown-linux-musl
OS: ubuntu-latest
GUI_TARGET:
- TARGET: mipsel-unknown-linux-musl
OS: ubuntu-latest
GUI_TARGET:
- TARGET: x86_64-apple-darwin
OS: macos-latest
GUI_TARGET: x86_64-apple-darwin
@ -81,27 +87,27 @@ jobs:
# curl -s musl.cc | grep mipsel
case $TARGET in
mipsel-unknown-linux-musl)
MUSL_URI=mipsel-linux-musl-cross
MUSL_URI=mipsel-linux-muslsf
;;
aarch64-unknown-linux-musl)
MUSL_URI=aarch64-linux-musl-cross
MUSL_URI=aarch64-linux-musl
;;
armv7-unknown-linux-musleabihf)
MUSL_URI=armv7l-linux-musleabihf-cross
MUSL_URI=armv7l-linux-musleabihf
;;
arm-unknown-linux-musleabihf)
MUSL_URI=arm-linux-musleabihf-cross
MUSL_URI=arm-linux-musleabihf
;;
mips-unknown-linux-musl)
MUSL_URI=mips-linux-musl-cross
MUSL_URI=mips-linux-muslsf
;;
esac
if [ -n "$MUSL_URI" ]; then
mkdir -p ./musl_gcc
wget -c https://musl.cc/$MUSL_URI.tgz -P ./musl_gcc/
tar zxf ./musl_gcc/$MUSL_URI.tgz -C ./musl_gcc/
sudo ln -s $(pwd)/musl_gcc/$MUSL_URI/bin/*gcc /usr/bin/
wget -c https://musl.cc/${MUSL_URI}-cross.tgz -P ./musl_gcc/
tar zxf ./musl_gcc/${MUSL_URI}-cross.tgz -C ./musl_gcc/
sudo ln -s $(pwd)/musl_gcc/${MUSL_URI}-cross/bin/*gcc /usr/bin/
fi
fi
@ -109,10 +115,25 @@ jobs:
rustup set auto-self-update disable
rustup install 1.75
rustup default 1.75
rustup target add $TARGET
rustup target add $GUI_TARGET
# mips/mipsel cannot add target from rustup, need compile by ourselves
if [[ $OS =~ ^ubuntu.*$ && $TARGET =~ ^mips.*$ ]]; then
cd "$PWD/musl_gcc/${MUSL_URI}-cross/lib/gcc/${MUSL_URI}/11.2.1" || exit 255
cp libgcc_eh.a libunwind.a
rustup toolchain install nightly-x86_64-unknown-linux-gnu
rustup component add rust-src --toolchain nightly-x86_64-unknown-linux-gnu
cd -
else
rustup target add $TARGET
rustup target add $GUI_TARGET
fi
- name: Run build
run: cargo build --release --verbose --target $TARGET
run: |
if [[ $OS =~ ^ubuntu.*$ && $TARGET =~ ^mips.*$ ]]; then
cargo +nightly build -r --verbose --target $TARGET -Z build-std --no-default-features --features mips
else
cargo build --release --verbose --target $TARGET
fi
- name: Install for aarch64 gui cross compile
run: |
# see https://tauri.app/v1/guides/building/linux/
@ -148,6 +169,9 @@ jobs:
fi
- name: Run build GUI
run: |
if [ ! -n "$GUI_TARGET" ]; then
exit 0
fi
cd easytier-gui
yarn install
if [[ $OS =~ ^ubuntu.*$ && ! $GUI_TARGET =~ ^x86_64.*$ ]]; then
@ -178,7 +202,7 @@ jobs:
mv ./target/$GUI_TARGET/release/bundle/nsis/*.exe ./artifacts/objects/
elif [[ $OS =~ ^macos.*$ ]]; then
mv ./target/$GUI_TARGET/release/bundle/dmg/*.dmg ./artifacts/objects/
elif [[ $OS =~ ^ubuntu.*$ ]]; then
elif [[ $OS =~ ^ubuntu.*$ && ! $TARGET =~ ^mips.*$ ]]; then
mv ./target/$GUI_TARGET/release/bundle/deb/*.deb ./artifacts/objects/
if [[ $GUI_TARGET =~ ^x86_64.*$ ]]; then
# currently only x86 appimage is supported

193
Cargo.lock generated
View File

@ -39,14 +39,17 @@ dependencies = [
]
[[package]]
name = "ahash"
version = "0.7.7"
name = "aes-gcm"
version = "0.10.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a824f2aa7e75a0c98c5a504fceb80649e9c35265d44525b5f94de4771a395cd"
checksum = "831010a0f742e1209b3bcea8fab6a8e149051ba6099432c8cb2cc117dec3ead1"
dependencies = [
"getrandom 0.2.12",
"once_cell",
"version_check",
"aead",
"aes",
"cipher",
"ctr",
"ghash",
"subtle",
]
[[package]]
@ -228,6 +231,15 @@ dependencies = [
"critical-section",
]
[[package]]
name = "atomic-shim"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "67cd4b51d303cf3501c301e8125df442128d3c6d7c69f71b27833d253de47e77"
dependencies = [
"crossbeam-utils",
]
[[package]]
name = "atomicbox"
version = "0.4.0"
@ -348,18 +360,6 @@ version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1"
[[package]]
name = "bitvec"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c"
dependencies = [
"funty",
"radium",
"tap",
"wyz",
]
[[package]]
name = "blake2"
version = "0.10.6"
@ -445,28 +445,6 @@ version = "3.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec"
[[package]]
name = "bytecheck"
version = "0.6.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b6372023ac861f6e6dc89c8344a8f398fb42aaba2b5dbc649ca0c0e9dbcb627"
dependencies = [
"bytecheck_derive",
"ptr_meta",
"simdutf8",
]
[[package]]
name = "bytecheck_derive"
version = "0.6.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a7ec4c6f261935ad534c0c22dbef2201b45918860eb1c574b972bd213a76af61"
dependencies = [
"proc-macro2",
"quote",
"syn 1.0.109",
]
[[package]]
name = "bytecodec"
version = "0.4.15"
@ -983,6 +961,15 @@ dependencies = [
"syn 2.0.48",
]
[[package]]
name = "ctr"
version = "0.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835"
dependencies = [
"cipher",
]
[[package]]
name = "cty"
version = "0.2.2"
@ -1281,10 +1268,12 @@ checksum = "56ce8c6da7551ec6c462cbaf3bfbc75131ebbfa1c944aeaa9dab51ca1c5f0c3b"
name = "easytier"
version = "1.0.0"
dependencies = [
"aes-gcm",
"anyhow",
"async-recursion",
"async-stream",
"async-trait",
"atomic-shim",
"atomicbox",
"auto_impl",
"base64 0.21.7",
@ -1304,6 +1293,7 @@ dependencies = [
"futures",
"gethostname",
"humansize",
"indexmap 1.9.3",
"log",
"mimalloc-rust",
"network-interface",
@ -1321,7 +1311,6 @@ dependencies = [
"rcgen",
"reqwest",
"ring 0.16.20",
"rkyv",
"rstest",
"rustls",
"serde",
@ -1532,12 +1521,6 @@ dependencies = [
"percent-encoding",
]
[[package]]
name = "funty"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c"
[[package]]
name = "futf"
version = "0.1.5"
@ -1793,6 +1776,16 @@ dependencies = [
"wasi 0.11.0+wasi-snapshot-preview1",
]
[[package]]
name = "ghash"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0d8a4362ccb29cb0b265253fb0a2728f592895ee6854fd9bc13f2ffda266ff1"
dependencies = [
"opaque-debug",
"polyval",
]
[[package]]
name = "gimli"
version = "0.28.1"
@ -1992,9 +1985,6 @@ name = "hashbrown"
version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
dependencies = [
"ahash",
]
[[package]]
name = "hashbrown"
@ -3548,6 +3538,18 @@ dependencies = [
"universal-hash",
]
[[package]]
name = "polyval"
version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9d1fe60d06143b2430aa532c94cfe9e29783047f06c0d7fd359a9a51b729fa25"
dependencies = [
"cfg-if",
"cpufeatures",
"opaque-debug",
"universal-hash",
]
[[package]]
name = "postcard"
version = "1.0.8"
@ -3703,26 +3705,6 @@ dependencies = [
"prost",
]
[[package]]
name = "ptr_meta"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0738ccf7ea06b608c10564b31debd4f5bc5e197fc8bfe088f68ae5ce81e7a4f1"
dependencies = [
"ptr_meta_derive",
]
[[package]]
name = "ptr_meta_derive"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "16b845dbfca988fa33db069c0e230574d15a3088f147a87b64c7589eb662c9ac"
dependencies = [
"proc-macro2",
"quote",
"syn 1.0.109",
]
[[package]]
name = "public-ip"
version = "0.2.2"
@ -3810,12 +3792,6 @@ dependencies = [
"proc-macro2",
]
[[package]]
name = "radium"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09"
[[package]]
name = "radix_trie"
version = "0.2.1"
@ -3995,15 +3971,6 @@ version = "1.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e898588f33fdd5b9420719948f9f2a32c922a246964576f71ba7f24f80610fbc"
[[package]]
name = "rend"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2571463863a6bd50c32f94402933f03457a3fbaf697a707c5be741e459f08fd"
dependencies = [
"bytecheck",
]
[[package]]
name = "reqwest"
version = "0.11.27"
@ -4074,35 +4041,6 @@ dependencies = [
"windows-sys 0.52.0",
]
[[package]]
name = "rkyv"
version = "0.7.43"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "527a97cdfef66f65998b5f3b637c26f5a5ec09cc52a3f9932313ac645f4190f5"
dependencies = [
"bitvec",
"bytecheck",
"bytes",
"hashbrown 0.12.3",
"ptr_meta",
"rend",
"rkyv_derive",
"seahash",
"tinyvec",
"uuid",
]
[[package]]
name = "rkyv_derive"
version = "0.7.43"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5c462a1328c8e67e4d6dbad1eb0355dd43e8ab432c6e227a43657f16ade5033"
dependencies = [
"proc-macro2",
"quote",
"syn 1.0.109",
]
[[package]]
name = "rstest"
version = "0.18.2"
@ -4261,12 +4199,6 @@ dependencies = [
"untrusted 0.9.0",
]
[[package]]
name = "seahash"
version = "4.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b"
[[package]]
name = "security-framework"
version = "2.9.2"
@ -4516,12 +4448,6 @@ version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe"
[[package]]
name = "simdutf8"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f27f6278552951f1f2b8cf9da965d10969b2efdea95a6ec47987ab46edfe263a"
[[package]]
name = "siphasher"
version = "0.3.11"
@ -4858,12 +4784,6 @@ dependencies = [
"syn 1.0.109",
]
[[package]]
name = "tap"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369"
[[package]]
name = "tar"
version = "0.4.40"
@ -6456,15 +6376,6 @@ dependencies = [
"windows-implement",
]
[[package]]
name = "wyz"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed"
dependencies = [
"tap",
]
[[package]]
name = "x11"
version = "2.21.0"

View File

@ -65,9 +65,11 @@ pin-project-lite = "0.2.13"
atomicbox = "0.4.0"
tachyonix = "0.2.1"
quinn = { version = "0.10.2" }
rustls = { version = "0.21.0", features = ["dangerous_configuration"] }
rcgen = "0.11.1"
quinn = { version = "0.10.2", optional = true }
rustls = { version = "0.21.0", features = [
"dangerous_configuration",
], optional = true }
rcgen = { version = "0.11.1", optional = true }
# for tap device
tun = { version = "0.6.1", features = ["async"] }
@ -86,13 +88,6 @@ crossbeam-queue = "0.3"
once_cell = "1.18.0"
# for packet
rkyv = { "version" = "0.7.42", features = [
"validation",
"archive_le",
"strict",
"copy_unsafe",
"arbitrary_enum_discriminant",
] }
postcard = { "version" = "1.0.8", features = ["alloc"] }
# for rpc
@ -130,9 +125,10 @@ network-interface = "1.1.1"
pathfinding = "4.9.1"
# for encryption
boringtun = { version = "0.6.0" }
ring = { version = "0.16" }
boringtun = { version = "0.6.0", optional = true }
ring = { version = "0.16", optional = true }
bitflags = "2.5"
aes-gcm = { version = "0.10.3", optional = true }
# for cli
tabled = "0.15.*"
@ -142,7 +138,11 @@ base64 = "0.21.7"
derivative = "2.2.0"
mimalloc-rust = "0.2.1"
mimalloc-rust = { version = "0.2.1", optional = true }
indexmap = { version = "~1.9.3", optional = false, features = ["std"] }
atomic-shim = "0.2.0"
[target.'cfg(windows)'.dependencies]
windows-sys = { version = "0.52", features = [
@ -164,3 +164,12 @@ zip = "0.6.6"
serial_test = "3.0.0"
rstest = "0.18.2"
defguard_wireguard_rs = "0.4.2"
[features]
default = ["wireguard", "quic", "mimalloc"]
mips = ["aes-gcm"]
wireguard = ["dep:boringtun", "dep:ring"]
quic = ["dep:quinn", "dep:rustls", "dep:rcgen"]
mimalloc = ["dep:mimalloc-rust"]
aes-gcm = ["dep:aes-gcm"]

View File

@ -13,7 +13,6 @@ pub mod global_ctx;
pub mod ifcfg;
pub mod netns;
pub mod network;
pub mod rkyv_util;
pub mod stun;
pub mod stun_codec_ext;

View File

@ -1,72 +0,0 @@
use rkyv::{
string::ArchivedString,
validation::{validators::DefaultValidator, CheckTypeError},
vec::ArchivedVec,
Archive, CheckBytes, Serialize,
};
use tokio_util::bytes::{Bytes, BytesMut};
pub fn decode_from_bytes_checked<'a, T: Archive>(
bytes: &'a [u8],
) -> Result<&'a T::Archived, CheckTypeError<T::Archived, DefaultValidator<'a>>>
where
T::Archived: CheckBytes<DefaultValidator<'a>>,
{
rkyv::check_archived_root::<T>(bytes)
}
pub fn decode_from_bytes<'a, T: Archive>(
bytes: &'a [u8],
) -> Result<&'a T::Archived, CheckTypeError<T::Archived, DefaultValidator<'a>>>
where
T::Archived: CheckBytes<DefaultValidator<'a>>,
{
// rkyv::check_archived_root::<T>(bytes)
unsafe { Ok(rkyv::archived_root::<T>(bytes)) }
}
// allow deseraial T to Bytes
pub fn encode_to_bytes<T, const N: usize>(val: &T) -> Bytes
where
T: Serialize<rkyv::ser::serializers::AllocSerializer<N>>,
{
let ret = rkyv::to_bytes::<_, N>(val).unwrap();
// let mut r = BytesMut::new();
// r.extend_from_slice(&ret);
// r.freeze()
ret.into_boxed_slice().into()
}
pub fn extract_bytes_from_archived_vec(raw_data: &Bytes, archived_data: &ArchivedVec<u8>) -> Bytes {
let ptr_range = archived_data.as_ptr_range();
let offset = ptr_range.start as usize - raw_data.as_ptr() as usize;
let len = ptr_range.end as usize - ptr_range.start as usize;
return raw_data.slice(offset..offset + len);
}
pub fn extract_bytes_from_archived_string(
raw_data: &Bytes,
archived_data: &ArchivedString,
) -> Bytes {
let offset = archived_data.as_ptr() as usize - raw_data.as_ptr() as usize;
let len = archived_data.len();
if offset + len > raw_data.len() {
return Bytes::new();
}
return raw_data.slice(offset..offset + archived_data.len());
}
pub fn extract_bytes_mut_from_archived_vec(
raw_data: &mut BytesMut,
archived_data: &ArchivedVec<u8>,
) -> BytesMut {
let ptr_range = archived_data.as_ptr_range();
let offset = ptr_range.start as usize - raw_data.as_ptr() as usize;
let len = ptr_range.end as usize - ptr_range.start as usize;
raw_data.split_off(offset).split_to(len)
}
pub fn vec_to_string(vec: Vec<u8>) -> String {
unsafe { String::from_utf8_unchecked(vec) }
}

View File

@ -3,16 +3,15 @@ use std::{
sync::Arc,
};
#[cfg(feature = "quic")]
use crate::tunnel::quic::QUICTunnelConnector;
#[cfg(feature = "wireguard")]
use crate::tunnel::wireguard::{WgConfig, WgTunnelConnector};
use crate::{
common::{error::Error, global_ctx::ArcGlobalCtx, network::IPCollector},
tunnel::{
check_scheme_and_get_socket_addr,
quic::QUICTunnelConnector,
ring::RingTunnelConnector,
tcp::TcpTunnelConnector,
udp::UdpTunnelConnector,
wireguard::{WgConfig, WgTunnelConnector},
TunnelConnector,
check_scheme_and_get_socket_addr, ring::RingTunnelConnector, tcp::TcpTunnelConnector,
udp::UdpTunnelConnector, TunnelConnector,
},
};
@ -77,6 +76,7 @@ pub async fn create_connector_by_url(
let connector = RingTunnelConnector::new(url);
return Ok(Box::new(connector));
}
#[cfg(feature = "quic")]
"quic" => {
let dst_addr = check_scheme_and_get_socket_addr::<SocketAddr>(&url, "quic")?;
let mut connector = QUICTunnelConnector::new(url);
@ -88,6 +88,7 @@ pub async fn create_connector_by_url(
.await;
return Ok(Box::new(connector));
}
#[cfg(feature = "wireguard")]
"wg" => {
let dst_addr = check_scheme_and_get_socket_addr::<SocketAddr>(&url, "wg")?;
let nid = global_ctx.get_network_identity();

View File

@ -32,8 +32,10 @@ use crate::common::{
global_ctx::GlobalCtxEvent,
};
#[cfg(feature = "mimalloc")]
use mimalloc_rust::*;
#[cfg(feature = "mimalloc")]
#[global_allocator]
static GLOBAL_MIMALLOC: GlobalMiMalloc = GlobalMiMalloc;

View File

@ -130,7 +130,10 @@ impl Instance {
let peer_center = Arc::new(PeerCenterInstance::new(peer_manager.clone()));
#[cfg(feature = "wireguard")]
let vpn_portal_inst = vpn_portal::wireguard::WireGuard::default();
#[cfg(not(feature = "wireguard"))]
let vpn_portal_inst = vpn_portal::NullVpnPortal;
Instance {
inst_name: global_ctx.inst_name.clone(),

View File

@ -4,6 +4,10 @@ use anyhow::Context;
use async_trait::async_trait;
use tokio::{sync::Mutex, task::JoinSet};
#[cfg(feature = "quic")]
use crate::tunnel::quic::QUICTunnelListener;
#[cfg(feature = "wireguard")]
use crate::tunnel::wireguard::{WgConfig, WgTunnelListener};
use crate::{
common::{
error::Error,
@ -12,30 +16,28 @@ use crate::{
},
peers::peer_manager::PeerManager,
tunnel::{
quic::QUICTunnelListener,
ring::RingTunnelListener,
tcp::TcpTunnelListener,
udp::UdpTunnelListener,
wireguard::{WgConfig, WgTunnelListener},
Tunnel, TunnelListener,
ring::RingTunnelListener, tcp::TcpTunnelListener, udp::UdpTunnelListener, Tunnel,
TunnelListener,
},
};
pub fn get_listener_by_url(
l: &url::Url,
ctx: ArcGlobalCtx,
_ctx: ArcGlobalCtx,
) -> Result<Box<dyn TunnelListener>, Error> {
Ok(match l.scheme() {
"tcp" => Box::new(TcpTunnelListener::new(l.clone())),
"udp" => Box::new(UdpTunnelListener::new(l.clone())),
#[cfg(feature = "wireguard")]
"wg" => {
let nid = ctx.get_network_identity();
let nid = _ctx.get_network_identity();
let wg_config = WgConfig::new_from_network_identity(
&nid.network_name,
&nid.network_secret.unwrap_or_default(),
);
Box::new(WgTunnelListener::new(l.clone(), wg_config))
}
#[cfg(feature = "quic")]
"quic" => Box::new(QUICTunnelListener::new(l.clone())),
_ => {
unreachable!("unsupported listener uri");

View File

@ -0,0 +1,146 @@
use aes_gcm::aead::consts::{U12, U16};
use aes_gcm::aead::generic_array::GenericArray;
use aes_gcm::{AeadCore, AeadInPlace, Aes128Gcm, Aes256Gcm, Key, KeyInit, Nonce, Tag};
use rand::rngs::OsRng;
use zerocopy::{AsBytes, FromBytes};
use crate::tunnel::packet_def::{AesGcmTail, ZCPacket, AES_GCM_ENCRYPTION_RESERVED};
use super::{Encryptor, Error};
#[derive(Clone)]
pub struct AesGcmCipher {
pub(crate) cipher: AesGcmEnum,
}
#[derive(Clone)]
pub enum AesGcmEnum {
AES128GCM(Aes128Gcm),
AES256GCM(Aes256Gcm),
}
impl AesGcmCipher {
pub fn new_128(key: [u8; 16]) -> Self {
let key: &Key<Aes128Gcm> = &key.into();
Self {
cipher: AesGcmEnum::AES128GCM(Aes128Gcm::new(key)),
}
}
pub fn new_256(key: [u8; 32]) -> Self {
let key: &Key<Aes256Gcm> = &key.into();
Self {
cipher: AesGcmEnum::AES256GCM(Aes256Gcm::new(key)),
}
}
}
impl Encryptor for AesGcmCipher {
fn decrypt(&self, zc_packet: &mut ZCPacket) -> Result<(), Error> {
let pm_header = zc_packet.peer_manager_header().unwrap();
if !pm_header.is_encrypted() {
return Err(Error::NotEcrypted);
}
let payload_len = zc_packet.payload().len();
if payload_len < AES_GCM_ENCRYPTION_RESERVED {
return Err(Error::PacketTooShort(zc_packet.payload().len()));
}
let text_len = payload_len - AES_GCM_ENCRYPTION_RESERVED;
let aes_tail = AesGcmTail::ref_from_suffix(zc_packet.payload())
.unwrap()
.clone();
let nonce: &GenericArray<u8, U12> = Nonce::from_slice(&aes_tail.nonce);
let tag: GenericArray<u8, U16> = Tag::clone_from_slice(aes_tail.tag.as_slice());
let rs = match &self.cipher {
AesGcmEnum::AES128GCM(aes_gcm) => aes_gcm.decrypt_in_place_detached(
nonce,
&[],
&mut zc_packet.mut_payload()[..text_len],
&tag,
),
AesGcmEnum::AES256GCM(aes_gcm) => aes_gcm.decrypt_in_place_detached(
nonce,
&[],
&mut zc_packet.mut_payload()[..text_len],
&tag,
),
};
if let Err(e) = rs {
println!("error: {:?}", e.to_string());
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 - AES_GCM_ENCRYPTION_RESERVED);
return 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 = AesGcmTail::default();
let rs = match &self.cipher {
AesGcmEnum::AES128GCM(aes_gcm) => {
let nonce = Aes128Gcm::generate_nonce(&mut OsRng);
tail.nonce.copy_from_slice(nonce.as_slice());
aes_gcm.encrypt_in_place_detached(&nonce, &[], zc_packet.mut_payload())
}
AesGcmEnum::AES256GCM(aes_gcm) => {
let nonce = Aes256Gcm::generate_nonce(&mut OsRng);
tail.nonce.copy_from_slice(nonce.as_slice());
aes_gcm.encrypt_in_place_detached(&nonce, &[], zc_packet.mut_payload())
}
};
return match rs {
Ok(tag) => {
tail.tag.copy_from_slice(tag.as_slice());
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::{aes_gcm::AesGcmCipher, Encryptor},
tunnel::packet_def::{ZCPacket, AES_GCM_ENCRYPTION_RESERVED},
};
#[test]
fn test_aes_gcm_cipher() {
let key = [0u8; 16];
let cipher = AesGcmCipher::new_128(key);
let text = b"1234567";
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() + AES_GCM_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);
}
}

View File

@ -1,7 +1,11 @@
use crate::tunnel::packet_def::ZCPacket;
#[cfg(feature = "wireguard")]
pub mod ring_aes_gcm;
#[cfg(feature = "aes-gcm")]
pub mod aes_gcm;
#[derive(thiserror::Error, Debug)]
pub enum Error {
#[error("packet is not encrypted")]

View File

@ -1,4 +1,3 @@
pub mod packet;
pub mod peer;
// pub mod peer_conn;
pub mod peer_conn;

View File

@ -1,254 +0,0 @@
use std::fmt::Debug;
use rkyv::{Archive, Deserialize, Serialize};
use tokio_util::bytes::Bytes;
use crate::common::{
global_ctx::NetworkIdentity,
rkyv_util::{decode_from_bytes, encode_to_bytes, vec_to_string},
PeerId,
};
const MAGIC: u32 = 0xd1e1a5e1;
const VERSION: u32 = 1;
#[derive(Archive, Deserialize, Serialize, PartialEq, Clone)]
#[archive(compare(PartialEq), check_bytes)]
// Derives can be passed through to the generated type:
#[archive_attr(derive(Debug))]
pub struct UUID(uuid::Bytes);
// impl Debug for UUID
impl std::fmt::Debug for UUID {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let uuid = uuid::Uuid::from_bytes(self.0);
write!(f, "{}", uuid)
}
}
impl From<uuid::Uuid> for UUID {
fn from(uuid: uuid::Uuid) -> Self {
UUID(*uuid.as_bytes())
}
}
impl From<UUID> for uuid::Uuid {
fn from(uuid: UUID) -> Self {
uuid::Uuid::from_bytes(uuid.0)
}
}
impl ArchivedUUID {
pub fn to_uuid(&self) -> uuid::Uuid {
uuid::Uuid::from_bytes(self.0)
}
}
impl From<&ArchivedUUID> for UUID {
fn from(uuid: &ArchivedUUID) -> Self {
UUID(uuid.0)
}
}
#[derive(serde::Serialize, serde::Deserialize, Debug)]
pub struct HandShake {
pub magic: u32,
pub my_peer_id: PeerId,
pub version: u32,
pub features: Vec<String>,
pub network_identity: NetworkIdentity,
}
#[derive(serde::Serialize, serde::Deserialize, Debug)]
pub struct RoutePacket {
pub route_id: u8,
pub body: Vec<u8>,
}
#[derive(Debug, serde::Serialize, serde::Deserialize)]
pub enum CtrlPacketPayload {
HandShake(HandShake),
RoutePacket(RoutePacket),
Ping(u32),
Pong(u32),
TaRpc(u32, u32, bool, Vec<u8>), // u32: service_id, u32: transact_id, bool: is_req, Vec<u8>: rpc body
}
impl CtrlPacketPayload {
pub fn from_packet(p: &ArchivedPacket) -> CtrlPacketPayload {
assert_ne!(p.packet_type, PacketType::Data);
postcard::from_bytes(p.payload.as_bytes()).unwrap()
}
pub fn from_packet2(p: &Packet) -> CtrlPacketPayload {
postcard::from_bytes(p.payload.as_bytes()).unwrap()
}
}
#[repr(u8)]
#[derive(Archive, Deserialize, Serialize, Debug)]
#[archive(compare(PartialEq), check_bytes)]
// Derives can be passed through to the generated type:
#[archive_attr(derive(Debug))]
pub enum PacketType {
Data = 1,
HandShake = 2,
RoutePacket = 3,
Ping = 4,
Pong = 5,
TaRpc = 6,
}
#[derive(Archive, Deserialize, Serialize)]
#[archive(compare(PartialEq), check_bytes)]
// Derives can be passed through to the generated type:
pub struct Packet {
pub from_peer: PeerId,
pub to_peer: PeerId,
pub packet_type: PacketType,
pub payload: String,
}
impl std::fmt::Debug for Packet {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"Packet {{ from_peer: {}, to_peer: {}, packet_type: {:?}, payload: {:?} }}",
self.from_peer,
self.to_peer,
self.packet_type,
&self.payload.as_bytes()
)
}
}
impl std::fmt::Debug for ArchivedPacket {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"Packet {{ from_peer: {}, to_peer: {}, packet_type: {:?}, payload: {:?} }}",
self.from_peer,
self.to_peer,
self.packet_type,
&self.payload.as_bytes()
)
}
}
impl Packet {
pub fn decode(v: &[u8]) -> &ArchivedPacket {
decode_from_bytes::<Packet>(v).unwrap()
}
pub fn new(
from_peer: PeerId,
to_peer: PeerId,
packet_type: PacketType,
payload: Vec<u8>,
) -> Self {
Packet {
from_peer,
to_peer,
packet_type,
payload: vec_to_string(payload),
}
}
}
impl From<Packet> for Bytes {
fn from(val: Packet) -> Self {
encode_to_bytes::<_, 4096>(&val)
}
}
impl Packet {
pub fn new_handshake(from_peer: PeerId, network: &NetworkIdentity) -> Self {
let handshake = CtrlPacketPayload::HandShake(HandShake {
magic: MAGIC,
my_peer_id: from_peer,
version: VERSION,
features: Vec::new(),
network_identity: network.clone().into(),
});
Packet::new(
from_peer.into(),
0,
PacketType::HandShake,
postcard::to_allocvec(&handshake).unwrap(),
)
}
pub fn new_data_packet(from_peer: PeerId, to_peer: PeerId, data: &[u8]) -> Self {
Packet::new(from_peer, to_peer, PacketType::Data, data.to_vec())
}
pub fn new_route_packet(from_peer: PeerId, to_peer: PeerId, route_id: u8, data: &[u8]) -> Self {
let route = CtrlPacketPayload::RoutePacket(RoutePacket {
route_id,
body: data.to_vec(),
});
Packet::new(
from_peer,
to_peer,
PacketType::RoutePacket,
postcard::to_allocvec(&route).unwrap(),
)
}
pub fn new_ping_packet(from_peer: PeerId, to_peer: PeerId, seq: u32) -> Self {
let ping = CtrlPacketPayload::Ping(seq);
Packet::new(
from_peer,
to_peer,
PacketType::Ping,
postcard::to_allocvec(&ping).unwrap(),
)
}
pub fn new_pong_packet(from_peer: PeerId, to_peer: PeerId, seq: u32) -> Self {
let pong = CtrlPacketPayload::Pong(seq);
Packet::new(
from_peer,
to_peer,
PacketType::Pong,
postcard::to_allocvec(&pong).unwrap(),
)
}
pub fn new_tarpc_packet(
from_peer: PeerId,
to_peer: PeerId,
service_id: u32,
transact_id: u32,
is_req: bool,
body: Vec<u8>,
) -> Self {
let ta_rpc = CtrlPacketPayload::TaRpc(service_id, transact_id, is_req, body);
Packet::new(
from_peer,
to_peer,
PacketType::TaRpc,
postcard::to_allocvec(&ta_rpc).unwrap(),
)
}
}
#[cfg(test)]
mod tests {
use crate::common::new_peer_id;
use super::*;
#[tokio::test]
async fn serialize() {
let a = "abcde";
let out = Packet::new_data_packet(new_peer_id(), new_peer_id(), a.as_bytes());
// let out = T::new(a.as_bytes());
let out_bytes: Bytes = out.into();
println!("out str: {:?}", a.as_bytes());
println!("out bytes: {:?}", out_bytes);
let archived = Packet::decode(&out_bytes[..]);
println!("in packet: {:?}", archived);
}
}

View File

@ -29,8 +29,8 @@ use crate::{
global_ctx::ArcGlobalCtx,
PeerId,
},
peers::packet::PacketType,
rpc::{HandshakeRequest, PeerConnInfo, PeerConnStats, TunnelInfo},
tunnel::packet_def::PacketType,
tunnel::{
filter::{StatsRecorderTunnelFilter, TunnelFilter, TunnelWithFilter},
mpsc::{MpscTunnel, MpscTunnelSender},

View File

@ -22,17 +22,18 @@ use tokio_util::bytes::Bytes;
use crate::{
common::{error::Error, global_ctx::ArcGlobalCtx, PeerId},
peers::{
packet, peer_conn::PeerConn, peer_rpc::PeerRpcManagerTransport,
route_trait::RouteInterface, PeerPacketFilter,
peer_conn::PeerConn, peer_rpc::PeerRpcManagerTransport, route_trait::RouteInterface,
PeerPacketFilter,
},
tunnel::{
self,
packet_def::{PacketType, ZCPacket},
SinkItem, Tunnel, TunnelConnector,
},
};
use super::{
encrypt::{ring_aes_gcm::AesGcmCipher, Encryptor, NullCipher},
encrypt::{Encryptor, NullCipher},
foreign_network_client::ForeignNetworkClient,
foreign_network_manager::ForeignNetworkManager,
peer_conn::PeerConnId,
@ -176,12 +177,25 @@ impl PeerManager {
my_peer_id,
));
let encryptor: Arc<Box<dyn Encryptor>> =
Arc::new(if global_ctx.get_flags().enable_encryption {
Box::new(AesGcmCipher::new_128(global_ctx.get_128_key()))
} else {
Box::new(NullCipher)
});
let mut encryptor: Arc<Box<dyn Encryptor>> = Arc::new(Box::new(NullCipher));
if global_ctx.get_flags().enable_encryption {
#[cfg(feature = "wireguard")]
{
use super::encrypt::ring_aes_gcm::AesGcmCipher;
encryptor = Arc::new(Box::new(AesGcmCipher::new_128(global_ctx.get_128_key())));
}
#[cfg(all(feature = "aes-gcm", not(feature = "wireguard")))]
{
use super::encrypt::aes_gcm::AesGcmCipher;
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");
}
}
// TODO: remove these because we have impl pipeline processor.
let (peer_rpc_tspt_sender, peer_rpc_tspt_recv) = mpsc::unbounded_channel();
@ -536,7 +550,11 @@ impl PeerManager {
return Ok(());
}
msg.fill_peer_manager_hdr(self.my_peer_id, 0, packet::PacketType::Data as u8);
msg.fill_peer_manager_hdr(
self.my_peer_id,
0,
tunnel::packet_def::PacketType::Data as u8,
);
self.run_nic_packet_process_pipeline(&mut msg).await;
self.encryptor
.encrypt(&mut msg)

View File

@ -3,7 +3,7 @@ use std::{
fmt::Debug,
net::Ipv4Addr,
sync::{
atomic::{AtomicBool, AtomicU32, AtomicU64, Ordering},
atomic::{AtomicBool, AtomicU32, Ordering},
Arc, Weak,
},
time::{Duration, SystemTime},
@ -473,7 +473,8 @@ impl RouteTable {
}
type SessionId = u64;
type AtomicSessionId = AtomicU64;
type AtomicSessionId = atomic_shim::AtomicU64;
// if we need to sync route info with one peer, we create a SyncRouteSession with that peer.
#[derive(Debug)]

View File

@ -9,17 +9,18 @@ use super::*;
use crate::{
common::{
config::{ConfigLoader, NetworkIdentity, TomlConfigLoader, VpnPortalConfig},
config::{ConfigLoader, NetworkIdentity, TomlConfigLoader},
netns::{NetNS, ROOT_NETNS_NAME},
},
instance::instance::Instance,
peers::tests::wait_for_condition,
tunnel::{
ring::RingTunnelConnector,
tcp::TcpTunnelConnector,
udp::UdpTunnelConnector,
wireguard::{WgConfig, WgTunnelConnector},
},
tunnel::{ring::RingTunnelConnector, tcp::TcpTunnelConnector, udp::UdpTunnelConnector},
};
#[cfg(feature = "wireguard")]
use crate::{
common::config::VpnPortalConfig,
tunnel::wireguard::{WgConfig, WgTunnelConnector},
vpn_portal::wireguard::get_wg_config_for_portal,
};
@ -81,6 +82,7 @@ pub async fn init_three_node(proto: &str) -> Vec<Instance> {
"udp://10.1.1.1:11010".parse().unwrap(),
));
} else if proto == "wg" {
#[cfg(feature = "wireguard")]
inst2
.get_conn_manager()
.add_connector(WgTunnelConnector::new(
@ -226,6 +228,7 @@ pub async fn icmp_proxy_three_node_test(#[values("tcp", "udp", "wg")] proto: &st
.await;
}
#[cfg(feature = "wireguard")]
#[rstest::rstest]
#[tokio::test]
#[serial_test::serial]
@ -478,6 +481,7 @@ fn run_wireguard_client(
Ok(())
}
#[cfg(feature = "wireguard")]
#[tokio::test]
#[serial_test::serial]
pub async fn wireguard_vpn_portal() {

View File

@ -17,13 +17,17 @@ pub mod common;
pub mod filter;
pub mod mpsc;
pub mod packet_def;
pub mod quic;
pub mod ring;
pub mod stats;
pub mod tcp;
pub mod udp;
#[cfg(feature = "wireguard")]
pub mod wireguard;
#[cfg(feature = "quic")]
pub mod quic;
#[derive(thiserror::Error, Debug)]
pub enum TunnelError {
#[error("io error")]

View File

@ -9,6 +9,7 @@ use std::sync::Arc;
use crate::{common::global_ctx::ArcGlobalCtx, peers::peer_manager::PeerManager};
#[cfg(feature = "wireguard")]
pub mod wireguard;
#[async_trait::async_trait]
@ -22,3 +23,28 @@ pub trait VpnPortal: Send + Sync {
fn name(&self) -> String;
async fn list_clients(&self) -> Vec<String>;
}
pub struct NullVpnPortal;
#[async_trait::async_trait]
impl VpnPortal for NullVpnPortal {
async fn start(
&mut self,
_global_ctx: ArcGlobalCtx,
_peer_mgr: Arc<PeerManager>,
) -> anyhow::Result<()> {
Ok(())
}
async fn dump_client_config(&self, _peer_mgr: Arc<PeerManager>) -> String {
"".to_string()
}
fn name(&self) -> String {
"null".to_string()
}
async fn list_clients(&self) -> Vec<String> {
vec![]
}
}