mirror of
https://mirror.suhoan.cn/https://github.com/EasyTier/EasyTier.git
synced 2025-12-12 20:57:26 +08:00
Android Support (#166)
1. Add vpnservice tauri plugin for android. 2. add workflow for android. 3. Easytier Core support android, allow set tun fd.
This commit is contained in:
@@ -150,7 +150,7 @@ pub struct VpnPortalConfig {
|
||||
pub struct Flags {
|
||||
#[derivative(Default(value = "\"tcp\".to_string()"))]
|
||||
pub default_protocol: String,
|
||||
#[derivative(Default(value = "\"tun\".to_string()"))]
|
||||
#[derivative(Default(value = "\"\".to_string()"))]
|
||||
pub dev_name: String,
|
||||
#[derivative(Default(value = "true"))]
|
||||
pub enable_encryption: bool,
|
||||
|
||||
@@ -9,28 +9,40 @@ use super::error::Error;
|
||||
pub trait IfConfiguerTrait: Send + Sync {
|
||||
async fn add_ipv4_route(
|
||||
&self,
|
||||
name: &str,
|
||||
address: Ipv4Addr,
|
||||
cidr_prefix: u8,
|
||||
) -> Result<(), Error>;
|
||||
_name: &str,
|
||||
_address: Ipv4Addr,
|
||||
_cidr_prefix: u8,
|
||||
) -> Result<(), Error> {
|
||||
Ok(())
|
||||
}
|
||||
async fn remove_ipv4_route(
|
||||
&self,
|
||||
name: &str,
|
||||
address: Ipv4Addr,
|
||||
cidr_prefix: u8,
|
||||
) -> Result<(), Error>;
|
||||
_name: &str,
|
||||
_address: Ipv4Addr,
|
||||
_cidr_prefix: u8,
|
||||
) -> Result<(), Error> {
|
||||
Ok(())
|
||||
}
|
||||
async fn add_ipv4_ip(
|
||||
&self,
|
||||
name: &str,
|
||||
address: Ipv4Addr,
|
||||
cidr_prefix: u8,
|
||||
) -> Result<(), Error>;
|
||||
async fn set_link_status(&self, name: &str, up: bool) -> Result<(), Error>;
|
||||
async fn remove_ip(&self, name: &str, ip: Option<Ipv4Addr>) -> Result<(), Error>;
|
||||
_name: &str,
|
||||
_address: Ipv4Addr,
|
||||
_cidr_prefix: u8,
|
||||
) -> Result<(), Error> {
|
||||
Ok(())
|
||||
}
|
||||
async fn set_link_status(&self, _name: &str, _up: bool) -> Result<(), Error> {
|
||||
Ok(())
|
||||
}
|
||||
async fn remove_ip(&self, _name: &str, _ip: Option<Ipv4Addr>) -> Result<(), Error> {
|
||||
Ok(())
|
||||
}
|
||||
async fn wait_interface_show(&self, _name: &str) -> Result<(), Error> {
|
||||
return Ok(());
|
||||
}
|
||||
async fn set_mtu(&self, _name: &str, _mtu: u32) -> Result<(), Error>;
|
||||
async fn set_mtu(&self, _name: &str, _mtu: u32) -> Result<(), Error> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn cidr_to_subnet_mask(prefix_length: u8) -> Ipv4Addr {
|
||||
@@ -379,6 +391,10 @@ impl IfConfiguerTrait for WindowsIfConfiger {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct DummyIfConfiger {}
|
||||
#[async_trait]
|
||||
impl IfConfiguerTrait for DummyIfConfiger {}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
pub type IfConfiger = MacIfConfiger;
|
||||
|
||||
@@ -387,3 +403,6 @@ pub type IfConfiger = LinuxIfConfiger;
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
pub type IfConfiger = WindowsIfConfiger;
|
||||
|
||||
#[cfg(not(any(target_os = "macos", target_os = "linux", target_os = "windows")))]
|
||||
pub type IfConfiger = DummyIfConfiger;
|
||||
|
||||
@@ -15,6 +15,13 @@ struct InterfaceFilter {
|
||||
iface: NetworkInterface,
|
||||
}
|
||||
|
||||
#[cfg(target_os = "android")]
|
||||
impl InterfaceFilter {
|
||||
async fn filter_iface(&self) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
impl InterfaceFilter {
|
||||
async fn is_tun_tap_device(&self) -> bool {
|
||||
|
||||
@@ -24,6 +24,10 @@ async fn set_bind_addr_for_peer_connector(
|
||||
is_ipv4: bool,
|
||||
ip_collector: &Arc<IPCollector>,
|
||||
) {
|
||||
if cfg!(target_os = "android") {
|
||||
return;
|
||||
}
|
||||
|
||||
let ips = ip_collector.collect_ip_addrs().await;
|
||||
if is_ipv4 {
|
||||
let mut bind_addrs = vec![];
|
||||
|
||||
@@ -172,8 +172,8 @@ and the vpn client is in network of 10.14.14.0/24"
|
||||
#[arg(long, help = "do not use ipv6", default_value = "false")]
|
||||
disable_ipv6: bool,
|
||||
|
||||
#[arg(long, help = "interface name", default_value = "tun")]
|
||||
dev_name: String,
|
||||
#[arg(long, help = "optional tun interface name")]
|
||||
dev_name: Option<String>,
|
||||
|
||||
#[arg(
|
||||
long,
|
||||
@@ -427,7 +427,7 @@ impl From<Cli> for TomlConfigLoader {
|
||||
f.enable_encryption = !cli.disable_encryption;
|
||||
f.enable_ipv6 = !cli.disable_ipv6;
|
||||
f.latency_first = cli.latency_first;
|
||||
f.dev_name = cli.dev_name;
|
||||
f.dev_name = cli.dev_name.unwrap_or(Default::default());
|
||||
if let Some(mtu) = cli.mtu {
|
||||
f.mtu = mtu;
|
||||
}
|
||||
|
||||
@@ -214,7 +214,7 @@ impl Instance {
|
||||
let peer_manager_c = self.peer_manager.clone();
|
||||
let global_ctx_c = self.get_global_ctx();
|
||||
let nic_ctx = self.nic_ctx.clone();
|
||||
let peer_packet_receiver = self.peer_packet_receiver.clone();
|
||||
let _peer_packet_receiver = self.peer_packet_receiver.clone();
|
||||
tokio::spawn(async move {
|
||||
let default_ipv4_addr = Ipv4Inet::new(Ipv4Addr::new(10, 126, 126, 0), 24).unwrap();
|
||||
let mut current_dhcp_ip: Option<Ipv4Inet> = None;
|
||||
@@ -286,26 +286,31 @@ impl Instance {
|
||||
));
|
||||
continue;
|
||||
}
|
||||
let mut new_nic_ctx = NicCtx::new(
|
||||
global_ctx_c.clone(),
|
||||
&peer_manager_c,
|
||||
peer_packet_receiver.clone(),
|
||||
);
|
||||
if let Err(e) = new_nic_ctx.run(ip.address()).await {
|
||||
tracing::error!(
|
||||
?current_dhcp_ip,
|
||||
?candidate_ipv4_addr,
|
||||
?e,
|
||||
"add ip failed"
|
||||
|
||||
#[cfg(not(target_os = "android"))]
|
||||
{
|
||||
let mut new_nic_ctx = NicCtx::new(
|
||||
global_ctx_c.clone(),
|
||||
&peer_manager_c,
|
||||
_peer_packet_receiver.clone(),
|
||||
);
|
||||
global_ctx_c.set_ipv4(None);
|
||||
continue;
|
||||
if let Err(e) = new_nic_ctx.run(ip.address()).await {
|
||||
tracing::error!(
|
||||
?current_dhcp_ip,
|
||||
?candidate_ipv4_addr,
|
||||
?e,
|
||||
"add ip failed"
|
||||
);
|
||||
global_ctx_c.set_ipv4(None);
|
||||
continue;
|
||||
}
|
||||
Self::use_new_nic_ctx(nic_ctx.clone(), new_nic_ctx).await;
|
||||
}
|
||||
|
||||
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())));
|
||||
Self::use_new_nic_ctx(nic_ctx.clone(), new_nic_ctx).await;
|
||||
} else {
|
||||
current_dhcp_ip = None;
|
||||
global_ctx_c.set_ipv4(None);
|
||||
@@ -326,14 +331,17 @@ impl Instance {
|
||||
|
||||
if self.global_ctx.config.get_flags().no_tun {
|
||||
self.peer_packet_receiver.lock().await.close();
|
||||
} else if let Some(ipv4_addr) = self.global_ctx.get_ipv4() {
|
||||
let mut new_nic_ctx = NicCtx::new(
|
||||
self.global_ctx.clone(),
|
||||
&self.peer_manager,
|
||||
self.peer_packet_receiver.clone(),
|
||||
);
|
||||
new_nic_ctx.run(ipv4_addr).await?;
|
||||
Self::use_new_nic_ctx(self.nic_ctx.clone(), new_nic_ctx).await;
|
||||
} else {
|
||||
#[cfg(not(target_os = "android"))]
|
||||
if let Some(ipv4_addr) = self.global_ctx.get_ipv4() {
|
||||
let mut new_nic_ctx = NicCtx::new(
|
||||
self.global_ctx.clone(),
|
||||
&self.peer_manager,
|
||||
self.peer_packet_receiver.clone(),
|
||||
);
|
||||
new_nic_ctx.run(ipv4_addr).await?;
|
||||
Self::use_new_nic_ctx(self.nic_ctx.clone(), new_nic_ctx).await;
|
||||
}
|
||||
}
|
||||
|
||||
if self.global_ctx.config.get_dhcp() {
|
||||
@@ -506,4 +514,38 @@ impl Instance {
|
||||
pub fn get_vpn_portal_inst(&self) -> Arc<Mutex<Box<dyn VpnPortal>>> {
|
||||
self.vpn_portal.clone()
|
||||
}
|
||||
|
||||
pub fn get_nic_ctx(&self) -> ArcNicCtx {
|
||||
self.nic_ctx.clone()
|
||||
}
|
||||
|
||||
pub fn get_peer_packet_receiver(&self) -> Arc<Mutex<PacketRecvChanReceiver>> {
|
||||
self.peer_packet_receiver.clone()
|
||||
}
|
||||
|
||||
#[cfg(target_os = "android")]
|
||||
pub async fn setup_nic_ctx_for_android(
|
||||
nic_ctx: ArcNicCtx,
|
||||
global_ctx: ArcGlobalCtx,
|
||||
peer_manager: Arc<PeerManager>,
|
||||
peer_packet_receiver: Arc<Mutex<PacketRecvChanReceiver>>,
|
||||
fd: i32,
|
||||
) -> Result<(), anyhow::Error> {
|
||||
println!("setup_nic_ctx_for_android, fd: {}", fd);
|
||||
Self::clear_nic_ctx(nic_ctx.clone()).await;
|
||||
if fd <= 0 {
|
||||
return Ok(());
|
||||
}
|
||||
let mut new_nic_ctx = NicCtx::new(
|
||||
global_ctx.clone(),
|
||||
&peer_manager,
|
||||
peer_packet_receiver.clone(),
|
||||
);
|
||||
new_nic_ctx
|
||||
.run_for_android(fd)
|
||||
.await
|
||||
.with_context(|| "add ip failed")?;
|
||||
Self::use_new_nic_ctx(nic_ctx.clone(), new_nic_ctx).await;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -274,7 +274,9 @@ impl VirtualNic {
|
||||
#[cfg(target_os = "linux")]
|
||||
{
|
||||
let dev_name = self.global_ctx.get_flags().dev_name;
|
||||
config.name(format!("{}{}", dev_name, 0));
|
||||
if !dev_name.is_empty() {
|
||||
config.name(format!("{}", dev_name));
|
||||
}
|
||||
config.platform(|config| {
|
||||
// detect protocol by ourselves for cross platform
|
||||
config.packet_information(false);
|
||||
@@ -318,7 +320,37 @@ impl VirtualNic {
|
||||
Ok(create_as_async(&config)?)
|
||||
}
|
||||
|
||||
async fn create_dev_ret_err(&mut self) -> Result<Box<dyn Tunnel>, Error> {
|
||||
#[cfg(target_os = "android")]
|
||||
pub async fn create_dev_for_android(
|
||||
&mut self,
|
||||
tun_fd: std::os::fd::RawFd,
|
||||
) -> Result<Box<dyn Tunnel>, Error> {
|
||||
println!("tun_fd: {}", tun_fd);
|
||||
let mut config = Configuration::default();
|
||||
config.layer(Layer::L3);
|
||||
config.raw_fd(tun_fd);
|
||||
config.platform(|config| {
|
||||
config.no_close_fd_on_drop(true);
|
||||
});
|
||||
config.up();
|
||||
|
||||
let dev = create_as_async(&config)?;
|
||||
let (a, b) = BiLock::new(dev);
|
||||
let ft = TunnelWrapper::new(
|
||||
TunStream::new(a, false),
|
||||
FramedWriter::new_with_converter(
|
||||
TunAsyncWrite { l: b },
|
||||
TunZCPacketToBytes::new(false),
|
||||
),
|
||||
None,
|
||||
);
|
||||
|
||||
self.ifname = Some(format!("tunfd_{}", tun_fd));
|
||||
|
||||
Ok(Box::new(ft))
|
||||
}
|
||||
|
||||
pub async fn create_dev(&mut self) -> Result<Box<dyn Tunnel>, Error> {
|
||||
let dev = self.create_tun().await?;
|
||||
let ifname = dev.get_ref().name()?;
|
||||
self.ifcfg.wait_interface_show(ifname.as_str()).await?;
|
||||
@@ -351,10 +383,6 @@ impl VirtualNic {
|
||||
Ok(Box::new(ft))
|
||||
}
|
||||
|
||||
pub async fn create_dev(&mut self) -> Result<Box<dyn Tunnel>, Error> {
|
||||
self.create_dev_ret_err().await
|
||||
}
|
||||
|
||||
pub fn ifname(&self) -> &str {
|
||||
self.ifname.as_ref().unwrap().as_str()
|
||||
}
|
||||
@@ -589,6 +617,24 @@ impl NicCtx {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(target_os = "android")]
|
||||
pub async fn run_for_android(&mut self, tun_fd: std::os::fd::RawFd) -> Result<(), Error> {
|
||||
let tunnel = {
|
||||
let mut nic = self.nic.lock().await;
|
||||
let ret = nic.create_dev_for_android(tun_fd).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);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -19,6 +19,7 @@ use crate::{
|
||||
};
|
||||
use chrono::{DateTime, Local};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tokio::task::JoinSet;
|
||||
|
||||
#[derive(Default, Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct MyNodeInfo {
|
||||
@@ -35,6 +36,7 @@ struct EasyTierData {
|
||||
node_info: Arc<RwLock<MyNodeInfo>>,
|
||||
routes: Arc<RwLock<Vec<Route>>>,
|
||||
peers: Arc<RwLock<Vec<PeerInfo>>>,
|
||||
tun_fd: Arc<RwLock<Option<i32>>>,
|
||||
}
|
||||
|
||||
pub struct EasyTierLauncher {
|
||||
@@ -69,6 +71,40 @@ impl EasyTierLauncher {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "android")]
|
||||
async fn run_routine_for_android(
|
||||
instance: &Instance,
|
||||
data: &EasyTierData,
|
||||
tasks: &mut JoinSet<()>,
|
||||
) {
|
||||
let global_ctx = instance.get_global_ctx();
|
||||
let peer_mgr = instance.get_peer_manager();
|
||||
let nic_ctx = instance.get_nic_ctx();
|
||||
let peer_packet_receiver = instance.get_peer_packet_receiver();
|
||||
let arc_tun_fd = data.tun_fd.clone();
|
||||
|
||||
tasks.spawn(async move {
|
||||
let mut old_tun_fd = arc_tun_fd.read().unwrap().clone();
|
||||
loop {
|
||||
tokio::time::sleep(std::time::Duration::from_secs(1)).await;
|
||||
let tun_fd = arc_tun_fd.read().unwrap().clone();
|
||||
if tun_fd != old_tun_fd && tun_fd.is_some() {
|
||||
let res = Instance::setup_nic_ctx_for_android(
|
||||
nic_ctx.clone(),
|
||||
global_ctx.clone(),
|
||||
peer_mgr.clone(),
|
||||
peer_packet_receiver.clone(),
|
||||
tun_fd.unwrap(),
|
||||
)
|
||||
.await;
|
||||
if res.is_ok() {
|
||||
old_tun_fd = tun_fd;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async fn easytier_routine(
|
||||
cfg: TomlConfigLoader,
|
||||
stop_signal: Arc<tokio::sync::Notify>,
|
||||
@@ -77,10 +113,12 @@ impl EasyTierLauncher {
|
||||
let mut instance = Instance::new(cfg);
|
||||
let peer_mgr = instance.get_peer_manager();
|
||||
|
||||
let mut tasks = JoinSet::new();
|
||||
|
||||
// Subscribe to global context events
|
||||
let global_ctx = instance.get_global_ctx();
|
||||
let data_c = data.clone();
|
||||
tokio::spawn(async move {
|
||||
tasks.spawn(async move {
|
||||
let mut receiver = global_ctx.subscribe();
|
||||
while let Ok(event) = receiver.recv().await {
|
||||
Self::handle_easytier_event(event, data_c.clone()).await;
|
||||
@@ -92,7 +130,7 @@ impl EasyTierLauncher {
|
||||
let global_ctx_c = instance.get_global_ctx();
|
||||
let peer_mgr_c = peer_mgr.clone();
|
||||
let vpn_portal = instance.get_vpn_portal_inst();
|
||||
tokio::spawn(async move {
|
||||
tasks.spawn(async move {
|
||||
loop {
|
||||
let node_info = MyNodeInfo {
|
||||
virtual_ipv4: global_ctx_c
|
||||
@@ -123,8 +161,15 @@ impl EasyTierLauncher {
|
||||
}
|
||||
});
|
||||
|
||||
#[cfg(target_os = "android")]
|
||||
Self::run_routine_for_android(&instance, &data, &mut tasks).await;
|
||||
|
||||
instance.run().await?;
|
||||
stop_signal.notified().await;
|
||||
|
||||
tasks.abort_all();
|
||||
drop(tasks);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -266,6 +311,12 @@ impl NetworkInstance {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn set_tun_fd(&mut self, tun_fd: i32) {
|
||||
if let Some(launcher) = self.launcher.as_ref() {
|
||||
launcher.data.tun_fd.write().unwrap().replace(tun_fd);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn start(&mut self) -> Result<(), anyhow::Error> {
|
||||
if self.is_easytier_running() {
|
||||
return Ok(());
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use crate::common::PeerId;
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
mod three_node;
|
||||
|
||||
pub fn get_guest_veth_name(net_ns: &str) -> &str {
|
||||
|
||||
Reference in New Issue
Block a user