Compare commits

...

6 Commits

Author SHA1 Message Date
Sijie.Sun
d2291628e0 mpsc tunnel may be stuck by slow tcp stream, should not panic for this (#406)
Some checks are pending
EasyTier Core / pre_job (push) Waiting to run
EasyTier Core / build (freebsd-13.2-x86_64, 13.2, ubuntu-latest, x86_64-unknown-freebsd) (push) Blocked by required conditions
EasyTier Core / build (linux-aarch64, ubuntu-latest, aarch64-unknown-linux-musl) (push) Blocked by required conditions
EasyTier Core / build (linux-arm, ubuntu-latest, arm-unknown-linux-musleabi) (push) Blocked by required conditions
EasyTier Core / build (linux-armhf, ubuntu-latest, arm-unknown-linux-musleabihf) (push) Blocked by required conditions
EasyTier Core / build (linux-armv7, ubuntu-latest, armv7-unknown-linux-musleabi) (push) Blocked by required conditions
EasyTier Core / build (linux-armv7hf, ubuntu-latest, armv7-unknown-linux-musleabihf) (push) Blocked by required conditions
EasyTier Core / build (linux-mips, ubuntu-latest, mips-unknown-linux-musl) (push) Blocked by required conditions
EasyTier Core / build (linux-mipsel, ubuntu-latest, mipsel-unknown-linux-musl) (push) Blocked by required conditions
EasyTier Core / build (linux-x86_64, ubuntu-latest, x86_64-unknown-linux-musl) (push) Blocked by required conditions
EasyTier Core / build (macos-aarch64, macos-latest, aarch64-apple-darwin) (push) Blocked by required conditions
EasyTier Core / build (macos-x86_64, macos-latest, x86_64-apple-darwin) (push) Blocked by required conditions
EasyTier Core / build (windows-x86_64, windows-latest, x86_64-pc-windows-msvc) (push) Blocked by required conditions
EasyTier Core / core-result (push) Blocked by required conditions
EasyTier GUI / pre_job (push) Waiting to run
EasyTier GUI / build-gui (linux-aarch64, aarch64-unknown-linux-gnu, ubuntu-latest, aarch64-unknown-linux-musl) (push) Blocked by required conditions
EasyTier GUI / build-gui (linux-x86_64, x86_64-unknown-linux-gnu, ubuntu-latest, x86_64-unknown-linux-musl) (push) Blocked by required conditions
EasyTier GUI / build-gui (macos-aarch64, aarch64-apple-darwin, macos-latest, aarch64-apple-darwin) (push) Blocked by required conditions
EasyTier GUI / build-gui (macos-x86_64, x86_64-apple-darwin, macos-latest, x86_64-apple-darwin) (push) Blocked by required conditions
EasyTier GUI / build-gui (windows-x86_64, x86_64-pc-windows-msvc, windows-latest, x86_64-pc-windows-msvc) (push) Blocked by required conditions
EasyTier GUI / gui-result (push) Blocked by required conditions
EasyTier Mobile / pre_job (push) Waiting to run
EasyTier Mobile / build-mobile (android, ubuntu-latest, android) (push) Blocked by required conditions
EasyTier Mobile / mobile-result (push) Blocked by required conditions
EasyTier Test / pre_job (push) Waiting to run
EasyTier Test / test (push) Blocked by required conditions
* mpsc tunnel may be stuck by slow tcp stream, should not panic for this
* disallow node connect to self
2024-10-11 00:12:14 +08:00
Sijie.Sun
7ab8cad1af allow use ipv4 address in any cidr (#404)
Some checks are pending
EasyTier Core / pre_job (push) Waiting to run
EasyTier Core / build (freebsd-13.2-x86_64, 13.2, ubuntu-latest, x86_64-unknown-freebsd) (push) Blocked by required conditions
EasyTier Core / build (linux-aarch64, ubuntu-latest, aarch64-unknown-linux-musl) (push) Blocked by required conditions
EasyTier Core / build (linux-arm, ubuntu-latest, arm-unknown-linux-musleabi) (push) Blocked by required conditions
EasyTier Core / build (linux-armhf, ubuntu-latest, arm-unknown-linux-musleabihf) (push) Blocked by required conditions
EasyTier Core / build (linux-armv7, ubuntu-latest, armv7-unknown-linux-musleabi) (push) Blocked by required conditions
EasyTier Core / build (linux-armv7hf, ubuntu-latest, armv7-unknown-linux-musleabihf) (push) Blocked by required conditions
EasyTier Core / build (linux-mips, ubuntu-latest, mips-unknown-linux-musl) (push) Blocked by required conditions
EasyTier Core / build (linux-mipsel, ubuntu-latest, mipsel-unknown-linux-musl) (push) Blocked by required conditions
EasyTier Core / build (linux-x86_64, ubuntu-latest, x86_64-unknown-linux-musl) (push) Blocked by required conditions
EasyTier Core / build (macos-aarch64, macos-latest, aarch64-apple-darwin) (push) Blocked by required conditions
EasyTier Core / build (macos-x86_64, macos-latest, x86_64-apple-darwin) (push) Blocked by required conditions
EasyTier Core / build (windows-x86_64, windows-latest, x86_64-pc-windows-msvc) (push) Blocked by required conditions
EasyTier Core / core-result (push) Blocked by required conditions
EasyTier GUI / pre_job (push) Waiting to run
EasyTier GUI / build-gui (linux-aarch64, aarch64-unknown-linux-gnu, ubuntu-latest, aarch64-unknown-linux-musl) (push) Blocked by required conditions
EasyTier GUI / build-gui (linux-x86_64, x86_64-unknown-linux-gnu, ubuntu-latest, x86_64-unknown-linux-musl) (push) Blocked by required conditions
EasyTier GUI / build-gui (macos-aarch64, aarch64-apple-darwin, macos-latest, aarch64-apple-darwin) (push) Blocked by required conditions
EasyTier GUI / build-gui (macos-x86_64, x86_64-apple-darwin, macos-latest, x86_64-apple-darwin) (push) Blocked by required conditions
EasyTier GUI / build-gui (windows-x86_64, x86_64-pc-windows-msvc, windows-latest, x86_64-pc-windows-msvc) (push) Blocked by required conditions
EasyTier GUI / gui-result (push) Blocked by required conditions
EasyTier Mobile / pre_job (push) Waiting to run
EasyTier Mobile / build-mobile (android, ubuntu-latest, android) (push) Blocked by required conditions
EasyTier Mobile / mobile-result (push) Blocked by required conditions
EasyTier Test / pre_job (push) Waiting to run
EasyTier Test / test (push) Blocked by required conditions
2024-10-10 10:28:48 +08:00
Sijie.Sun
2c017e0fc5 improve hole punch (#403)
Some checks are pending
EasyTier Core / pre_job (push) Waiting to run
EasyTier Core / build (freebsd-13.2-x86_64, 13.2, ubuntu-latest, x86_64-unknown-freebsd) (push) Blocked by required conditions
EasyTier Core / build (linux-aarch64, ubuntu-latest, aarch64-unknown-linux-musl) (push) Blocked by required conditions
EasyTier Core / build (linux-arm, ubuntu-latest, arm-unknown-linux-musleabi) (push) Blocked by required conditions
EasyTier Core / build (linux-armhf, ubuntu-latest, arm-unknown-linux-musleabihf) (push) Blocked by required conditions
EasyTier Core / build (linux-armv7, ubuntu-latest, armv7-unknown-linux-musleabi) (push) Blocked by required conditions
EasyTier Core / build (linux-armv7hf, ubuntu-latest, armv7-unknown-linux-musleabihf) (push) Blocked by required conditions
EasyTier Core / build (linux-mips, ubuntu-latest, mips-unknown-linux-musl) (push) Blocked by required conditions
EasyTier Core / build (linux-mipsel, ubuntu-latest, mipsel-unknown-linux-musl) (push) Blocked by required conditions
EasyTier Core / build (linux-x86_64, ubuntu-latest, x86_64-unknown-linux-musl) (push) Blocked by required conditions
EasyTier Core / build (macos-aarch64, macos-latest, aarch64-apple-darwin) (push) Blocked by required conditions
EasyTier Core / build (macos-x86_64, macos-latest, x86_64-apple-darwin) (push) Blocked by required conditions
EasyTier Core / build (windows-x86_64, windows-latest, x86_64-pc-windows-msvc) (push) Blocked by required conditions
EasyTier Core / core-result (push) Blocked by required conditions
EasyTier GUI / pre_job (push) Waiting to run
EasyTier GUI / build-gui (linux-aarch64, aarch64-unknown-linux-gnu, ubuntu-latest, aarch64-unknown-linux-musl) (push) Blocked by required conditions
EasyTier GUI / build-gui (linux-x86_64, x86_64-unknown-linux-gnu, ubuntu-latest, x86_64-unknown-linux-musl) (push) Blocked by required conditions
EasyTier GUI / build-gui (macos-aarch64, aarch64-apple-darwin, macos-latest, aarch64-apple-darwin) (push) Blocked by required conditions
EasyTier GUI / build-gui (macos-x86_64, x86_64-apple-darwin, macos-latest, x86_64-apple-darwin) (push) Blocked by required conditions
EasyTier GUI / build-gui (windows-x86_64, x86_64-pc-windows-msvc, windows-latest, x86_64-pc-windows-msvc) (push) Blocked by required conditions
EasyTier GUI / gui-result (push) Blocked by required conditions
EasyTier Mobile / pre_job (push) Waiting to run
EasyTier Mobile / build-mobile (android, ubuntu-latest, android) (push) Blocked by required conditions
EasyTier Mobile / mobile-result (push) Blocked by required conditions
EasyTier Test / pre_job (push) Waiting to run
EasyTier Test / test (push) Blocked by required conditions
* fix duplicated peer id (again)

* improve udp hole punch

1. always try cone punch for any nat type, tolerate fault stun type.
2. serializing all sym punch request, including server side.
2024-10-10 00:07:42 +08:00
Hs_Yeah
d9453589ac Fix panic when DNS resolution for STUN server returns only IPv6 addrs. (#402) 2024-10-09 22:40:01 +08:00
Sijie.Sun
e344372616 fix cone-to-cone punch (#401) 2024-10-09 22:39:06 +08:00
Sijie.Sun
63821e56bc fix udp buffer size, avoid packet loss (#399)
Some checks are pending
EasyTier Core / pre_job (push) Waiting to run
EasyTier Core / build (freebsd-13.2-x86_64, 13.2, ubuntu-latest, x86_64-unknown-freebsd) (push) Blocked by required conditions
EasyTier Core / build (linux-aarch64, ubuntu-latest, aarch64-unknown-linux-musl) (push) Blocked by required conditions
EasyTier Core / build (linux-arm, ubuntu-latest, arm-unknown-linux-musleabi) (push) Blocked by required conditions
EasyTier Core / build (linux-armhf, ubuntu-latest, arm-unknown-linux-musleabihf) (push) Blocked by required conditions
EasyTier Core / build (linux-armv7, ubuntu-latest, armv7-unknown-linux-musleabi) (push) Blocked by required conditions
EasyTier Core / build (linux-armv7hf, ubuntu-latest, armv7-unknown-linux-musleabihf) (push) Blocked by required conditions
EasyTier Core / build (linux-mips, ubuntu-latest, mips-unknown-linux-musl) (push) Blocked by required conditions
EasyTier Core / build (linux-mipsel, ubuntu-latest, mipsel-unknown-linux-musl) (push) Blocked by required conditions
EasyTier Core / build (linux-x86_64, ubuntu-latest, x86_64-unknown-linux-musl) (push) Blocked by required conditions
EasyTier Core / build (macos-aarch64, macos-latest, aarch64-apple-darwin) (push) Blocked by required conditions
EasyTier Core / build (macos-x86_64, macos-latest, x86_64-apple-darwin) (push) Blocked by required conditions
EasyTier Core / build (windows-x86_64, windows-latest, x86_64-pc-windows-msvc) (push) Blocked by required conditions
EasyTier Core / core-result (push) Blocked by required conditions
EasyTier GUI / pre_job (push) Waiting to run
EasyTier GUI / build-gui (linux-aarch64, aarch64-unknown-linux-gnu, ubuntu-latest, aarch64-unknown-linux-musl) (push) Blocked by required conditions
EasyTier GUI / build-gui (linux-x86_64, x86_64-unknown-linux-gnu, ubuntu-latest, x86_64-unknown-linux-musl) (push) Blocked by required conditions
EasyTier GUI / build-gui (macos-aarch64, aarch64-apple-darwin, macos-latest, aarch64-apple-darwin) (push) Blocked by required conditions
EasyTier GUI / build-gui (macos-x86_64, x86_64-apple-darwin, macos-latest, x86_64-apple-darwin) (push) Blocked by required conditions
EasyTier GUI / build-gui (windows-x86_64, x86_64-pc-windows-msvc, windows-latest, x86_64-pc-windows-msvc) (push) Blocked by required conditions
EasyTier GUI / gui-result (push) Blocked by required conditions
EasyTier Mobile / pre_job (push) Waiting to run
EasyTier Mobile / build-mobile (android, ubuntu-latest, android) (push) Blocked by required conditions
EasyTier Mobile / mobile-result (push) Blocked by required conditions
EasyTier Test / pre_job (push) Waiting to run
EasyTier Test / test (push) Blocked by required conditions
also bump version to 2.0.2
2024-10-08 22:01:15 +08:00
33 changed files with 393 additions and 166 deletions

View File

@@ -21,7 +21,7 @@ on:
version:
description: 'Version for this release'
type: string
default: 'v2.0.1'
default: 'v2.0.2'
required: true
make_latest:
description: 'Mark this release as latest'

4
Cargo.lock generated
View File

@@ -1539,7 +1539,7 @@ checksum = "0d6ef0072f8a535281e4876be788938b528e9a1d43900b82c2569af7da799125"
[[package]]
name = "easytier"
version = "2.0.1"
version = "2.0.2"
dependencies = [
"aes-gcm",
"anyhow",
@@ -1631,7 +1631,7 @@ dependencies = [
[[package]]
name = "easytier-gui"
version = "2.0.1"
version = "2.0.2"
dependencies = [
"anyhow",
"chrono",

View File

@@ -1,7 +1,7 @@
{
"name": "easytier-gui",
"type": "module",
"version": "2.0.1",
"version": "2.0.2",
"private": true,
"scripts": {
"dev": "vite",

View File

@@ -1,6 +1,6 @@
[package]
name = "easytier-gui"
version = "2.0.1"
version = "2.0.2"
description = "EasyTier GUI"
authors = ["you"]
edition = "2021"

View File

@@ -17,7 +17,7 @@
"createUpdaterArtifacts": false
},
"productName": "easytier-gui",
"version": "2.0.1",
"version": "2.0.2",
"identifier": "com.kkrainbow.easytier",
"plugins": {},
"app": {

View File

@@ -3,7 +3,7 @@ name = "easytier"
description = "A full meshed p2p VPN, connecting all your devices in one network with one command."
homepage = "https://github.com/EasyTier/EasyTier"
repository = "https://github.com/EasyTier/EasyTier"
version = "2.0.1"
version = "2.0.2"
edition = "2021"
authors = ["kkrainbow"]
keywords = ["vpn", "p2p", "network", "easytier"]

View File

@@ -23,8 +23,8 @@ pub trait ConfigLoader: Send + Sync {
fn get_netns(&self) -> Option<String>;
fn set_netns(&self, ns: Option<String>);
fn get_ipv4(&self) -> Option<std::net::Ipv4Addr>;
fn set_ipv4(&self, addr: Option<std::net::Ipv4Addr>);
fn get_ipv4(&self) -> Option<cidr::Ipv4Inet>;
fn set_ipv4(&self, addr: Option<cidr::Ipv4Inet>);
fn get_dhcp(&self) -> bool;
fn set_dhcp(&self, dhcp: bool);
@@ -324,16 +324,23 @@ impl ConfigLoader for TomlConfigLoader {
self.config.lock().unwrap().netns = ns;
}
fn get_ipv4(&self) -> Option<std::net::Ipv4Addr> {
fn get_ipv4(&self) -> Option<cidr::Ipv4Inet> {
let locked_config = self.config.lock().unwrap();
locked_config
.ipv4
.as_ref()
.map(|s| s.parse().ok())
.flatten()
.map(|c: cidr::Ipv4Inet| {
if c.network_length() == 32 {
cidr::Ipv4Inet::new(c.address(), 24).unwrap()
} else {
c
}
})
}
fn set_ipv4(&self, addr: Option<std::net::Ipv4Addr>) {
fn set_ipv4(&self, addr: Option<cidr::Ipv4Inet>) {
self.config.lock().unwrap().ipv4 = if let Some(addr) = addr {
Some(addr.to_string())
} else {
@@ -590,7 +597,7 @@ level = "warn"
assert!(ret.is_ok());
let ret = ret.unwrap();
assert_eq!("10.144.144.10", ret.get_ipv4().unwrap().to_string());
assert_eq!("10.144.144.10/24", ret.get_ipv4().unwrap().to_string());
assert_eq!(
vec!["tcp://0.0.0.0:11010", "udp://0.0.0.0:11010"],

View File

@@ -40,8 +40,8 @@ pub enum GlobalCtxEvent {
VpnPortalClientConnected(String, String), // (portal, client ip)
VpnPortalClientDisconnected(String, String), // (portal, client ip)
DhcpIpv4Changed(Option<std::net::Ipv4Addr>, Option<std::net::Ipv4Addr>), // (old, new)
DhcpIpv4Conflicted(Option<std::net::Ipv4Addr>),
DhcpIpv4Changed(Option<cidr::Ipv4Inet>, Option<cidr::Ipv4Inet>), // (old, new)
DhcpIpv4Conflicted(Option<cidr::Ipv4Inet>),
}
type EventBus = tokio::sync::broadcast::Sender<GlobalCtxEvent>;
@@ -56,7 +56,7 @@ pub struct GlobalCtx {
event_bus: EventBus,
cached_ipv4: AtomicCell<Option<std::net::Ipv4Addr>>,
cached_ipv4: AtomicCell<Option<cidr::Ipv4Inet>>,
cached_proxy_cidrs: AtomicCell<Option<Vec<cidr::IpCidr>>>,
ip_collector: Arc<IPCollector>,
@@ -139,7 +139,7 @@ impl GlobalCtx {
}
}
pub fn get_ipv4(&self) -> Option<std::net::Ipv4Addr> {
pub fn get_ipv4(&self) -> Option<cidr::Ipv4Inet> {
if let Some(ret) = self.cached_ipv4.load() {
return Some(ret);
}
@@ -148,7 +148,7 @@ impl GlobalCtx {
return addr;
}
pub fn set_ipv4(&self, addr: Option<std::net::Ipv4Addr>) {
pub fn set_ipv4(&self, addr: Option<cidr::Ipv4Inet>) {
self.config.set_ipv4(addr);
self.cached_ipv4.store(None);
}

View File

@@ -56,6 +56,8 @@ impl HostResolverIter {
self.ips = ips
.filter(|x| x.is_ipv4())
.choose_multiple(&mut rand::thread_rng(), self.max_ip_per_domain as usize);
if self.ips.is_empty() {return self.next().await;}
}
Err(e) => {
tracing::warn!(?host, ?e, "lookup host for stun failed");

View File

@@ -185,7 +185,7 @@ impl PunchBothEasySymHoleClient {
my_nat_info: UdpNatType,
peer_nat_info: UdpNatType,
is_busy: &mut bool,
) -> Result<Box<dyn Tunnel>, anyhow::Error> {
) -> Result<Option<Box<dyn Tunnel>>, anyhow::Error> {
*is_busy = false;
let udp_array = UdpSocketArray::new(
@@ -301,7 +301,7 @@ impl PunchBothEasySymHoleClient {
.await
{
Ok(tunnel) => {
return Ok(tunnel);
return Ok(Some(tunnel));
}
Err(e) => {
tracing::error!(?e, "failed to connect with socket");
@@ -312,7 +312,7 @@ impl PunchBothEasySymHoleClient {
udp_array.add_new_socket(socket.socket).await?;
}
anyhow::bail!("failed to punch hole for both easy sym");
Ok(None)
}
}
@@ -325,6 +325,7 @@ pub mod tests {
use tokio::net::UdpSocket;
use crate::connector::udp_hole_punch::RUN_TESTING;
use crate::{
connector::udp_hole_punch::{
tests::create_mock_peer_manager_with_mock_stun, UdpHolePunchConnector,
@@ -338,6 +339,8 @@ pub mod tests {
#[tokio::test]
#[serial_test::serial(hole_punch)]
async fn hole_punching_easy_sym(#[values("true", "false")] is_inc: bool) {
RUN_TESTING.store(true, std::sync::atomic::Ordering::Relaxed);
let p_a = create_mock_peer_manager_with_mock_stun(if is_inc {
NatType::SymmetricEasyInc
} else {

View File

@@ -94,7 +94,7 @@ impl PunchConeHoleClient {
pub(crate) async fn do_hole_punching(
&self,
dst_peer_id: PeerId,
) -> Result<Box<dyn Tunnel>, anyhow::Error> {
) -> Result<Option<Box<dyn Tunnel>>, anyhow::Error> {
tracing::info!(?dst_peer_id, "start hole punching");
let tid = rand::random();
@@ -110,12 +110,18 @@ impl PunchConeHoleClient {
.with_context(|| anyhow::anyhow!("failed to get local port from udp array"))?;
let local_port = local_addr.port();
drop(local_socket);
let local_mapped_addr = global_ctx
.get_stun_info_collector()
.get_udp_port_mapping(local_port)
.await
.with_context(|| "failed to get udp port mapping")?;
let local_socket = {
let _g = self.peer_mgr.get_global_ctx().net_ns.guard();
Arc::new(UdpSocket::bind(local_addr).await?)
};
// client -> server: tell server the mapped port, server will return the mapped address of listening port.
let rpc_stub = self
.peer_mgr
@@ -206,7 +212,7 @@ impl PunchConeHoleClient {
{
Ok(tunnel) => {
tracing::info!(?tunnel, "hole punched");
return Ok(tunnel);
return Ok(Some(tunnel));
}
Err(e) => {
tracing::error!(?e, "failed to connect with socket");
@@ -215,7 +221,7 @@ impl PunchConeHoleClient {
}
}
return Err(anyhow::anyhow!("punch task finished but no hole punched"));
return Ok(None);
}
}

View File

@@ -1,4 +1,4 @@
use std::sync::Arc;
use std::sync::{atomic::AtomicBool, Arc};
use anyhow::{Context, Error};
use both_easy_sym::{PunchBothEasySymHoleClient, PunchBothEasySymHoleServer};
@@ -27,6 +27,7 @@ use crate::{
},
rpc_types::{self, controller::BaseController},
},
tunnel::Tunnel,
};
pub(crate) mod both_easy_sym;
@@ -36,6 +37,7 @@ pub(crate) mod sym_to_cone;
// sym punch should be serialized
static SYM_PUNCH_LOCK: Lazy<DashMap<PeerId, Arc<Mutex<()>>>> = Lazy::new(|| DashMap::new());
static RUN_TESTING: Lazy<AtomicBool> = Lazy::new(|| AtomicBool::new(false));
fn get_sym_punch_lock(peer_id: PeerId) -> Arc<Mutex<()>> {
SYM_PUNCH_LOCK
@@ -103,6 +105,9 @@ impl UdpHolePunchRpc for UdpHolePunchServer {
_ctrl: Self::Controller,
input: SendPunchPacketHardSymRequest,
) -> rpc_types::error::Result<SendPunchPacketHardSymResponse> {
let _locked = get_sym_punch_lock(self.common.get_peer_mgr().my_peer_id())
.try_lock_owned()
.with_context(|| "sym punch lock is busy")?;
self.sym_to_cone_server
.send_punch_packet_hard_sym(input)
.await
@@ -113,6 +118,9 @@ impl UdpHolePunchRpc for UdpHolePunchServer {
_ctrl: Self::Controller,
input: SendPunchPacketEasySymRequest,
) -> rpc_types::error::Result<Void> {
let _locked = get_sym_punch_lock(self.common.get_peer_mgr().my_peer_id())
.try_lock_owned()
.with_context(|| "sym punch lock is busy")?;
self.sym_to_cone_server
.send_punch_packet_easy_sym(input)
.await
@@ -134,6 +142,7 @@ impl UdpHolePunchRpc for UdpHolePunchServer {
}
}
#[derive(Debug)]
struct BackOff {
backoffs_ms: Vec<u64>,
current_idx: usize,
@@ -186,6 +195,53 @@ impl UdpHoePunchConnectorData {
})
}
#[tracing::instrument(skip(self))]
async fn handle_punch_result(
self: &Self,
ret: Result<Option<Box<dyn Tunnel>>, Error>,
backoff: Option<&mut BackOff>,
round: Option<&mut u32>,
) -> bool {
let op = |rollback: bool| {
if rollback {
if let Some(backoff) = backoff {
backoff.rollback();
}
if let Some(round) = round {
*round = round.saturating_sub(1);
}
} else {
if let Some(round) = round {
*round += 1;
}
}
};
match ret {
Ok(Some(tunnel)) => {
tracing::info!(?tunnel, "hole punching get tunnel success");
if let Err(e) = self.peer_mgr.add_client_tunnel(tunnel).await {
tracing::warn!(?e, "add client tunnel failed");
op(true);
false
} else {
true
}
}
Ok(None) => {
tracing::info!("hole punching failed, no punch tunnel");
op(false);
false
}
Err(e) => {
tracing::info!(?e, "hole punching failed");
op(true);
false
}
}
}
#[tracing::instrument(skip(self))]
async fn cone_to_cone(self: Arc<Self>, task_info: PunchTaskInfo) -> Result<(), Error> {
let mut backoff = BackOff::new(vec![0, 1000, 2000, 4000, 4000, 8000, 8000, 16000]);
@@ -197,20 +253,15 @@ impl UdpHoePunchConnectorData {
.cone_client
.do_hole_punching(task_info.dst_peer_id)
.await;
if let Err(e) = ret {
tracing::info!(?e, "cone_to_cone hole punching failed");
continue;
}
if let Err(e) = self.peer_mgr.add_client_tunnel(ret.unwrap()).await {
tracing::warn!(?e, "cone_to_cone add client tunnel failed");
continue;
if self
.handle_punch_result(ret, Some(&mut backoff), None)
.await
{
break;
}
break;
}
tracing::info!("cone_to_cone hole punching success");
Ok(())
}
@@ -223,6 +274,17 @@ impl UdpHoePunchConnectorData {
loop {
backoff.sleep_for_next_backoff().await;
// always try cone first
if !RUN_TESTING.load(std::sync::atomic::Ordering::Relaxed) {
let ret = self
.cone_client
.do_hole_punching(task_info.dst_peer_id)
.await;
if self.handle_punch_result(ret, None, None).await {
break;
}
}
let ret = {
let _lock = get_sym_punch_lock(self.peer_mgr.my_peer_id())
.lock_owned()
@@ -237,19 +299,12 @@ impl UdpHoePunchConnectorData {
.await
};
round += 1;
if let Err(e) = ret {
tracing::info!(?e, "sym_to_cone hole punching failed");
continue;
if self
.handle_punch_result(ret, Some(&mut backoff), Some(&mut round))
.await
{
break;
}
if let Err(e) = self.peer_mgr.add_client_tunnel(ret.unwrap()).await {
tracing::warn!(?e, "sym_to_cone add client tunnel failed");
continue;
}
break;
}
Ok(())
@@ -262,6 +317,17 @@ impl UdpHoePunchConnectorData {
loop {
backoff.sleep_for_next_backoff().await;
// always try cone first
if !RUN_TESTING.load(std::sync::atomic::Ordering::Relaxed) {
let ret = self
.cone_client
.do_hole_punching(task_info.dst_peer_id)
.await;
if self.handle_punch_result(ret, None, None).await {
break;
}
}
let mut is_busy = false;
let ret = {
@@ -280,19 +346,12 @@ impl UdpHoePunchConnectorData {
if is_busy {
backoff.rollback();
} else if self
.handle_punch_result(ret, Some(&mut backoff), None)
.await
{
break;
}
if let Err(e) = ret {
tracing::info!(?e, "both_easy_sym hole punching failed");
continue;
}
if let Err(e) = self.peer_mgr.add_client_tunnel(ret.unwrap()).await {
tracing::warn!(?e, "both_easy_sym add client tunnel failed");
continue;
}
break;
}
Ok(())

View File

@@ -258,7 +258,7 @@ impl PunchSymToConeHoleClient {
round: u32,
last_port_idx: &mut usize,
my_nat_info: UdpNatType,
) -> Result<Box<dyn Tunnel>, anyhow::Error> {
) -> Result<Option<Box<dyn Tunnel>>, anyhow::Error> {
let udp_array = self.prepare_udp_array().await?;
let global_ctx = self.peer_mgr.get_global_ctx();
@@ -291,7 +291,7 @@ impl PunchSymToConeHoleClient {
)
.await
{
return Ok(tunnel);
return Ok(Some(tunnel));
}
}
@@ -411,14 +411,7 @@ impl PunchSymToConeHoleClient {
*last_port_idx = rand::random();
}
if let Some(tunnel) = ret_tunnel {
Ok(tunnel)
} else {
anyhow::bail!(
"failed to hole punch, punch task result: {:?}",
punch_task_result
)
}
Ok(ret_tunnel)
}
}
@@ -433,7 +426,7 @@ pub mod tests {
use crate::{
connector::udp_hole_punch::{
tests::create_mock_peer_manager_with_mock_stun, UdpHolePunchConnector,
tests::create_mock_peer_manager_with_mock_stun, UdpHolePunchConnector, RUN_TESTING,
},
peers::tests::{connect_peer_manager, wait_route_appear, wait_route_appear_with_cost},
proto::common::NatType,
@@ -443,6 +436,8 @@ pub mod tests {
#[tokio::test]
#[serial_test::serial(hole_punch)]
async fn hole_punching_symmetric_only_random() {
RUN_TESTING.store(true, std::sync::atomic::Ordering::Relaxed);
let p_a = create_mock_peer_manager_with_mock_stun(NatType::Symmetric).await;
let p_b = create_mock_peer_manager_with_mock_stun(NatType::PortRestricted).await;
let p_c = create_mock_peer_manager_with_mock_stun(NatType::PortRestricted).await;
@@ -518,6 +513,8 @@ pub mod tests {
#[tokio::test]
#[serial_test::serial(hole_punch)]
async fn hole_punching_symmetric_only_predict(#[values("true", "false")] is_inc: bool) {
RUN_TESTING.store(true, std::sync::atomic::Ordering::Relaxed);
let p_a = create_mock_peer_manager_with_mock_stun(if is_inc {
NatType::SymmetricEasyInc
} else {

View File

@@ -227,7 +227,12 @@ impl CommandHandler {
impl From<PeerRoutePair> for PeerTableItem {
fn from(p: PeerRoutePair) -> Self {
PeerTableItem {
ipv4: p.route.ipv4_addr.clone(),
ipv4: p
.route
.ipv4_addr
.clone()
.map(|ip| ip.to_string())
.unwrap_or_default(),
hostname: p.route.hostname.clone(),
cost: cost_to_str(p.route.cost),
lat_ms: float_to_str(p.get_latency_ms().unwrap_or(0.0), 3),
@@ -413,7 +418,12 @@ impl CommandHandler {
if p.route.cost == 1 {
items.push(RouteTableItem {
ipv4: p.route.ipv4_addr.clone(),
ipv4: p
.route
.ipv4_addr
.clone()
.map(|ip| ip.to_string())
.unwrap_or_default(),
hostname: p.route.hostname.clone(),
proxy_cidrs: p.route.proxy_cidrs.clone().join(",").to_string(),
next_hop_ipv4: "DIRECT".to_string(),
@@ -428,10 +438,20 @@ impl CommandHandler {
});
} else {
items.push(RouteTableItem {
ipv4: p.route.ipv4_addr.clone(),
ipv4: p
.route
.ipv4_addr
.clone()
.map(|ip| ip.to_string())
.unwrap_or_default(),
hostname: p.route.hostname.clone(),
proxy_cidrs: p.route.proxy_cidrs.clone().join(",").to_string(),
next_hop_ipv4: next_hop_pair.route.ipv4_addr.clone(),
next_hop_ipv4: next_hop_pair
.route
.ipv4_addr
.clone()
.map(|ip| ip.to_string())
.unwrap_or_default(),
next_hop_hostname: next_hop_pair.route.hostname.clone(),
next_hop_lat: next_hop_pair.get_latency_ms().unwrap_or(0.0),
cost: p.route.cost,

View File

@@ -358,7 +358,12 @@ impl IcmpProxy {
if !self.cidr_set.contains_v4(ipv4.get_destination())
&& !is_exit_node
&& !(self.global_ctx.no_tun()
&& Some(ipv4.get_destination()) == self.global_ctx.get_ipv4())
&& Some(ipv4.get_destination())
== self
.global_ctx
.get_ipv4()
.as_ref()
.map(cidr::Ipv4Inet::address))
{
return None;
}
@@ -382,7 +387,14 @@ impl IcmpProxy {
return None;
}
if self.global_ctx.no_tun() && Some(ipv4.get_destination()) == self.global_ctx.get_ipv4() {
if self.global_ctx.no_tun()
&& Some(ipv4.get_destination())
== self
.global_ctx
.get_ipv4()
.as_ref()
.map(cidr::Ipv4Inet::address)
{
self.send_icmp_reply_to_peer(
&ipv4.get_destination(),
&ipv4.get_source(),

View File

@@ -111,7 +111,7 @@ struct Socks5Entry {
type Socks5EntrySet = Arc<DashSet<Socks5Entry>>;
struct Socks5ServerNet {
ipv4_addr: Ipv4Addr,
ipv4_addr: cidr::Ipv4Inet,
auth: Option<SimpleUserPassword>,
smoltcp_net: Arc<Net>,
@@ -122,7 +122,7 @@ struct Socks5ServerNet {
impl Socks5ServerNet {
pub fn new(
ipv4_addr: Ipv4Addr,
ipv4_addr: cidr::Ipv4Inet,
auth: Option<SimpleUserPassword>,
peer_manager: Arc<PeerManager>,
packet_recv: Arc<Mutex<mpsc::Receiver<ZCPacket>>>,
@@ -173,8 +173,10 @@ impl Socks5ServerNet {
dev,
NetConfig::new(
interface_config,
format!("{}/24", ipv4_addr).parse().unwrap(),
vec![format!("{}", ipv4_addr).parse().unwrap()],
format!("{}/{}", ipv4_addr.address(), ipv4_addr.network_length())
.parse()
.unwrap(),
vec![format!("{}", ipv4_addr.address()).parse().unwrap()],
),
);

View File

@@ -1,3 +1,4 @@
use cidr::Ipv4Inet;
use core::panic;
use crossbeam::atomic::AtomicCell;
use dashmap::DashMap;
@@ -526,7 +527,8 @@ impl TcpProxy {
tracing::warn!("set_nodelay failed, ignore it: {:?}", e);
}
let nat_dst = if Some(nat_entry.dst.ip()) == global_ctx.get_ipv4().map(|ip| IpAddr::V4(ip))
let nat_dst = if Some(nat_entry.dst.ip())
== global_ctx.get_ipv4().map(|ip| IpAddr::V4(ip.address()))
{
format!("127.0.0.1:{}", nat_entry.dst.port())
.parse()
@@ -591,7 +593,10 @@ impl TcpProxy {
{
Some(Ipv4Addr::new(192, 88, 99, 254))
} else {
self.global_ctx.get_ipv4()
self.global_ctx
.get_ipv4()
.as_ref()
.map(cidr::Ipv4Inet::address)
}
}
@@ -621,7 +626,8 @@ impl TcpProxy {
if !self.cidr_set.contains_v4(ipv4.get_destination())
&& !is_exit_node
&& !(self.global_ctx.no_tun()
&& Some(ipv4.get_destination()) == self.global_ctx.get_ipv4())
&& Some(ipv4.get_destination())
== self.global_ctx.get_ipv4().as_ref().map(Ipv4Inet::address))
{
return None;
}

View File

@@ -4,6 +4,7 @@ use std::{
time::Duration,
};
use cidr::Ipv4Inet;
use crossbeam::atomic::AtomicCell;
use dashmap::DashMap;
use pnet::packet::{
@@ -245,7 +246,8 @@ impl UdpProxy {
if !self.cidr_set.contains_v4(ipv4.get_destination())
&& !is_exit_node
&& !(self.global_ctx.no_tun()
&& Some(ipv4.get_destination()) == self.global_ctx.get_ipv4())
&& Some(ipv4.get_destination())
== self.global_ctx.get_ipv4().as_ref().map(Ipv4Inet::address))
{
return None;
}
@@ -296,14 +298,16 @@ impl UdpProxy {
.replace(tokio::spawn(UdpNatEntry::forward_task(
nat_entry.clone(),
self.sender.clone(),
self.global_ctx.get_ipv4()?,
self.global_ctx.get_ipv4().map(|x| x.address())?,
)));
}
nat_entry.mark_active();
// TODO: should it be async.
let dst_socket = if Some(ipv4.get_destination()) == self.global_ctx.get_ipv4() {
let dst_socket = if Some(ipv4.get_destination())
== self.global_ctx.get_ipv4().as_ref().map(Ipv4Inet::address)
{
format!("127.0.0.1:{}", udp_packet.get_destination())
.parse()
.unwrap()

View File

@@ -270,19 +270,11 @@ impl Instance {
let mut used_ipv4 = HashSet::new();
for route in routes {
if route.ipv4_addr.is_empty() {
continue;
}
let Ok(peer_ipv4_addr) = route.ipv4_addr.parse::<Ipv4Addr>() else {
let Some(peer_ipv4_addr) = route.ipv4_addr else {
continue;
};
let Ok(peer_ipv4_addr) = Ipv4Inet::new(peer_ipv4_addr, 24) else {
continue;
};
used_ipv4.insert(peer_ipv4_addr);
used_ipv4.insert(peer_ipv4_addr.into());
}
let dhcp_inet = used_ipv4.iter().next().unwrap_or(&default_ipv4_addr);
@@ -304,7 +296,7 @@ impl Instance {
continue;
}
let last_ip = current_dhcp_ip.as_ref().map(Ipv4Inet::address);
let last_ip = current_dhcp_ip.clone();
tracing::debug!(
?current_dhcp_ip,
?candidate_ipv4_addr,
@@ -316,11 +308,9 @@ impl Instance {
if let Some(ip) = candidate_ipv4_addr {
if global_ctx_c.no_tun() {
current_dhcp_ip = Some(ip);
global_ctx_c.set_ipv4(Some(ip.address()));
global_ctx_c.issue_event(GlobalCtxEvent::DhcpIpv4Changed(
last_ip,
Some(ip.address()),
));
global_ctx_c.set_ipv4(Some(ip));
global_ctx_c
.issue_event(GlobalCtxEvent::DhcpIpv4Changed(last_ip, Some(ip)));
continue;
}
@@ -331,7 +321,7 @@ impl Instance {
&peer_manager_c,
_peer_packet_receiver.clone(),
);
if let Err(e) = new_nic_ctx.run(ip.address()).await {
if let Err(e) = new_nic_ctx.run(ip).await {
tracing::error!(
?current_dhcp_ip,
?candidate_ipv4_addr,
@@ -345,9 +335,8 @@ impl Instance {
}
current_dhcp_ip = Some(ip);
global_ctx_c.set_ipv4(Some(ip.address()));
global_ctx_c
.issue_event(GlobalCtxEvent::DhcpIpv4Changed(last_ip, Some(ip.address())));
global_ctx_c.set_ipv4(Some(ip));
global_ctx_c.issue_event(GlobalCtxEvent::DhcpIpv4Changed(last_ip, Some(ip)));
} else {
current_dhcp_ip = None;
global_ctx_c.set_ipv4(None);

View File

@@ -504,8 +504,7 @@ pub fn reg_change_catrgory_in_profile(dev_name: &str) -> io::Result<()> {
let subkey = profiles_key.open_subkey_with_flags(&subkey_name, KEY_ALL_ACCESS)?;
match subkey.get_value::<String, _>("ProfileName") {
Ok(profile_name) => {
if !dev_name.is_empty() && dev_name == profile_name
{
if !dev_name.is_empty() && dev_name == profile_name {
match subkey.set_value("Category", &1u32) {
Ok(_) => tracing::trace!("Successfully set Category in registry"),
Err(e) => tracing::error!("Failed to set Category in registry: {}", e),
@@ -548,14 +547,16 @@ impl NicCtx {
}
}
async fn assign_ipv4_to_tun_device(&self, ipv4_addr: Ipv4Addr) -> Result<(), Error> {
async fn assign_ipv4_to_tun_device(&self, ipv4_addr: cidr::Ipv4Inet) -> Result<(), Error> {
let nic = self.nic.lock().await;
nic.link_up().await?;
nic.remove_ip(None).await?;
nic.add_ip(ipv4_addr, 24).await?;
nic.add_ip(ipv4_addr.address(), ipv4_addr.network_length() as i32)
.await?;
#[cfg(any(target_os = "macos", target_os = "freebsd"))]
{
nic.add_route(ipv4_addr, 24).await?;
nic.add_route(ipv4_addr.first_address(), ipv4_addr.network_length())
.await?;
}
Ok(())
}
@@ -710,18 +711,17 @@ impl NicCtx {
Ok(())
}
pub async fn run(&mut self, ipv4_addr: Ipv4Addr) -> Result<(), Error> {
pub async fn run(&mut self, ipv4_addr: cidr::Ipv4Inet) -> Result<(), Error> {
let tunnel = {
let mut nic = self.nic.lock().await;
match nic.create_dev().await {
Ok(ret) => {
#[cfg(target_os = "windows")]
#[cfg(target_os = "windows")]
{
let dev_name = self.global_ctx.get_flags().dev_name;
let _ = reg_change_catrgory_in_profile(&dev_name);
}
self.global_ctx
.issue_event(GlobalCtxEvent::TunDeviceReady(nic.ifname().to_string()));
ret

View File

@@ -224,7 +224,12 @@ impl PeerConn {
self.info = Some(rsp);
self.is_client = Some(false);
self.send_handshake().await?;
Ok(())
if self.get_peer_id() == self.my_peer_id {
Err(Error::WaitRespError("peer id conflict".to_owned()))
} else {
Ok(())
}
}
#[tracing::instrument]
@@ -235,7 +240,12 @@ impl PeerConn {
tracing::info!("handshake response: {:?}", rsp);
self.info = Some(rsp);
self.is_client = Some(true);
Ok(())
if self.get_peer_id() == self.my_peer_id {
Err(Error::WaitRespError("peer id conflict".to_owned()))
} else {
Ok(())
}
}
pub fn handshake_done(&self) -> bool {
@@ -396,6 +406,24 @@ mod tests {
use crate::tunnel::filter::PacketRecorderTunnelFilter;
use crate::tunnel::ring::create_ring_tunnel_pair;
#[tokio::test]
async fn peer_conn_handshake_same_id() {
let (c, s) = create_ring_tunnel_pair();
let c_peer_id = new_peer_id();
let s_peer_id = c_peer_id;
let mut c_peer = PeerConn::new(c_peer_id, get_mock_global_ctx(), Box::new(c));
let mut s_peer = PeerConn::new(s_peer_id, get_mock_global_ctx(), Box::new(s));
let (c_ret, s_ret) = tokio::join!(
c_peer.do_handshake_as_client(),
s_peer.do_handshake_as_server()
);
assert!(c_ret.is_err());
assert!(s_ret.is_err());
}
#[tokio::test]
async fn peer_conn_handshake() {
let (c, s) = create_ring_tunnel_pair();

View File

@@ -294,6 +294,8 @@ impl PeerConnPinger {
let need_close = if last_rx_packets != current_rx_packets {
// if we receive some packet from peers, we should relax the condition
counter > 50 && loss_rate_1 > 0.5
// TODO: wait more time to see if the loss rate is still high after no rx
} else {
true
};

View File

@@ -718,8 +718,16 @@ impl PeerManager {
let mut is_exit_node = false;
let mut dst_peers = vec![];
// NOTE: currently we only support ipv4 and cidr is 24
if ipv4_addr.is_broadcast() || ipv4_addr.is_multicast() || ipv4_addr.octets()[3] == 255 {
let network_length = self
.global_ctx
.get_ipv4()
.map(|x| x.network_length())
.unwrap_or(24);
let ipv4_inet = cidr::Ipv4Inet::new(ipv4_addr, network_length).unwrap();
if ipv4_addr.is_broadcast()
|| ipv4_addr.is_multicast()
|| ipv4_addr == ipv4_inet.last_address()
{
dst_peers.extend(
self.peers
.list_routes()

View File

@@ -30,7 +30,7 @@ use crate::{
},
peers::route_trait::{Route, RouteInterfaceBox},
proto::{
common::{NatType, StunInfo},
common::{Ipv4Inet, NatType, StunInfo},
peer_rpc::{
route_foreign_network_infos, ForeignNetworkRouteInfoEntry, ForeignNetworkRouteInfoKey,
OspfRouteRpc, OspfRouteRpcClientFactory, OspfRouteRpcServer, PeerIdVersion,
@@ -118,6 +118,7 @@ impl RoutePeerInfo {
easytier_version: EASYTIER_VERSION.to_string(),
feature_flag: None,
peer_route_id: 0,
network_length: 24,
}
}
@@ -131,7 +132,7 @@ impl RoutePeerInfo {
peer_id: my_peer_id,
inst_id: Some(global_ctx.get_id().into()),
cost: 0,
ipv4_addr: global_ctx.get_ipv4().map(|x| x.into()),
ipv4_addr: global_ctx.get_ipv4().map(|x| x.address().into()),
proxy_cidrs: global_ctx
.get_proxy_cidrs()
.iter()
@@ -150,6 +151,10 @@ impl RoutePeerInfo {
easytier_version: EASYTIER_VERSION.to_string(),
feature_flag: Some(global_ctx.get_feature_flags()),
peer_route_id,
network_length: global_ctx
.get_ipv4()
.map(|x| x.network_length() as u32)
.unwrap_or(24),
};
let need_update_periodically = if let Ok(Ok(d)) =
@@ -171,12 +176,21 @@ impl RoutePeerInfo {
impl Into<crate::proto::cli::Route> for RoutePeerInfo {
fn into(self) -> crate::proto::cli::Route {
let network_length = if self.network_length == 0 {
24
} else {
self.network_length
};
crate::proto::cli::Route {
peer_id: self.peer_id,
ipv4_addr: if let Some(ipv4_addr) = self.ipv4_addr {
ipv4_addr.to_string()
Some(Ipv4Inet {
address: Some(ipv4_addr.into()),
network_length,
})
} else {
"".to_string()
None
},
next_hop_peer_id: 0,
cost: self.cost as i32,
@@ -305,26 +319,32 @@ impl SyncedRouteInfo {
my_peer_id: PeerId,
my_peer_route_id: u64,
dst_peer_id: PeerId,
route_infos: &Vec<RoutePeerInfo>,
dst_peer_route_id: Option<u64>,
info: &RoutePeerInfo,
) -> Result<(), Error> {
// 1. check if we are duplicated.
for info in route_infos.iter() {
if info.peer_id == my_peer_id {
if info.version > self.get_peer_info_version_with_default(info.peer_id) {
// if dst peer send to us with higher version info of my peer, our peer id is duplicated
// TODO: handle this better. restart peer manager?
panic!("my peer id is duplicated");
// return Err(Error::DuplicatePeerId);
}
if info.peer_id == my_peer_id {
if info.peer_route_id != my_peer_route_id
&& info.version > self.get_peer_info_version_with_default(info.peer_id)
{
// if dst peer send to us with higher version info of my peer, our peer id is duplicated
// TODO: handle this better. restart peer manager?
panic!("my peer id is duplicated");
// return Err(Error::DuplicatePeerId);
}
} else if info.peer_id == dst_peer_id {
let Some(dst_peer_route_id) = dst_peer_route_id else {
return Ok(());
};
if info.peer_id == dst_peer_id && info.peer_route_id != my_peer_route_id {
if info.version < self.get_peer_info_version_with_default(info.peer_id) {
// if dst peer send to us with lower version info of dst peer, dst peer id is duplicated
return Err(Error::DuplicatePeerId);
}
if dst_peer_route_id != info.peer_route_id
&& info.version < self.get_peer_info_version_with_default(info.peer_id)
{
// if dst peer send to us with lower version info of dst peer, dst peer id is duplicated
return Err(Error::DuplicatePeerId);
}
}
Ok(())
}
@@ -335,8 +355,19 @@ impl SyncedRouteInfo {
dst_peer_id: PeerId,
peer_infos: &Vec<RoutePeerInfo>,
) -> Result<(), Error> {
self.check_duplicate_peer_id(my_peer_id, my_peer_route_id, dst_peer_id, peer_infos)?;
for mut route_info in peer_infos.iter().map(Clone::clone) {
self.check_duplicate_peer_id(
my_peer_id,
my_peer_route_id,
dst_peer_id,
if route_info.peer_id == dst_peer_id {
self.peer_infos.get(&dst_peer_id).map(|x| x.peer_route_id)
} else {
None
},
&route_info,
)?;
// time between peers may not be synchronized, so update last_update to local now.
// note only last_update with larger version will be updated to local saved peer info.
route_info.last_update = Some(SystemTime::now().into());

View File

@@ -45,7 +45,7 @@ message ListPeerResponse {
message Route {
uint32 peer_id = 1;
string ipv4_addr = 2;
common.Ipv4Inet ipv4_addr = 2;
uint32 next_hop_peer_id = 3;
int32 cost = 4;
repeated string proxy_cidrs = 5;

View File

@@ -72,6 +72,11 @@ message Ipv6Addr {
uint32 part4 = 4;
}
message Ipv4Inet {
Ipv4Addr address = 1;
uint32 network_length = 2;
}
message Url { string url = 1; }
message SocketAddr {

View File

@@ -1,5 +1,7 @@
use std::{fmt::Display, str::FromStr};
use anyhow::Context;
include!(concat!(env!("OUT_DIR"), "/common.rs"));
impl From<uuid::Uuid> for Uuid {
@@ -60,10 +62,8 @@ impl From<Ipv6Addr> for std::net::Ipv6Addr {
let part3 = value.part3.to_be_bytes();
let part4 = value.part4.to_be_bytes();
std::net::Ipv6Addr::from([
part1[0], part1[1], part1[2], part1[3],
part2[0], part2[1], part2[2], part2[3],
part3[0], part3[1], part3[2], part3[3],
part4[0], part4[1], part4[2], part4[3]
part1[0], part1[1], part1[2], part1[3], part2[0], part2[1], part2[2], part2[3],
part3[0], part3[1], part3[2], part3[3], part4[0], part4[1], part4[2], part4[3],
])
}
}
@@ -74,6 +74,37 @@ impl ToString for Ipv6Addr {
}
}
impl From<cidr::Ipv4Inet> for Ipv4Inet {
fn from(value: cidr::Ipv4Inet) -> Self {
Ipv4Inet {
address: Some(value.address().into()),
network_length: value.network_length() as u32,
}
}
}
impl From<Ipv4Inet> for cidr::Ipv4Inet {
fn from(value: Ipv4Inet) -> Self {
cidr::Ipv4Inet::new(value.address.unwrap().into(), value.network_length as u8).unwrap()
}
}
impl std::fmt::Display for Ipv4Inet {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", cidr::Ipv4Inet::from(self.clone()))
}
}
impl FromStr for Ipv4Inet {
type Err = anyhow::Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(Ipv4Inet::from(
cidr::Ipv4Inet::from_str(s).with_context(|| "Failed to parse Ipv4Inet")?,
))
}
}
impl From<url::Url> for Url {
fn from(value: url::Url) -> Self {
Url {

View File

@@ -20,6 +20,8 @@ message RoutePeerInfo {
string easytier_version = 10;
common.PeerFeatureFlag feature_flag = 11;
uint64 peer_route_id = 12;
uint32 network_length = 13;
}
message PeerIdVersion {

View File

@@ -130,7 +130,7 @@ pub fn enable_log() {
fn check_route(ipv4: &str, dst_peer_id: PeerId, routes: Vec<crate::proto::cli::Route>) {
let mut found = false;
for r in routes.iter() {
if r.ipv4_addr == ipv4.to_string() {
if r.ipv4_addr == Some(ipv4.parse().unwrap()) {
found = true;
assert_eq!(r.peer_id, dst_peer_id, "{:?}", routes);
}
@@ -154,7 +154,7 @@ async fn wait_proxy_route_appear(
let r = r;
if r.proxy_cidrs.contains(&proxy_cidr.to_owned()) {
assert_eq!(r.peer_id, dst_peer_id);
assert_eq!(r.ipv4_addr, ipv4);
assert_eq!(r.ipv4_addr, Some(ipv4.parse().unwrap()));
return;
}
}

View File

@@ -184,13 +184,13 @@ pub async fn basic_three_node_test(#[values("tcp", "udp", "wg", "ws", "wss")] pr
let insts = init_three_node(proto).await;
check_route(
"10.144.144.2",
"10.144.144.2/24",
insts[1].peer_id(),
insts[0].get_peer_manager().list_routes().await,
);
check_route(
"10.144.144.3",
"10.144.144.3/24",
insts[2].peer_id(),
insts[0].get_peer_manager().list_routes().await,
);
@@ -357,7 +357,7 @@ pub async fn subnet_proxy_three_node_test(
wait_proxy_route_appear(
&insts[0].get_peer_manager(),
"10.144.144.3",
"10.144.144.3/24",
insts[2].peer_id(),
"10.1.2.0/24",
)

View File

@@ -70,17 +70,32 @@ impl<T: Tunnel> MpscTunnel<T> {
sink: &mut Pin<Box<dyn ZCPacketSink>>,
) -> Result<(), TunnelError> {
let item = rx.recv().await.with_context(|| "recv error")?;
sink.feed(item).await?;
while let Ok(item) = rx.try_recv() {
if let Err(e) = timeout(Duration::from_secs(5), sink.feed(item))
.await
.unwrap()
{
tracing::error!(?e, "feed error");
break;
match timeout(Duration::from_secs(10), async move {
sink.feed(item).await?;
while let Ok(item) = rx.try_recv() {
match sink.feed(item).await {
Err(e) => {
tracing::error!(?e, "feed error");
return Err(e);
}
Ok(_) => {}
}
}
sink.flush().await
})
.await
{
Ok(Ok(_)) => Ok(()),
Ok(Err(e)) => {
tracing::error!(?e, "forward error");
Err(e)
}
Err(e) => {
tracing::error!(?e, "forward timeout");
Err(e.into())
}
}
sink.flush().await
}
pub fn get_stream(&mut self) -> Pin<Box<dyn ZCPacketStream>> {

View File

@@ -296,8 +296,8 @@ impl UdpTunnelListenerData {
return;
}
let ring_for_send_udp = Arc::new(RingTunnel::new(64));
let ring_for_recv_udp = Arc::new(RingTunnel::new(64));
let ring_for_send_udp = Arc::new(RingTunnel::new(128));
let ring_for_recv_udp = Arc::new(RingTunnel::new(128));
tracing::debug!(
?ring_for_send_udp,
?ring_for_recv_udp,
@@ -559,8 +559,8 @@ impl UdpTunnelConnector {
dst_addr: SocketAddr,
conn_id: u32,
) -> Result<Box<dyn super::Tunnel>, super::TunnelError> {
let ring_for_send_udp = Arc::new(RingTunnel::new(32));
let ring_for_recv_udp = Arc::new(RingTunnel::new(32));
let ring_for_send_udp = Arc::new(RingTunnel::new(128));
let ring_for_recv_udp = Arc::new(RingTunnel::new(128));
tracing::debug!(
?ring_for_send_udp,
?ring_for_recv_udp,

View File

@@ -284,13 +284,11 @@ impl VpnPortal for WireGuard {
.collect::<Vec<_>>();
for ipv4 in routes
.iter()
.map(|x| x.ipv4_addr.clone())
.chain(global_ctx.get_ipv4().iter().map(|x| x.to_string()))
.filter(|x| x.ipv4_addr.is_some())
.map(|x| x.ipv4_addr.unwrap())
.chain(global_ctx.get_ipv4().into_iter().map(Into::into))
{
let Ok(ipv4) = ipv4.parse() else {
continue;
};
let inet = Ipv4Inet::new(ipv4, 24).unwrap();
let inet = Ipv4Inet::from(ipv4);
allow_ips.push(inet.network().to_string());
break;
}