mirror of
https://github.com/EasyTier/EasyTier.git
synced 2026-05-07 18:24:36 +00:00
make tun dependency optional (#142)
* remove log crates * remove udp/raw of smoltcp * make tun as optional dependancy, compile for freebsd works
This commit is contained in:
@@ -1,14 +1,10 @@
|
||||
use std::collections::HashSet;
|
||||
use std::net::Ipv4Addr;
|
||||
use std::pin::Pin;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::{Arc, Weak};
|
||||
|
||||
use anyhow::Context;
|
||||
use cidr::Ipv4Inet;
|
||||
use futures::{SinkExt, StreamExt};
|
||||
|
||||
use pnet::packet::ipv4::Ipv4Packet;
|
||||
|
||||
use tokio::{sync::Mutex, task::JoinSet};
|
||||
use tonic::transport::server::TcpIncoming;
|
||||
@@ -31,15 +27,9 @@ use crate::peers::rpc_service::PeerManagerRpcService;
|
||||
use crate::peers::PacketRecvChanReceiver;
|
||||
use crate::rpc::vpn_portal_rpc_server::VpnPortalRpc;
|
||||
use crate::rpc::{GetVpnPortalInfoRequest, GetVpnPortalInfoResponse, VpnPortalInfo};
|
||||
use crate::tunnel::packet_def::ZCPacket;
|
||||
|
||||
use crate::tunnel::{ZCPacketSink, ZCPacketStream};
|
||||
use crate::vpn_portal::{self, VpnPortal};
|
||||
|
||||
use super::listeners::ListenerManager;
|
||||
use super::virtual_nic;
|
||||
|
||||
use crate::common::ifcfg::IfConfiguerTrait;
|
||||
|
||||
#[derive(Clone)]
|
||||
struct IpProxy {
|
||||
@@ -82,200 +72,21 @@ impl IpProxy {
|
||||
}
|
||||
}
|
||||
|
||||
struct NicCtx {
|
||||
global_ctx: ArcGlobalCtx,
|
||||
peer_mgr: Weak<PeerManager>,
|
||||
peer_packet_receiver: Arc<Mutex<PacketRecvChanReceiver>>,
|
||||
|
||||
nic: Arc<Mutex<virtual_nic::VirtualNic>>,
|
||||
tasks: JoinSet<()>,
|
||||
}
|
||||
|
||||
#[cfg(feature = "tun")]
|
||||
type NicCtx = super::virtual_nic::NicCtx;
|
||||
#[cfg(not(feature = "tun"))]
|
||||
struct NicCtx;
|
||||
#[cfg(not(feature = "tun"))]
|
||||
impl NicCtx {
|
||||
fn new(
|
||||
global_ctx: ArcGlobalCtx,
|
||||
peer_manager: &Arc<PeerManager>,
|
||||
peer_packet_receiver: Arc<Mutex<PacketRecvChanReceiver>>,
|
||||
pub fn new(
|
||||
_global_ctx: ArcGlobalCtx,
|
||||
_peer_manager: &Arc<PeerManager>,
|
||||
_peer_packet_receiver: Arc<Mutex<PacketRecvChanReceiver>>,
|
||||
) -> Self {
|
||||
NicCtx {
|
||||
global_ctx: global_ctx.clone(),
|
||||
peer_mgr: Arc::downgrade(&peer_manager),
|
||||
peer_packet_receiver,
|
||||
nic: Arc::new(Mutex::new(virtual_nic::VirtualNic::new(global_ctx))),
|
||||
tasks: JoinSet::new(),
|
||||
}
|
||||
Self
|
||||
}
|
||||
|
||||
async fn assign_ipv4_to_tun_device(&self, ipv4_addr: Ipv4Addr) -> Result<(), Error> {
|
||||
let nic = self.nic.lock().await;
|
||||
nic.link_up().await?;
|
||||
nic.remove_ip(None).await?;
|
||||
nic.add_ip(ipv4_addr, 24).await?;
|
||||
if cfg!(target_os = "macos") {
|
||||
nic.add_route(ipv4_addr, 24).await?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn do_forward_nic_to_peers_ipv4(ret: ZCPacket, mgr: &PeerManager) {
|
||||
if let Some(ipv4) = Ipv4Packet::new(ret.payload()) {
|
||||
if ipv4.get_version() != 4 {
|
||||
tracing::info!("[USER_PACKET] not ipv4 packet: {:?}", ipv4);
|
||||
return;
|
||||
}
|
||||
let dst_ipv4 = ipv4.get_destination();
|
||||
tracing::trace!(
|
||||
?ret,
|
||||
"[USER_PACKET] recv new packet from tun device and forward to peers."
|
||||
);
|
||||
|
||||
// TODO: use zero-copy
|
||||
let send_ret = mgr.send_msg_ipv4(ret, dst_ipv4).await;
|
||||
if send_ret.is_err() {
|
||||
tracing::trace!(?send_ret, "[USER_PACKET] send_msg_ipv4 failed")
|
||||
}
|
||||
} else {
|
||||
tracing::warn!(?ret, "[USER_PACKET] not ipv4 packet");
|
||||
}
|
||||
}
|
||||
|
||||
fn do_forward_nic_to_peers(
|
||||
&mut self,
|
||||
mut stream: Pin<Box<dyn ZCPacketStream>>,
|
||||
) -> Result<(), Error> {
|
||||
// read from nic and write to corresponding tunnel
|
||||
let Some(mgr) = self.peer_mgr.upgrade() else {
|
||||
return Err(anyhow::anyhow!("peer manager not available").into());
|
||||
};
|
||||
self.tasks.spawn(async move {
|
||||
while let Some(ret) = stream.next().await {
|
||||
if ret.is_err() {
|
||||
log::error!("read from nic failed: {:?}", ret);
|
||||
break;
|
||||
}
|
||||
Self::do_forward_nic_to_peers_ipv4(ret.unwrap(), mgr.as_ref()).await;
|
||||
}
|
||||
});
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn do_forward_peers_to_nic(&mut self, mut sink: Pin<Box<dyn ZCPacketSink>>) {
|
||||
let channel = self.peer_packet_receiver.clone();
|
||||
self.tasks.spawn(async move {
|
||||
// unlock until coroutine finished
|
||||
let mut channel = channel.lock().await;
|
||||
while let Some(packet) = channel.recv().await {
|
||||
tracing::trace!(
|
||||
"[USER_PACKET] forward packet from peers to nic. packet: {:?}",
|
||||
packet
|
||||
);
|
||||
let ret = sink.send(packet).await;
|
||||
if ret.is_err() {
|
||||
tracing::error!(?ret, "do_forward_tunnel_to_nic sink error");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async fn run_proxy_cidrs_route_updater(&mut self) -> Result<(), Error> {
|
||||
let Some(peer_mgr) = self.peer_mgr.upgrade() else {
|
||||
return Err(anyhow::anyhow!("peer manager not available").into());
|
||||
};
|
||||
let global_ctx = self.global_ctx.clone();
|
||||
let net_ns = self.global_ctx.net_ns.clone();
|
||||
let nic = self.nic.lock().await;
|
||||
let ifcfg = nic.get_ifcfg();
|
||||
let ifname = nic.ifname().to_owned();
|
||||
|
||||
self.tasks.spawn(async move {
|
||||
let mut cur_proxy_cidrs = vec![];
|
||||
loop {
|
||||
let mut proxy_cidrs = vec![];
|
||||
let routes = peer_mgr.list_routes().await;
|
||||
for r in routes {
|
||||
for cidr in r.proxy_cidrs {
|
||||
let Ok(cidr) = cidr.parse::<cidr::Ipv4Cidr>() else {
|
||||
continue;
|
||||
};
|
||||
proxy_cidrs.push(cidr);
|
||||
}
|
||||
}
|
||||
// add vpn portal cidr to proxy_cidrs
|
||||
if let Some(vpn_cfg) = global_ctx.config.get_vpn_portal_config() {
|
||||
proxy_cidrs.push(vpn_cfg.client_cidr);
|
||||
}
|
||||
|
||||
// if route is in cur_proxy_cidrs but not in proxy_cidrs, delete it.
|
||||
for cidr in cur_proxy_cidrs.iter() {
|
||||
if proxy_cidrs.contains(cidr) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let _g = net_ns.guard();
|
||||
let ret = ifcfg
|
||||
.remove_ipv4_route(
|
||||
ifname.as_str(),
|
||||
cidr.first_address(),
|
||||
cidr.network_length(),
|
||||
)
|
||||
.await;
|
||||
|
||||
if ret.is_err() {
|
||||
tracing::trace!(
|
||||
cidr = ?cidr,
|
||||
err = ?ret,
|
||||
"remove route failed.",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
for cidr in proxy_cidrs.iter() {
|
||||
if cur_proxy_cidrs.contains(cidr) {
|
||||
continue;
|
||||
}
|
||||
let _g = net_ns.guard();
|
||||
let ret = ifcfg
|
||||
.add_ipv4_route(
|
||||
ifname.as_str(),
|
||||
cidr.first_address(),
|
||||
cidr.network_length(),
|
||||
)
|
||||
.await;
|
||||
|
||||
if ret.is_err() {
|
||||
tracing::trace!(
|
||||
cidr = ?cidr,
|
||||
err = ?ret,
|
||||
"add route failed.",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
cur_proxy_cidrs = proxy_cidrs;
|
||||
tokio::time::sleep(std::time::Duration::from_secs(1)).await;
|
||||
}
|
||||
});
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn run(&mut self, ipv4_addr: Ipv4Addr) -> Result<(), Error> {
|
||||
let tunnel = {
|
||||
let mut nic = self.nic.lock().await;
|
||||
let ret = nic.create_dev().await?;
|
||||
self.global_ctx
|
||||
.issue_event(GlobalCtxEvent::TunDeviceReady(nic.ifname().to_string()));
|
||||
ret
|
||||
};
|
||||
|
||||
let (stream, sink) = tunnel.split();
|
||||
|
||||
self.do_forward_nic_to_peers(stream)?;
|
||||
self.do_forward_peers_to_nic(sink);
|
||||
|
||||
self.assign_ipv4_to_tun_device(ipv4_addr).await?;
|
||||
self.run_proxy_cidrs_route_updater().await?;
|
||||
pub async fn run(&mut self, _ipv4_addr: Ipv4Addr) -> Result<(), Error> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -311,7 +122,7 @@ impl Instance {
|
||||
pub fn new(config: impl ConfigLoader + Send + Sync + 'static) -> Self {
|
||||
let global_ctx = Arc::new(GlobalCtx::new(config));
|
||||
|
||||
log::info!(
|
||||
tracing::info!(
|
||||
"[INIT] instance creating. config: {}",
|
||||
global_ctx.config.dump()
|
||||
);
|
||||
@@ -584,7 +395,7 @@ impl Instance {
|
||||
|
||||
pub async fn wait(&mut self) {
|
||||
while let Some(ret) = self.tasks.join_next().await {
|
||||
log::info!("task finished: {:?}", ret);
|
||||
tracing::info!("task finished: {:?}", ret);
|
||||
ret.unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user