diff --git a/vnt-jni/java/top/wherewego/vnt/jni/CallBack.java b/vnt-jni/java/top/wherewego/vnt/jni/CallBack.java index 305e8a2..52e22f3 100644 --- a/vnt-jni/java/top/wherewego/vnt/jni/CallBack.java +++ b/vnt-jni/java/top/wherewego/vnt/jni/CallBack.java @@ -12,8 +12,10 @@ public interface CallBack { * 连接成功的回调 */ void success(); + /** * 创建虚拟网卡成功的回调方法 + * 仅在 windows/linux/macos上使用 * * @param info 网卡信息 */ @@ -42,6 +44,24 @@ public interface CallBack { */ boolean register(RegisterInfo info); + /** + * 创建网卡回调 + * 仅在android上使用 + * + * @param info 创建配置 + * @return 网卡fd + */ + + int generateTun(DeviceConfig info); + + /** + * 对端用户列表 + * + * @param infoArray + */ + void peerClientList(PeerClientInfo[] infoArray); + + /** * 异常回调 * diff --git a/vnt-jni/java/top/wherewego/vnt/jni/PeerDeviceInfo.java b/vnt-jni/java/top/wherewego/vnt/jni/PeerRouteInfo.java similarity index 88% rename from vnt-jni/java/top/wherewego/vnt/jni/PeerDeviceInfo.java rename to vnt-jni/java/top/wherewego/vnt/jni/PeerRouteInfo.java index b7e2126..adc92a7 100644 --- a/vnt-jni/java/top/wherewego/vnt/jni/PeerDeviceInfo.java +++ b/vnt-jni/java/top/wherewego/vnt/jni/PeerRouteInfo.java @@ -5,13 +5,13 @@ package top.wherewego.vnt.jni; * * @author https://github.com/lbl8603/vnt */ -public class PeerDeviceInfo { +public class PeerRouteInfo { private final int virtualIp; private final String name; private final String status; private final Route route; - public PeerDeviceInfo(int virtualIp, String name, String status, Route route) { + public PeerRouteInfo(int virtualIp, String name, String status, Route route) { this.virtualIp = virtualIp; this.name = name; this.status = status; diff --git a/vnt-jni/java/top/wherewego/vnt/jni/Route.java b/vnt-jni/java/top/wherewego/vnt/jni/Route.java index 4b90ffb..fe68702 100644 --- a/vnt-jni/java/top/wherewego/vnt/jni/Route.java +++ b/vnt-jni/java/top/wherewego/vnt/jni/Route.java @@ -6,16 +6,26 @@ package top.wherewego.vnt.jni; * @author https://github.com/lbl8603/vnt */ public class Route { + /** + * 是否使用tcp + */ + private final boolean tcp; private final String address; private final byte metric; private final int rt; - public Route(String address, byte metric, int rt) { + + public Route(boolean tcp, String address, byte metric, int rt) { + this.tcp = tcp; this.address = address; this.metric = metric; this.rt = rt; } + public boolean isTcp() { + return tcp; + } + public String getAddress() { return address; } @@ -31,7 +41,8 @@ public class Route { @Override public String toString() { return "Route{" + - "address='" + address + '\'' + + "tcp=" + tcp + + ", address='" + address + '\'' + ", metric=" + metric + ", rt=" + rt + '}'; diff --git a/vnt-jni/java/top/wherewego/vnt/jni/Vnt.java b/vnt-jni/java/top/wherewego/vnt/jni/Vnt.java index 199a564..a2bd45a 100644 --- a/vnt-jni/java/top/wherewego/vnt/jni/Vnt.java +++ b/vnt-jni/java/top/wherewego/vnt/jni/Vnt.java @@ -13,6 +13,9 @@ public class Vnt implements Closeable { public Vnt(Config config, CallBack callBack) throws Exception{ this.raw = new0(config, callBack); + if (this.raw == 0) { + throw new RuntimeException(); + } } public void stop() { @@ -23,7 +26,7 @@ public class Vnt implements Closeable { wait0(raw); } - public PeerDeviceInfo[] list() { + public PeerRouteInfo[] list() { return list0(raw); } @@ -35,7 +38,7 @@ public class Vnt implements Closeable { private native void drop0(long raw); - private native PeerDeviceInfo[] list0(long raw); + private native PeerRouteInfo[] list0(long raw); @Override public void close() throws IOException { diff --git a/vnt-jni/java/top/wherewego/vnt/jni/param/DeviceConfig.java b/vnt-jni/java/top/wherewego/vnt/jni/param/DeviceConfig.java new file mode 100644 index 0000000..f3b38af --- /dev/null +++ b/vnt-jni/java/top/wherewego/vnt/jni/param/DeviceConfig.java @@ -0,0 +1,60 @@ +package top.wherewego.vnt.jni.param; + +import top.wherewego.vnt.jni.IpUtils; + +/** + * 创建网卡所需信息,仅在android上使用 + * + * @author https://github.com/lbl8603/vnt + */ +public class DeviceConfig { + /** + * 虚拟IP + */ + public final int virtualIp; + /** + * 掩码 + */ + public final int virtualNetmask; + /** + * 网关 + */ + public final int virtualGateway; + /** + * 虚拟网段 + */ + public final int virtualNetwork; + + public DeviceConfig(int virtualIp, int virtualNetmask, int virtualGateway, int virtualNetwork) { + this.virtualIp = virtualIp; + this.virtualNetmask = virtualNetmask; + this.virtualGateway = virtualGateway; + this.virtualNetwork = virtualNetwork; + } + + public int getVirtualIp() { + return virtualIp; + } + + public int getVirtualNetmask() { + return virtualNetmask; + } + + public int getVirtualGateway() { + return virtualGateway; + } + + public int getVirtualNetwork() { + return virtualNetwork; + } + + @Override + public String toString() { + return "DeviceConfig{" + + "virtualIp=" + IpUtils.intToIpAddress(virtualIp) + + ", virtualNetmask=" + IpUtils.intToIpAddress(virtualNetmask) + + ", virtualGateway=" + IpUtils.intToIpAddress(virtualGateway) + + ", virtualNetwork=" + IpUtils.intToIpAddress(virtualNetwork) + + '}'; + } +} diff --git a/vnt-jni/java/top/wherewego/vnt/jni/param/DeviceInfo.java b/vnt-jni/java/top/wherewego/vnt/jni/param/DeviceInfo.java index 020254a..ddb8f0a 100644 --- a/vnt-jni/java/top/wherewego/vnt/jni/param/DeviceInfo.java +++ b/vnt-jni/java/top/wherewego/vnt/jni/param/DeviceInfo.java @@ -1,7 +1,7 @@ package top.wherewego.vnt.jni.param; /** - * 网卡信息 + * 网卡信息 仅在 windows/linux/macos上使用 * * @author https://github.com/lbl8603/vnt */ diff --git a/vnt-jni/java/top/wherewego/vnt/jni/param/ErrorInfo.java b/vnt-jni/java/top/wherewego/vnt/jni/param/ErrorInfo.java index f2ea8b7..f24e443 100644 --- a/vnt-jni/java/top/wherewego/vnt/jni/param/ErrorInfo.java +++ b/vnt-jni/java/top/wherewego/vnt/jni/param/ErrorInfo.java @@ -16,15 +16,25 @@ public class ErrorInfo { public final String msg; public ErrorInfo(int code, String msg) { - this.code = switch (code) { - case 1 -> ErrorCodeEnum.TokenError; - case 2 -> ErrorCodeEnum.Disconnect; - case 3 -> ErrorCodeEnum.AddressExhausted; - case 4 -> ErrorCodeEnum.IpAlreadyExists; - case 5 -> ErrorCodeEnum.InvalidIp; - case 6 -> ErrorCodeEnum.Unknown; - default -> null; - }; + switch (code) { + case 1: + this.code = ErrorCodeEnum.TokenError; + break; + case 2: + this.code = ErrorCodeEnum.Disconnect; + break; + case 3: + this.code = ErrorCodeEnum.AddressExhausted; + break; + case 4: + this.code = ErrorCodeEnum.IpAlreadyExists; + break; + case 5: + this.code = ErrorCodeEnum.InvalidIp; + break; + default: + this.code = ErrorCodeEnum.Unknown; + } this.msg = msg; } diff --git a/vnt-jni/java/top/wherewego/vnt/jni/param/PeerClientInfo.java b/vnt-jni/java/top/wherewego/vnt/jni/param/PeerClientInfo.java new file mode 100644 index 0000000..f19a759 --- /dev/null +++ b/vnt-jni/java/top/wherewego/vnt/jni/param/PeerClientInfo.java @@ -0,0 +1,60 @@ +package top.wherewego.vnt.jni.param; + +import top.wherewego.vnt.jni.IpUtils; + +/** + * 创建网卡所需信息,仅在android上使用 + * + * @author https://github.com/lbl8603/vnt + */ +public class PeerClientInfo { + /** + * 虚拟IP + */ + public final int virtualIp; + /** + * 名称 + */ + public final String name; + /** + * 是否在线 + */ + public final boolean online; + /** + * 是否开启客户端加密,不同加密状态的不能通信 + */ + public final boolean clientSecret; + + public PeerClientInfo(int virtualIp, String name, boolean online, boolean clientSecret) { + this.virtualIp = virtualIp; + this.name = name; + this.online = online; + this.clientSecret = clientSecret; + } + + public int getVirtualIp() { + return virtualIp; + } + + public String getName() { + return name; + } + + public boolean isOnline() { + return online; + } + + public boolean isClientSecret() { + return clientSecret; + } + + @Override + public String toString() { + return "PeerDeviceInfo{" + + "virtualIp=" + IpUtils.intToIpAddress(virtualIp) + + ", name='" + name + '\'' + + ", online=" + online + + ", clientSecret=" + clientSecret + + '}'; + } +} diff --git a/vnt-jni/java/top/wherewego/vnt/jni/param/RegisterInfo.java b/vnt-jni/java/top/wherewego/vnt/jni/param/RegisterInfo.java index 9d51a6d..3ff5cd0 100644 --- a/vnt-jni/java/top/wherewego/vnt/jni/param/RegisterInfo.java +++ b/vnt-jni/java/top/wherewego/vnt/jni/param/RegisterInfo.java @@ -1,5 +1,7 @@ package top.wherewego.vnt.jni.param; +import top.wherewego.vnt.jni.IpUtils; + /** * 注册回调信息 * @@ -9,40 +11,40 @@ public class RegisterInfo { /** * 虚拟IP */ - public final String virtualIp; + public final int virtualIp; /** * 掩码 */ - public final String virtualNetmask; + public final int virtualNetmask; /** * 网关 */ - public final String virtualGateway; + public final int virtualGateway; - public RegisterInfo(String virtualIp, String virtualNetmask, String virtualGateway) { + public RegisterInfo(int virtualIp, int virtualNetmask, int virtualGateway) { this.virtualIp = virtualIp; this.virtualNetmask = virtualNetmask; this.virtualGateway = virtualGateway; } - public String getVirtualIp() { + public int getVirtualIp() { return virtualIp; } - public String getVirtualNetmask() { + public int getVirtualNetmask() { return virtualNetmask; } - public String getVirtualGateway() { + public int getVirtualGateway() { return virtualGateway; } @Override public String toString() { return "RegisterInfo{" + - "virtualIp='" + virtualIp + '\'' + - ", virtualNetmask='" + virtualNetmask + '\'' + - ", virtualGateway='" + virtualGateway + '\'' + + "virtualIp='" + IpUtils.intToIpAddress(virtualIp) + '\'' + + ", virtualNetmask='" + IpUtils.intToIpAddress(virtualNetmask) + '\'' + + ", virtualGateway='" + IpUtils.intToIpAddress(virtualGateway) + '\'' + '}'; } } diff --git a/vnt-jni/src/callback.rs b/vnt-jni/src/callback.rs index 14336cc..b909646 100644 --- a/vnt-jni/src/callback.rs +++ b/vnt-jni/src/callback.rs @@ -1,40 +1,87 @@ use std::sync::Arc; -use jni::objects::{GlobalRef, JString, JValue}; +use jni::objects::{GlobalRef, JClass, JObject, JString, JValue}; use jni::{JNIEnv, JavaVM}; use spki::der::pem::LineEnding; use spki::EncodePublicKey; use vnt::handle::callback::ConnectInfo; -use vnt::{DeviceInfo, ErrorInfo, HandshakeInfo, RegisterInfo, VntCallback}; +#[cfg(target_os = "android")] +use vnt::handle::callback::DeviceConfig; +#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))] +use vnt::DeviceInfo; +use vnt::{ErrorInfo, HandshakeInfo, PeerClientInfo, RegisterInfo, VntCallback}; #[derive(Clone)] pub struct CallBack { jvm: Arc, this: GlobalRef, + connect_info_class: GlobalRef, + handshake_info_class: GlobalRef, + error_info_class: GlobalRef, + register_info_class: GlobalRef, + #[cfg(target_os = "android")] + device_config_class: GlobalRef, + peer_client_info_class: GlobalRef, + #[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))] + device_info_class: GlobalRef, } unsafe impl Send for CallBack {} +fn find_class_global_ref(env: &mut JNIEnv, class: &str) -> jni::errors::Result { + let class = env.find_class(class)?; + env.new_global_ref(class) +} impl CallBack { - pub fn new(jvm: JavaVM, this: GlobalRef) -> Self { - Self { + pub fn new(jvm: JavaVM, this: GlobalRef) -> jni::errors::Result { + let mut env = jvm.attach_current_thread_as_daemon()?; + let connect_info_class = + find_class_global_ref(&mut env, "top/wherewego/vnt/jni/param/ConnectInfo")?; + let handshake_info_class = + find_class_global_ref(&mut env, "top/wherewego/vnt/jni/param/HandshakeInfo")?; + let error_info_class = + find_class_global_ref(&mut env, "top/wherewego/vnt/jni/param/ErrorInfo")?; + let register_info_class = + find_class_global_ref(&mut env, "top/wherewego/vnt/jni/param/RegisterInfo")?; + #[cfg(target_os = "android")] + let device_config_class = crate::callback::find_class_global_ref( + &mut env, + "top/wherewego/vnt/jni/param/DeviceConfig", + )?; + let peer_client_info_class = + find_class_global_ref(&mut env, "top/wherewego/vnt/jni/param/PeerClientInfo")?; + #[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))] + let device_info_class = + find_class_global_ref(&mut env, "top/wherewego/vnt/jni/param/DeviceInfo")?; + Ok(Self { jvm: Arc::new(jvm), this, - } + connect_info_class, + handshake_info_class, + error_info_class, + register_info_class, + #[cfg(target_os = "android")] + device_config_class, + peer_client_info_class, + #[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))] + device_info_class, + }) } } impl CallBack { fn success0(&self) -> jni::errors::Result<()> { - let env = &mut self.jvm.attach_current_thread()? as &mut JNIEnv; + let mut env = self.jvm.attach_current_thread_as_daemon()?; env.call_method(&self.this, "success", "()V", &[])?; Ok(()) } + #[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))] fn create_tun0(&self, info: DeviceInfo) -> jni::errors::Result<()> { - let env = &mut self.jvm.attach_current_thread()? as &mut JNIEnv; + let mut env = self.jvm.attach_current_thread_as_daemon()?; + let class = unsafe { JClass::from_raw(self.device_info_class.as_raw()) }; let param = env.new_object( - "top/wherewego/vnt/jni/param/DeviceInfo", + class, "(Ljava/lang/String;Ljava/lang/String;)V", &[ JValue::Object(&env.new_string(info.name)?.into()), @@ -50,9 +97,10 @@ impl CallBack { Ok(()) } fn connect0(&self, info: ConnectInfo) -> jni::errors::Result<()> { - let env = &mut self.jvm.attach_current_thread()? as &mut JNIEnv; + let mut env = self.jvm.attach_current_thread_as_daemon()?; + let class = unsafe { JClass::from_raw(self.connect_info_class.as_raw()) }; let param = env.new_object( - "top/wherewego/vnt/jni/param/ConnectInfo", + class, "(JLjava/lang/String;)V", &[ JValue::Long(info.count as _), @@ -68,7 +116,7 @@ impl CallBack { Ok(()) } fn handshake0(&self, info: HandshakeInfo) -> jni::errors::Result { - let env = &mut self.jvm.attach_current_thread()? as &mut JNIEnv; + let mut env = self.jvm.attach_current_thread_as_daemon()?; let public_key = if let Some(public_key) = info.public_key { match public_key.to_public_key_pem(LineEnding::CRLF) { Ok(public_key) => env.new_string(public_key)?, @@ -85,8 +133,10 @@ impl CallBack { } else { JString::default() }; + let class = unsafe { JClass::from_raw(self.handshake_info_class.as_raw()) }; + let param = env.new_object( - "top/wherewego/vnt/jni/param/HandshakeInfo", + class, "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V", &[ JValue::Object(&public_key), @@ -103,14 +153,15 @@ impl CallBack { rs.z() } fn register0(&self, info: RegisterInfo) -> jni::errors::Result { - let env = &mut self.jvm.attach_current_thread()? as &mut JNIEnv; + let mut env = self.jvm.attach_current_thread_as_daemon()?; + let class = unsafe { JClass::from_raw(self.register_info_class.as_raw()) }; let param = env.new_object( - "top/wherewego/vnt/jni/param/RegisterInfo", - "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V", + class, + "(III)V", &[ - JValue::Object(&env.new_string(info.virtual_ip.to_string())?.into()), - JValue::Object(&env.new_string(info.virtual_netmask.to_string())?.into()), - JValue::Object(&env.new_string(info.virtual_gateway.to_string())?.into()), + JValue::Int(Into::::into(info.virtual_ip) as _), + JValue::Int(Into::::into(info.virtual_netmask) as _), + JValue::Int(Into::::into(info.virtual_gateway) as _), ], )?; let rs = env.call_method( @@ -121,16 +172,66 @@ impl CallBack { )?; rs.z() } + #[cfg(target_os = "android")] + fn generate_tun0(&self, info: DeviceConfig) -> jni::errors::Result { + let mut env = self.jvm.attach_current_thread_as_daemon()?; + let class = unsafe { JClass::from_raw(self.device_config_class.as_raw()) }; + let param = env.new_object( + class, + "(IIII)V", + &[ + JValue::Int(Into::::into(info.virtual_ip) as _), + JValue::Int(Into::::into(info.virtual_netmask) as _), + JValue::Int(Into::::into(info.virtual_gateway) as _), + JValue::Int(Into::::into(info.virtual_network) as _), + ], + )?; + let rs = env.call_method( + &self.this, + "generateTun", + "(Ltop/wherewego/vnt/jni/param/DeviceConfig;)I", + &[JValue::Object(¶m)], + )?; + rs.i().map(|v| v as _) + } + fn peer_client_list0(&self, info_vec: Vec) -> jni::errors::Result<()> { + let mut env = self.jvm.attach_current_thread_as_daemon()?; + let class = unsafe { JClass::from_raw(self.peer_client_info_class.as_raw()) }; + let object_array = env.new_object_array(info_vec.len() as _, &class, JObject::null())?; + for (index, info) in info_vec.into_iter().enumerate() { + let param = env.new_object( + &class, + "(ILjava/lang/String;ZZ)V", + &[ + JValue::Int(Into::::into(info.virtual_ip) as _), + JValue::Object(&env.new_string(info.name)?.into()), + JValue::Bool(info.status.is_online() as _), + JValue::Bool(info.client_secret as _), + ], + )?; + env.set_object_array_element(&object_array, index as _, ¶m)?; + } + + env.call_method( + &self.this, + "peerClientList", + "([Ltop/wherewego/vnt/jni/param/PeerClientInfo;)V", + &[JValue::Object(&object_array)], + )?; + Ok(()) + } + fn error0(&self, info: ErrorInfo) -> jni::errors::Result<()> { let code: u8 = info.code.into(); - let env = &mut self.jvm.attach_current_thread()? as &mut JNIEnv; + let mut env = self.jvm.attach_current_thread_as_daemon()?; + let class = unsafe { JClass::from_raw(self.error_info_class.as_raw()) }; let msg = if let Some(msg) = info.msg { env.new_string(msg)? } else { JString::default() }; let param = env.new_object( - "top/wherewego/vnt/jni/param/ErrorInfo", + class, "(ILjava/lang/String;)V", &[JValue::Int(code as _), JValue::Object(&msg.into())], )?; @@ -143,7 +244,7 @@ impl CallBack { Ok(()) } fn stop0(&self) -> jni::errors::Result<()> { - let env = &mut self.jvm.attach_current_thread()? as &mut JNIEnv; + let mut env = self.jvm.attach_current_thread_as_daemon()?; env.call_method(&self.this, "stop", "()V", &[])?; Ok(()) } @@ -155,6 +256,7 @@ impl VntCallback for CallBack { log::warn!("success {:?}", e); } } + #[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))] fn create_tun(&self, info: DeviceInfo) { if let Err(e) = self.create_tun0(info) { log::warn!("create_tun {:?}", e); @@ -180,6 +282,19 @@ impl VntCallback for CallBack { false }) } + #[cfg(target_os = "android")] + fn generate_tun(&self, info: DeviceConfig) -> u32 { + self.generate_tun0(info).unwrap_or_else(|e| { + log::warn!("generate_tun {:?}", e); + 0 + }) + } + + fn peer_client_list(&self, info: Vec) { + if let Err(e) = self.peer_client_list0(info) { + log::warn!("peer_client_list {:?}", e); + } + } fn error(&self, info: ErrorInfo) { if let Err(e) = self.error0(info) { diff --git a/vnt-jni/src/config.rs b/vnt-jni/src/config.rs index b43d8d4..46d66e0 100644 --- a/vnt-jni/src/config.rs +++ b/vnt-jni/src/config.rs @@ -107,8 +107,6 @@ pub fn new_config(env: &mut JNIEnv, config: JObject) -> Result { }; #[cfg(not(target_os = "android"))] let device_name = to_string(env, &config, "deviceName")?; - #[cfg(target_os = "android")] - let device_fd = env.get_field(&config, "deviceFd", "I")?.i()? as i32; let config = match Config::new( #[cfg(any(target_os = "windows", target_os = "linux"))] tap, @@ -134,8 +132,6 @@ pub fn new_config(env: &mut JNIEnv, config: JObject) -> Result { first_latency, #[cfg(not(target_os = "android"))] device_name, - #[cfg(target_os = "android")] - device_fd, UseChannelType::from_str(&use_channel.unwrap_or_default()).unwrap_or_default(), packet_loss_rate, packet_delay, diff --git a/vnt-jni/src/vnt.rs b/vnt-jni/src/vnt.rs index 8cb8c3b..d1a0196 100644 --- a/vnt-jni/src/vnt.rs +++ b/vnt-jni/src/vnt.rs @@ -2,7 +2,7 @@ use std::ptr; use jni::errors::Error; use jni::objects::{JClass, JObject, JValue}; -use jni::sys::{jbyte, jint, jlong, jobject, jobjectArray, jsize}; +use jni::sys::{jint, jlong, jobject, jobjectArray, jsize}; use jni::JNIEnv; use vnt::channel::Route; @@ -30,7 +30,13 @@ pub unsafe extern "C" fn Java_top_wherewego_vnt_jni_Vnt_new0( } else { return 0; }; - let vnt_util = match Vnt::new(config, CallBack::new(jvm, call_back)) { + let call_back = match CallBack::new(jvm, call_back) { + Ok(call_back) => call_back, + Err(_) => { + return 0; + } + }; + let vnt_util = match Vnt::new(config, call_back) { Ok(vnt_util) => vnt_util, Err(e) => { env.throw_new( @@ -58,6 +64,7 @@ pub unsafe extern "C" fn Java_top_wherewego_vnt_jni_Vnt_stop0( let vnt = raw_vnt as *mut Vnt; let _ = (&*vnt).stop(); } + #[no_mangle] pub unsafe extern "C" fn Java_top_wherewego_vnt_jni_Vnt_wait0( _env: JNIEnv, @@ -90,7 +97,7 @@ pub unsafe extern "C" fn Java_top_wherewego_vnt_jni_Vnt_list0( let arr = match env.new_object_array( list.len() as jsize, - "top/wherewego/vnt/jni/PeerDeviceInfo", + "top/wherewego/vnt/jni/PeerRouteInfo", JObject::null(), ) { Ok(arr) => arr, @@ -131,16 +138,14 @@ pub unsafe extern "C" fn Java_top_wherewego_vnt_jni_Vnt_list0( } fn route_parse(env: &mut JNIEnv, route: Route) -> Result { - let address = route.addr.to_string(); - let metric = route.metric; - let rt = route.rt; let rs = env.new_object( "top/wherewego/vnt/jni/Route", - "(Ljava/lang/String;BI)V", + "(ZLjava/lang/String;BI)V", &[ - JValue::Object(&env.new_string(address)?.into()), - JValue::Byte(metric as jbyte), - JValue::Int(rt as jint), + JValue::Bool(route.is_tcp as _), + JValue::Object(&env.new_string(route.addr.to_string())?.into()), + JValue::Byte(route.metric as _), + JValue::Int(route.rt as _), ], )?; Ok(rs.as_raw()) @@ -155,7 +160,7 @@ fn peer_device_info_parse( let name = peer.name.to_string(); let status = format!("{:?}", peer.status); let rs = env.new_object( - "top/wherewego/vnt/jni/PeerDeviceInfo", + "top/wherewego/vnt/jni/PeerRouteInfo", "(ILjava/lang/String;Ljava/lang/String;Ltop/wherewego/vnt/jni/Route;)V", &[ JValue::Int(virtual_ip as jint), diff --git a/vnt/Cargo.toml b/vnt/Cargo.toml index d26afa4..32a456f 100644 --- a/vnt/Cargo.toml +++ b/vnt/Cargo.toml @@ -31,7 +31,7 @@ openssl-sys = { git = "https://github.com/lbl8603/rust-openssl" ,optional = true libsm = {git="https://github.com/lbl8603/libsm" ,optional = true} mio = {version = "0.8.10",features = ["os-poll","net"]} - +crossbeam-queue = "0.3.11" [target.'cfg(target_os = "windows")'.dependencies] libloading = "0.8.0" diff --git a/vnt/src/core/conn.rs b/vnt/src/core/conn.rs index 8d639b1..f0bb8cf 100644 --- a/vnt/src/core/conn.rs +++ b/vnt/src/core/conn.rs @@ -7,7 +7,7 @@ use std::time::Duration; use crossbeam_utils::atomic::AtomicCell; use parking_lot::{Mutex, RwLock}; use rand::Rng; - +#[cfg(not(target_os = "android"))] use tun::device::IFace; use crate::channel::context::Context; @@ -22,14 +22,15 @@ use crate::external_route::{AllowExternalRoute, ExternalRoute}; use crate::handle::handshaker::Handshake; use crate::handle::maintain::PunchReceiver; use crate::handle::recv_data::RecvDataHandler; -use crate::handle::{ - maintain, tun_tap, BaseConfigInfo, ConnectStatus, CurrentDeviceInfo, PeerDeviceInfo, -}; +use crate::handle::{maintain, BaseConfigInfo, ConnectStatus, CurrentDeviceInfo, PeerDeviceInfo}; use crate::nat::NatTest; +use crate::tun_tap_device::tun_create_helper::{DeviceAdapter, TunDeviceHelper}; use crate::util::{ Scheduler, SingleU64Adder, StopManager, U64Adder, WatchSingleU64Adder, WatchU64Adder, }; -use crate::{nat, tun_tap_device, DeviceInfo, VntCallback}; +use crate::{nat, VntCallback}; +#[cfg(not(target_os = "android"))] +use crate::{tun_tap_device, DeviceInfo}; #[derive(Clone)] pub struct Vnt { @@ -113,10 +114,14 @@ impl Vnt { tcp_port, ); - // 虚拟网卡 - let device = tun_tap_device::create_device(&config)?; - let tun_info = DeviceInfo::new(device.name()?, device.version()?); - callback.create_tun(tun_info); + // pc上先创建虚拟网卡 + #[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))] + let device = { + let device = tun_tap_device::create_device(&config)?; + let tun_info = DeviceInfo::new(device.name()?, device.version()?); + callback.create_tun(tun_info); + device + }; // 服务停止管理器 let stop_manager = { let callback = callback.clone(); @@ -146,13 +151,33 @@ impl Vnt { U64Adder::with_capacity(config.ports.as_ref().map(|v| v.len()).unwrap_or_default() + 8); let down_count_watcher = down_counter.watch(); let handshake = Handshake::new(rsa_cipher.clone()); + let up_counter = SingleU64Adder::new(); + let up_count_watcher = up_counter.watch(); + let tun_helper = TunDeviceHelper::new( + stop_manager.clone(), + context.clone(), + current_device.clone(), + external_route.clone(), + #[cfg(feature = "ip_proxy")] + proxy_map.clone(), + client_cipher.clone(), + server_cipher.clone(), + config.parallel, + up_counter, + device_list.clone(), + ); + #[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))] + let device_adapter = DeviceAdapter::new(device.clone()); + #[cfg(target_os = "android")] + let device_adapter = DeviceAdapter::new(tun_helper); + let handler = RecvDataHandler::new( #[cfg(feature = "server_encrypt")] rsa_cipher, server_cipher.clone(), client_cipher.clone(), current_device.clone(), - device.clone(), + device_adapter, device_list.clone(), config_info.clone(), nat_test.clone(), @@ -177,22 +202,10 @@ impl Vnt { config.tcp, tcp_socket_sender.clone(), ); - let up_counter = SingleU64Adder::new(); - let up_count_watcher = up_counter.watch(); - tun_tap::tun_handler::start( - stop_manager.clone(), - context.clone(), - device.clone(), - current_device.clone(), - external_route, - #[cfg(feature = "ip_proxy")] - proxy_map, - client_cipher.clone(), - server_cipher.clone(), - config.parallel, - up_counter, - device_list.clone(), - )?; + + #[cfg(not(target_os = "android"))] + tun_helper.start(device)?; + maintain::idle_gateway( &scheduler, context.clone(), diff --git a/vnt/src/core/mod.rs b/vnt/src/core/mod.rs index b53ac46..a297b7e 100644 --- a/vnt/src/core/mod.rs +++ b/vnt/src/core/mod.rs @@ -36,8 +36,6 @@ pub struct Config { pub first_latency: bool, #[cfg(not(target_os = "android"))] pub device_name: Option, - #[cfg(target_os = "android")] - pub device_fd: i32, pub use_channel_type: UseChannelType, //控制丢包率 pub packet_loss_rate: Option, @@ -68,7 +66,6 @@ impl Config { ports: Option>, first_latency: bool, #[cfg(not(target_os = "android"))] device_name: Option, - #[cfg(target_os = "android")] device_fd: i32, use_channel_type: UseChannelType, packet_loss_rate: Option, packet_delay: u32, @@ -113,8 +110,6 @@ impl Config { first_latency, #[cfg(not(target_os = "android"))] device_name, - #[cfg(target_os = "android")] - device_fd, use_channel_type, packet_loss_rate, packet_delay, diff --git a/vnt/src/handle/callback.rs b/vnt/src/handle/callback.rs index aeac7d5..8e7219c 100644 --- a/vnt/src/handle/callback.rs +++ b/vnt/src/handle/callback.rs @@ -1,21 +1,25 @@ +use crate::handle::PeerDeviceStatus; #[cfg(feature = "server_encrypt")] use rsa::RsaPublicKey; use std::fmt::{Display, Formatter}; use std::io; use std::net::{Ipv4Addr, SocketAddr}; +#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))] #[derive(Debug)] pub struct DeviceInfo { pub name: String, pub version: String, } +#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))] impl Display for DeviceInfo { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { f.write_str(&format!("name={} ,version={}", self.name, self.version)) } } +#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))] impl DeviceInfo { pub fn new(name: String, version: String) -> Self { return Self { name, version }; @@ -68,6 +72,7 @@ impl Display for HandshakeInfo { f.write_str(&format!("server version={}", self.version)) } } + #[cfg(feature = "server_encrypt")] impl HandshakeInfo { pub fn new(public_key: RsaPublicKey, finger: String, version: String) -> Self { @@ -85,6 +90,7 @@ impl HandshakeInfo { } } } + #[cfg(not(feature = "server_encrypt"))] impl HandshakeInfo { pub fn new_no_secret(version: String) -> Self { @@ -183,11 +189,89 @@ impl Into for ErrorType { } } +#[cfg(target_os = "android")] +#[derive(Debug)] +pub struct DeviceConfig { + //本机虚拟IP + pub virtual_ip: Ipv4Addr, + //子网掩码 + pub virtual_netmask: Ipv4Addr, + //虚拟网关 + pub virtual_gateway: Ipv4Addr, + //虚拟网段 + pub virtual_network: Ipv4Addr, + // 额外的路由 + pub external_route: Vec<(Ipv4Addr, Ipv4Addr)>, +} + +#[cfg(target_os = "android")] +impl DeviceConfig { + pub fn new( + virtual_ip: Ipv4Addr, + virtual_netmask: Ipv4Addr, + virtual_gateway: Ipv4Addr, + virtual_network: Ipv4Addr, + external_route: Vec<(Ipv4Addr, Ipv4Addr)>, + ) -> Self { + Self { + virtual_ip, + virtual_netmask, + virtual_gateway, + virtual_network, + external_route, + } + } +} + +#[cfg(target_os = "android")] +impl Display for DeviceConfig { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + f.write_str(&format!( + "ip={} ,netmask={} ,gateway={}, external_route={:?}", + self.virtual_ip, self.virtual_netmask, self.virtual_gateway, self.external_route + )) + } +} + +#[derive(Debug)] +pub struct PeerClientInfo { + pub virtual_ip: Ipv4Addr, + pub name: String, + pub status: PeerDeviceStatus, + pub client_secret: bool, +} + +impl PeerClientInfo { + pub fn new( + virtual_ip: Ipv4Addr, + name: String, + status: PeerDeviceStatus, + client_secret: bool, + ) -> Self { + Self { + virtual_ip, + name, + status, + client_secret, + } + } +} + +impl Display for PeerClientInfo { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + f.write_str(&format!( + "ip={} ,name={} ,status={:?}, client_secret={}", + self.virtual_ip, self.name, self.status, self.client_secret + )) + } +} + pub trait VntCallback: Clone + Send + Sync + 'static { /// 启动成功 fn success(&self) {} /// 创建网卡的信息 + #[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))] fn create_tun(&self, _info: DeviceInfo) {} /// 连接 fn connect(&self, _info: ConnectInfo) {} @@ -199,6 +283,11 @@ pub trait VntCallback: Clone + Send + Sync + 'static { fn register(&self, _info: RegisterInfo) -> bool { true } + #[cfg(target_os = "android")] + fn generate_tun(&self, _info: DeviceConfig) -> u32 { + 0 + } + fn peer_client_list(&self, _info: Vec) {} /// 异常信息 fn error(&self, _info: ErrorInfo) {} /// 服务停止 diff --git a/vnt/src/handle/interface/adapter.rs b/vnt/src/handle/interface/adapter.rs new file mode 100644 index 0000000..1fee951 --- /dev/null +++ b/vnt/src/handle/interface/adapter.rs @@ -0,0 +1,216 @@ +use std::net::Ipv4Addr; +use std::{io, process, thread}; +use std::sync::Arc; +use std::sync::mpsc::{Receiver, SyncSender, TrySendError}; +use crossbeam_utils::atomic::AtomicCell; +use tun::Device; +use tun::device::IFace; +use crate::handle::callback::DeviceConfig; +use crate::protocol::NetPacket; +use crate::util::{BufBlock, BufPool, GroupSyncSender, StopManager}; + +pub struct TunAdapter { + #[cfg(any(target_os = "windows", target_os = "linux"))] is_tap: bool, + #[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))] device_name: Option, + #[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))] mtu: u32, + #[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))] route_record: Vec<(Ipv4Addr, Ipv4Addr)>, + device: Option>, + buf_pool: BufPool, + stop_manager: StopManager, + receiver_stage: Option>>, + sender_stage: Option>>, +} +impl TunAdapter { + pub fn new( + #[cfg(any(target_os = "windows", target_os = "linux"))] is_tap: bool, + #[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))] device_name: Option, + #[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))] mtu: u32, + #[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))] route_record: Vec<(Ipv4Addr, Ipv4Addr)>, + buf_pool: BufPool, + stop_manager: StopManager, + receiver: Receiver>, + sender: SyncSender>, + )->Self{ + Self{ + #[cfg(any(target_os = "windows", target_os = "linux"))] is_tap, + #[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))] device_name, + #[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))] mtu, + #[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))] route_record, + device: None, + buf_pool, + stop_manager, + receiver_stage: Some(receiver), + sender_stage: Some(sender), + } + } +} + +impl TunAdapter { + pub fn device(&mut self, #[cfg(target_os = "android")] device_fd: u32) -> io::Result<()> { + if self.device.is_some() { + return Ok(()); + } else { + let device = create_device(#[cfg(any(target_os = "windows", target_os = "linux"))] self.is_tap, + #[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))] self.device_name.clone(), + #[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))] self.mtu, + #[cfg(target_os = "android")] device_fd, )?; + let device = Arc::new(device); + self.device.replace(device); + { + let device = device.clone(); + let buf_pool = self.buf_pool.clone(); + let stop_manager = self.stop_manager.clone(); + let sender = self.sender_stage.take().unwrap(); + thread::Builder::new().name("tun-read".into()).spawn(move || { + loop { + let mut buf_block = buf_pool.alloc(); + #[cfg(not(target_os = "macos"))] + let start = 12; + #[cfg(target_os = "macos")] + let start = 8; + match device.read(&mut buf_block.as_mut()[start..]) { + Ok(len) => { + buf_block.as_mut()[..12].fill(0); + buf_block.set_data_len(start + len); + if let Err(e) = sender.try_send(buf_block) { + match e { + TrySendError::Full(_) => { + log::warn!("发生丢包"); + } + TrySendError::Disconnected(_) => { + break; + } + } + } + } + Err(e) => { + log::warn!("{:?}",e); + break; + } + } + } + stop_manager.stop(); + }).unwrap(); + } + { + let device = device.clone(); + let stop_manager = self.stop_manager.clone(); + let receiver = self.receiver_stage.take().unwrap(); + + thread::Builder::new().name("tun-write".into()).spawn(move || { + while let Ok(data) = receiver.recv() { + if let Err(e) = device.write(data.as_data()) { + log::warn!("写入网卡失败:{}",e); + break; + } + } + stop_manager.stop(); + }).unwrap(); + } + } + } + #[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))] + pub fn change_ip(&mut self, info: DeviceConfig) -> io::Result<()> { + let device = if let Some(device) = &self.device { + device + } else { + return Err(io::Error::new(io::ErrorKind::NotFound, "IFace")); + }; + device.set_ip(info.virtual_ip, info.virtual_netmask)?; + for (dest, mask) in self.route_record.drain(..) { + if let Err(e) = self.device.delete_route(dest, mask) { + log::warn!("删除路由失败 ={:?}", e); + } + } + if let Err(e) = device.add_route(info.virtual_network, info.virtual_netmask, 1) + { + log::warn!("添加默认路由失败 ={:?}", e); + } else { + self.route_record.push((info.virtual_network, info.virtual_netmask)); + } + if let Err(e) = device + .add_route(Ipv4Addr::BROADCAST, Ipv4Addr::BROADCAST, 1) + { + log::warn!("添加广播路由失败 ={:?}", e); + } else { + self.route_record.push((Ipv4Addr::BROADCAST, Ipv4Addr::BROADCAST)); + } + + if let Err(e) = device.add_route( + Ipv4Addr::from([224, 0, 0, 0]), + Ipv4Addr::from([240, 0, 0, 0]), + 1, + ) { + log::warn!("添加组播路由失败 ={:?}", e); + } else { + self.route_record.push(( + Ipv4Addr::from([224, 0, 0, 0]), + Ipv4Addr::from([240, 0, 0, 0]), + )); + } + + for (dest, mask) in info.external_route { + if let Err(e) = self.device.add_route(dest, mask, 1) { + log::warn!("添加路由失败 ={:?}", e); + } else { + self.route_record.push((dest, mask)); + } + } + Ok(()) + } +} + +#[cfg(any(target_os = "windows", target_os = "linux"))] +const DEFAULT_TUN_NAME: &str = "vnt-tun"; +#[cfg(any(target_os = "windows", target_os = "linux"))] +const DEFAULT_TAP_NAME: &str = "vnt-tap"; + +pub fn create_device(#[cfg(any(target_os = "windows", target_os = "linux"))] is_tap: bool, + #[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))] device_name: Option, + #[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))] mtu: u32, + #[cfg(target_os = "android")] device_fd: u32, ) -> io::Result { + #[cfg(any(target_os = "windows", target_os = "linux"))] + let default_name: &str = if is_tap { + DEFAULT_TAP_NAME + } else { + DEFAULT_TUN_NAME + }; + #[cfg(target_os = "linux")] + let device = { + let device_name = device_name + .unwrap_or(default_name.to_string()); + if &device_name == default_name { + delete_device(default_name); + } + Device::new(Some(device_name), is_tap)? + }; + #[cfg(target_os = "macos")] + let device = Device::new(device_name)?; + #[cfg(target_os = "windows")] + let device = Device::new( + device_name + .unwrap_or(default_name.to_string()), + is_tap, + )?; + #[cfg(target_os = "android")] + let device = Device::new(device_fd as _)?; + #[cfg(not(target_os = "android"))] + device.set_mtu(mtu)?; + Ok(device) +} + +#[cfg(target_os = "linux")] +fn delete_device(name: &str) { + // 删除默认网卡,此操作有风险,后续可能去除 + use std::process::Command; + let cmd = format!("ip link delete {}", name); + let delete_tun = Command::new("sh") + .arg("-c") + .arg(&cmd) + .output() + .expect("sh exec error!"); + if !delete_tun.status.success() { + log::info!("{},{:?}",cmd, delete_tun); + } +} + diff --git a/vnt/src/handle/interface/mod.rs b/vnt/src/handle/interface/mod.rs new file mode 100644 index 0000000..5355ceb --- /dev/null +++ b/vnt/src/handle/interface/mod.rs @@ -0,0 +1,242 @@ +use std::{io, thread}; +use std::net::Ipv4Addr; +use std::sync::Arc; +use std::sync::mpsc::Receiver; + +use crossbeam_utils::atomic::AtomicCell; +use parking_lot::Mutex; + +use packet::icmp::icmp::IcmpPacket; +use packet::icmp::Kind; +use packet::ip::ipv4; +use packet::ip::ipv4::packet::IpV4Packet; +use packet::ip::ipv4::protocol::Protocol; + +use crate::channel::context::Context; +use crate::cipher::Cipher; +use crate::external_route::ExternalRoute; +use crate::handle::{check_dest, CurrentDeviceInfo, PeerDeviceInfo}; +use crate::ip_proxy::{IpProxyMap, ProxyHandler}; +use crate::protocol; +use crate::protocol::{ip_turn_packet, MAX_TTL, NetPacket, Version}; +use crate::protocol::body::ENCRYPTION_RESERVED; +use crate::protocol::ip_turn_packet::BroadcastPacket; +use crate::util::{BufBlock, SingleU64Adder, StopManager}; +pub mod adapter; +pub fn start( + receivers: Vec>, + context: Context, + current_device: Arc>, + ip_route: ExternalRoute, + #[cfg(feature = "ip_proxy")] ip_proxy_map: Option, + client_cipher: Cipher, + server_cipher: Cipher, + device_list: Arc)>>, +) -> io::Result<()> { + for (index,receiver) in receivers.into_iter().enumerate() { + let context = context.clone(); + let current_device = current_device.clone(); + let ip_route = ip_route.clone(); + #[cfg(feature = "ip_proxy")] + let ip_proxy_map = ip_proxy_map.clone(); + let client_cipher = client_cipher.clone(); + let server_cipher = server_cipher.clone(); + let device_list = device_list.clone(); + thread::Builder::new() + .name(format!("IFace-{}", index)) + .spawn(move || { + while let Ok(mut data) = receiver.recv() { + let data_len = data.data_len(); + let buf = data.as_start_mut(); + if data_len==0{ + break; + } + match handle( + &context, + buf, + data_len, + current_device.load(), + &ip_route, + #[cfg(feature = "ip_proxy")] + &ip_proxy_map, + &client_cipher, + &server_cipher, + &device_list, + ) { + Ok(_) => {} + Err(e) => { + log::warn!("{:?}", e) + } + } + } + })?; + } + Ok(()) +} + + +/// 实现一个原地发送,必须保证是如下结构 +/// |12字节开头|ip报文|至少1024字节结尾| +/// +pub fn handle( + context: &Context, + buf: &mut [u8], + data_len: usize, //数据总长度=12+ip包长度 + current_device: CurrentDeviceInfo, + ip_route: &ExternalRoute, + #[cfg(feature = "ip_proxy")] proxy_map: &Option, + client_cipher: &Cipher, + server_cipher: &Cipher, + device_list: &Mutex<(u16, Vec)>, +) -> io::Result<()> { + let ipv4_packet = IpV4Packet::new(&buf[12..data_len])?; + let protocol = ipv4_packet.protocol(); + let src_ip = ipv4_packet.source_ip(); + let mut dest_ip = ipv4_packet.destination_ip(); + let mut net_packet = NetPacket::new0(data_len, buf)?; + net_packet.set_version(Version::V1); + net_packet.set_protocol(protocol::Protocol::IpTurn); + net_packet.set_transport_protocol(ip_turn_packet::Protocol::Ipv4.into()); + net_packet.first_set_ttl(6); + net_packet.set_source(src_ip); + net_packet.set_destination(dest_ip); + if dest_ip == current_device.virtual_gateway { + // 发到网关的加密方式不一样,要单独处理 + if protocol == Protocol::Icmp { + net_packet.set_gateway_flag(true); + server_cipher.encrypt_ipv4(&mut net_packet)?; + context.send_default(net_packet.buffer(), current_device.connect_server)?; + } + return Ok(()); + } + if dest_ip.is_multicast() { + //当作广播处理 + dest_ip = Ipv4Addr::BROADCAST; + net_packet.set_destination(Ipv4Addr::BROADCAST); + } + if dest_ip.is_broadcast() || current_device.broadcast_ip == dest_ip { + // 广播 发送到直连目标 + client_cipher.encrypt_ipv4(&mut net_packet)?; + broadcast( + server_cipher, + context, + &mut net_packet, + ¤t_device, + device_list, + )?; + return Ok(()); + } + if !check_dest( + dest_ip, + current_device.virtual_netmask, + current_device.virtual_network, + ) { + if let Some(r_dest_ip) = ip_route.route(&dest_ip) { + //路由的目标不能是自己 + if r_dest_ip == src_ip { + return Ok(()); + } + //需要修改目的地址 + dest_ip = r_dest_ip; + net_packet.set_destination(r_dest_ip); + } else { + return Ok(()); + } + } + #[cfg(feature = "ip_proxy")] + if let Some(proxy_map) = proxy_map { + let mut ipv4_packet = IpV4Packet::new(net_packet.payload_mut())?; + proxy_map.send_handle(&mut ipv4_packet)?; + } + client_cipher.encrypt_ipv4(&mut net_packet)?; + context.send_ipv4_by_id( + net_packet.buffer(), + &dest_ip, + current_device.connect_server, + current_device.status.online(), + ) +} + +fn broadcast( + server_cipher: &Cipher, + sender: &Context, + net_packet: &mut NetPacket<&mut [u8]>, + current_device: &CurrentDeviceInfo, + device_list: &Mutex<(u16, Vec)>, +) -> io::Result<()> { + let list: Vec = device_list + .lock() + .1 + .iter() + .filter(|info| info.status.is_online()) + .map(|info| info.virtual_ip) + .collect(); + const MAX_COUNT: usize = 8; + let mut p2p_ips = Vec::with_capacity(8); + let mut relay_ips = Vec::with_capacity(8); + let mut overflow = false; + for (index, peer_ip) in list.into_iter().enumerate() { + if index > MAX_COUNT { + overflow = true; + break; + } + if let Some(route) = sender.route_table.route_one_p2p(&peer_ip) { + if sender + .send_by_key(net_packet.buffer(), route.route_key()) + .is_ok() + { + p2p_ips.push(peer_ip); + continue; + } + } + relay_ips.push(peer_ip); + } + if !overflow && relay_ips.is_empty() { + //全部p2p,不需要服务器中转 + return Ok(()); + } + + if p2p_ips.is_empty() { + //都没有p2p则直接由服务器转发 + if current_device.status.online() { + sender.send_default(net_packet.buffer(), current_device.connect_server)?; + } + return Ok(()); + } + if !overflow && relay_ips.len() == 2 { + // 如果转发的ip数不多就直接发 + for peer_ip in relay_ips { + //非直连的广播要改变目的地址,不然服务端收到了会再次广播 + net_packet.set_destination(peer_ip); + sender.send_ipv4_by_id( + net_packet.buffer(), + &peer_ip, + current_device.connect_server, + current_device.status.online(), + )?; + } + return Ok(()); + } + if current_device.status.offline() { + //离线的不再转发 + return Ok(()); + } + let buf = vec![0u8; 12 + 1 + p2p_ips.len() * 4 + net_packet.data_len() + ENCRYPTION_RESERVED]; + //剩余的发送到服务端,需要告知哪些已发送过 + let mut server_packet = NetPacket::new_encrypt(buf)?; + server_packet.set_version(Version::V1); + server_packet.set_gateway_flag(true); + server_packet.first_set_ttl(MAX_TTL); + server_packet.set_source(net_packet.source()); + //使用对应的目的地址 + server_packet.set_destination(net_packet.destination()); + server_packet.set_protocol(protocol::Protocol::IpTurn); + server_packet.set_transport_protocol(ip_turn_packet::Protocol::Ipv4Broadcast.into()); + + let mut broadcast = BroadcastPacket::unchecked(server_packet.payload_mut()); + broadcast.set_address(&p2p_ips)?; + broadcast.set_data(net_packet.buffer())?; + server_cipher.encrypt_ipv4(&mut server_packet)?; + sender.send_default(server_packet.buffer(), current_device.connect_server) +} + diff --git a/vnt/src/handle/recv_data/client.rs b/vnt/src/handle/recv_data/client.rs index 314e02f..06e09b7 100644 --- a/vnt/src/handle/recv_data/client.rs +++ b/vnt/src/handle/recv_data/client.rs @@ -1,16 +1,13 @@ +use parking_lot::RwLock; +use protobuf::Message; use std::collections::HashMap; use std::io; use std::net::{Ipv4Addr, Ipv6Addr}; use std::sync::Arc; -use parking_lot::RwLock; -use protobuf::Message; - use packet::icmp::{icmp, Kind}; use packet::ip::ipv4; use packet::ip::ipv4::packet::IpV4Packet; -use tun::device::IFace; -use tun::Device; use crate::channel::context::Context; use crate::channel::punch::NatInfo; @@ -29,11 +26,13 @@ use crate::protocol::control_packet::ControlPacket; use crate::protocol::{ control_packet, ip_turn_packet, other_turn_packet, NetPacket, Protocol, Version, MAX_TTL, }; - +use crate::tun_tap_device::tun_create_helper::DeviceAdapter; +#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))] +use tun::device::IFace; /// 处理来源于客户端的包 #[derive(Clone)] pub struct ClientPacketHandler { - device: Arc, + device: DeviceAdapter, client_cipher: Cipher, punch_sender: PunchSender, peer_nat_info_map: Arc>>, @@ -45,7 +44,7 @@ pub struct ClientPacketHandler { impl ClientPacketHandler { pub fn new( - device: Arc, + device: DeviceAdapter, client_cipher: Cipher, punch_sender: PunchSender, peer_nat_info_map: Arc>>, diff --git a/vnt/src/handle/recv_data/mod.rs b/vnt/src/handle/recv_data/mod.rs index a4fcd85..d02997c 100644 --- a/vnt/src/handle/recv_data/mod.rs +++ b/vnt/src/handle/recv_data/mod.rs @@ -6,8 +6,6 @@ use std::{io, thread}; use crossbeam_utils::atomic::AtomicCell; use parking_lot::{Mutex, RwLock}; -use tun::Device; - use crate::channel::context::Context; use crate::channel::handler::RecvChannelHandler; use crate::channel::punch::NatInfo; @@ -27,6 +25,7 @@ use crate::handle::{BaseConfigInfo, CurrentDeviceInfo, PeerDeviceInfo, SELF_IP}; use crate::ip_proxy::IpProxyMap; use crate::nat::NatTest; use crate::protocol::NetPacket; +use crate::tun_tap_device::tun_create_helper::DeviceAdapter; use crate::util::U64Adder; mod client; @@ -56,7 +55,7 @@ impl RecvDataHandler { server_cipher: Cipher, client_cipher: Cipher, current_device: Arc>, - device: Arc, + device: DeviceAdapter, device_list: Arc)>>, config_info: BaseConfigInfo, nat_test: NatTest, diff --git a/vnt/src/handle/recv_data/server.rs b/vnt/src/handle/recv_data/server.rs index 379cd8b..77bb122 100644 --- a/vnt/src/handle/recv_data/server.rs +++ b/vnt/src/handle/recv_data/server.rs @@ -11,8 +11,6 @@ use protobuf::Message; use packet::icmp::{icmp, Kind}; use packet::ip::ipv4; use packet::ip::ipv4::packet::IpV4Packet; -use tun::device::IFace; -use tun::Device; use crate::channel::context::Context; use crate::channel::{Route, RouteKey}; @@ -29,12 +27,15 @@ use crate::handle::{ registrar, BaseConfigInfo, ConnectStatus, CurrentDeviceInfo, PeerDeviceInfo, GATEWAY_IP, }; use crate::nat::NatTest; -use crate::proto; use crate::proto::message::{DeviceList, HandshakeResponse, RegistrationResponse}; use crate::protocol::body::ENCRYPTION_RESERVED; use crate::protocol::control_packet::ControlPacket; use crate::protocol::error_packet::InErrorPacket; use crate::protocol::{ip_turn_packet, service_packet, NetPacket, Protocol, Version, MAX_TTL}; +use crate::tun_tap_device::tun_create_helper::DeviceAdapter; +use crate::{proto, PeerClientInfo}; +#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))] +use tun::device::IFace; /// 处理来源于服务端的包 #[derive(Clone)] @@ -43,13 +44,14 @@ pub struct ServerPacketHandler { rsa_cipher: Arc>>, server_cipher: Cipher, current_device: Arc>, - device: Arc, + device: DeviceAdapter, device_list: Arc)>>, config_info: BaseConfigInfo, nat_test: NatTest, callback: Call, #[cfg(feature = "server_encrypt")] up_key_time: Arc>, + #[cfg(not(target_os = "android"))] route_record: Arc>>, external_route: ExternalRoute, handshake: Handshake, @@ -60,7 +62,7 @@ impl ServerPacketHandler { #[cfg(feature = "server_encrypt")] rsa_cipher: Arc>>, server_cipher: Cipher, current_device: Arc>, - device: Arc, + device: DeviceAdapter, device_list: Arc)>>, config_info: BaseConfigInfo, nat_test: NatTest, @@ -80,6 +82,7 @@ impl ServerPacketHandler { callback, #[cfg(feature = "server_encrypt")] up_key_time: Arc::new(AtomicCell::new(Instant::now() - Duration::from_secs(60))), + #[cfg(not(target_os = "android"))] route_record: Arc::new(Mutex::default()), external_route, handshake, @@ -299,6 +302,31 @@ impl ServerPacketHandler { if old.virtual_ip != Ipv4Addr::UNSPECIFIED { log::info!("ip发生变化,old:{:?},response={:?}", old, response); } + #[cfg(target_os = "android")] + { + let device_config = crate::handle::callback::DeviceConfig::new( + virtual_ip, + virtual_netmask, + virtual_gateway, + virtual_network, + self.external_route.to_route(), + ); + let device_fd = self.callback.generate_tun(device_config); + if device_fd == 0 { + self.callback.error(ErrorInfo::new_msg( + ErrorType::Unknown, + "device_fd == 0".into(), + )); + } else { + let device = Arc::new(tun::Device::new(device_fd as _)?); + if let Err(e) = self.device.start(device) { + self.callback.error(ErrorInfo::new_msg( + ErrorType::Unknown, + format!("{:?}", e), + )); + } + } + } #[cfg(not(target_os = "android"))] { if let Err(e) = self.device.set_ip(virtual_ip, virtual_netmask) { @@ -393,10 +421,18 @@ impl ServerPacketHandler { ) }) .collect(); - let mut dev = self.device_list.lock(); - //这里可能会收到旧的消息,但是随着时间推移总会收到新的 - dev.0 = epoch; - dev.1 = ip_list; + { + let mut dev = self.device_list.lock(); + //这里可能会收到旧的消息,但是随着时间推移总会收到新的 + dev.0 = epoch; + dev.1 = ip_list.clone(); + } + self.callback.peer_client_list( + ip_list + .into_iter() + .map(|v| PeerClientInfo::new(v.virtual_ip, v.name, v.status, v.client_secret)) + .collect(), + ); } fn register(&self, current_device: &CurrentDeviceInfo, context: &Context) -> io::Result<()> { if current_device.status.online() { diff --git a/vnt/src/handle/tun_tap/tun_handler.rs b/vnt/src/handle/tun_tap/tun_handler.rs index 2803915..83da150 100644 --- a/vnt/src/handle/tun_tap/tun_handler.rs +++ b/vnt/src/handle/tun_tap/tun_handler.rs @@ -87,14 +87,14 @@ pub fn start( device_list: Arc)>>, ) -> io::Result<()> { let worker = { - #[cfg(target_os = "macos")] + #[cfg(any(target_os = "macos", target_os = "android"))] let current_device = current_device.clone(); let device = device.clone(); stop_manager.add_listener("tun_device".into(), move || { if let Err(e) = device.shutdown() { log::warn!("{:?}", e); } - #[cfg(target_os = "macos")] + #[cfg(any(target_os = "macos", target_os = "android"))] { let ip = current_device.load().virtual_ip; if let Ok(udp) = std::net::UdpSocket::bind("0.0.0.0:0") { diff --git a/vnt/src/lib.rs b/vnt/src/lib.rs index 65d4a95..92ae669 100644 --- a/vnt/src/lib.rs +++ b/vnt/src/lib.rs @@ -13,4 +13,4 @@ pub mod protocol; pub mod tun_tap_device; pub mod util; -pub use handle::callback::{DeviceInfo, ErrorInfo, HandshakeInfo, RegisterInfo, VntCallback}; +pub use handle::callback::*; diff --git a/vnt/src/tun_tap_device/create_device.rs b/vnt/src/tun_tap_device/create_device.rs new file mode 100644 index 0000000..30a904f --- /dev/null +++ b/vnt/src/tun_tap_device/create_device.rs @@ -0,0 +1,64 @@ +use std::io; +use std::sync::Arc; +use tun::device::IFace; +use tun::Device; + +#[cfg(any(target_os = "windows", target_os = "linux"))] +const DEFAULT_TUN_NAME: &str = "vnt-tun"; +#[cfg(any(target_os = "windows", target_os = "linux"))] +const DEFAULT_TAP_NAME: &str = "vnt-tap"; + +#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))] +pub fn create_device(config: &crate::core::Config) -> io::Result> { + #[cfg(any(target_os = "windows", target_os = "linux"))] + let default_name: &str = if config.tap { + DEFAULT_TAP_NAME + } else { + DEFAULT_TUN_NAME + }; + #[cfg(target_os = "linux")] + let device = { + let device_name = config + .device_name + .clone() + .unwrap_or(default_name.to_string()); + if &device_name == default_name { + delete_device(default_name); + } + Arc::new(Device::new(Some(device_name), config.tap)?) + }; + #[cfg(target_os = "macos")] + let device = Arc::new(Device::new(config.device_name.clone())?); + #[cfg(target_os = "windows")] + let device = Arc::new(Device::new( + config + .device_name + .clone() + .unwrap_or(default_name.to_string()), + config.tap, + )?); + let mtu = config.mtu.unwrap_or_else(|| { + if config.password.is_none() { + 1450 + } else { + 1410 + } + }); + device.set_mtu(mtu)?; + Ok(device) +} + +#[cfg(target_os = "linux")] +fn delete_device(name: &str) { + // 删除默认网卡,此操作有风险,后续可能去除 + use std::process::Command; + let cmd = format!("ip link delete {}", name); + let delete_tun = Command::new("sh") + .arg("-c") + .arg(&cmd) + .output() + .expect("sh exec error!"); + if !delete_tun.status.success() { + log::warn!("删除网卡失败:{:?}", delete_tun); + } +} diff --git a/vnt/src/tun_tap_device/mod.rs b/vnt/src/tun_tap_device/mod.rs index e950563..f5037c8 100644 --- a/vnt/src/tun_tap_device/mod.rs +++ b/vnt/src/tun_tap_device/mod.rs @@ -1,70 +1,6 @@ -use std::io; -use std::sync::Arc; +#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))] +pub use create_device::create_device; -use tun::device::IFace; -use tun::Device; - -use crate::core::Config; -#[cfg(any(target_os = "windows", target_os = "linux"))] -const DEFAULT_TUN_NAME: &str = "vnt-tun"; -#[cfg(any(target_os = "windows", target_os = "linux"))] -const DEFAULT_TAP_NAME: &str = "vnt-tap"; - -pub fn create_device(config: &Config) -> io::Result> { - #[cfg(any(target_os = "windows", target_os = "linux"))] - let default_name: &str = if config.tap { - DEFAULT_TAP_NAME - } else { - DEFAULT_TUN_NAME - }; - #[cfg(target_os = "linux")] - let device = { - let device_name = config - .device_name - .clone() - .unwrap_or(default_name.to_string()); - if &device_name == default_name { - delete_device(default_name); - } - Arc::new(Device::new(Some(device_name), config.tap)?) - }; - #[cfg(target_os = "macos")] - let device = Arc::new(Device::new(config.device_name.clone())?); - #[cfg(target_os = "windows")] - let device = Arc::new(Device::new( - config - .device_name - .clone() - .unwrap_or(default_name.to_string()), - config.tap, - )?); - #[cfg(target_os = "android")] - let device = Arc::new(Device::new(config.device_fd as _)?); - #[cfg(not(target_os = "android"))] - { - let mtu = config.mtu.unwrap_or_else(|| { - if config.password.is_none() { - 1450 - } else { - 1410 - } - }); - device.set_mtu(mtu)?; - } - Ok(device) -} - -#[cfg(target_os = "linux")] -fn delete_device(name: &str) { - // 删除默认网卡,此操作有风险,后续可能去除 - use std::process::Command; - let cmd = format!("ip link delete {}", name); - let delete_tun = Command::new("sh") - .arg("-c") - .arg(&cmd) - .output() - .expect("sh exec error!"); - if !delete_tun.status.success() { - log::warn!("删除网卡失败:{:?}", delete_tun); - } -} +#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))] +mod create_device; +pub mod tun_create_helper; diff --git a/vnt/src/tun_tap_device/tun_create_helper.rs b/vnt/src/tun_tap_device/tun_create_helper.rs new file mode 100644 index 0000000..c5ecc45 --- /dev/null +++ b/vnt/src/tun_tap_device/tun_create_helper.rs @@ -0,0 +1,134 @@ +use std::io; +use std::sync::Arc; + +use crossbeam_utils::atomic::AtomicCell; +use parking_lot::Mutex; + +use tun::Device; + +use crate::channel::context::Context; +use crate::cipher::Cipher; +use crate::external_route::ExternalRoute; +use crate::handle::{CurrentDeviceInfo, PeerDeviceInfo}; +use crate::ip_proxy::IpProxyMap; +use crate::util::{SingleU64Adder, StopManager}; +#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))] +#[repr(transparent)] +#[derive(Clone)] +pub struct DeviceAdapter { + tun: Arc, +} +impl DeviceAdapter { + #[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))] + pub fn new(tun: Arc) -> Self { + Self { tun } + } + #[cfg(target_os = "android")] + pub fn new(tun_device_helper: TunDeviceHelper) -> Self { + Self { + tun: Arc::new(Mutex::new(None)), + tun_device_helper, + } + } +} +#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))] +impl std::ops::Deref for DeviceAdapter { + type Target = Arc; + + fn deref(&self) -> &Self::Target { + &self.tun + } +} + +#[cfg(target_os = "android")] +#[derive(Clone)] +pub struct DeviceAdapter { + tun: Arc>>>, + tun_device_helper: TunDeviceHelper, +} +#[cfg(target_os = "android")] +impl DeviceAdapter { + pub fn write(&self, buf: &[u8]) -> io::Result { + if let Some(device) = self.tun.lock().as_ref() { + use tun::device::IFace; + device.write(buf) + } else { + Err(io::Error::new(io::ErrorKind::Other, "not tun device")) + } + } + pub fn start(&self, device: Arc) -> io::Result<()> { + self.tun_device_helper.start(device.clone())?; + self.tun.lock().replace(device); + Ok(()) + } +} + +#[derive(Clone)] +pub struct TunDeviceHelper { + inner: Arc>>, +} + +struct TunDeviceHelperInner { + stop_manager: StopManager, + context: Context, + current_device: Arc>, + ip_route: ExternalRoute, + #[cfg(feature = "ip_proxy")] + ip_proxy_map: Option, + client_cipher: Cipher, + server_cipher: Cipher, + parallel: usize, + up_counter: SingleU64Adder, + device_list: Arc)>>, +} + +impl TunDeviceHelper { + pub fn new( + stop_manager: StopManager, + context: Context, + current_device: Arc>, + ip_route: ExternalRoute, + #[cfg(feature = "ip_proxy")] ip_proxy_map: Option, + client_cipher: Cipher, + server_cipher: Cipher, + parallel: usize, + up_counter: SingleU64Adder, + device_list: Arc)>>, + ) -> Self { + Self { + inner: Arc::new(AtomicCell::new(Some(TunDeviceHelperInner { + stop_manager, + context, + current_device, + ip_route, + ip_proxy_map, + client_cipher, + server_cipher, + parallel, + up_counter, + device_list, + }))), + } + } + pub fn start(&self, device: Arc) -> io::Result<()> { + if let Some(inner) = self.inner.take() { + crate::handle::tun_tap::tun_handler::start( + inner.stop_manager, + inner.context, + device, + inner.current_device, + inner.ip_route, + #[cfg(feature = "ip_proxy")] + inner.ip_proxy_map, + inner.client_cipher, + inner.server_cipher, + inner.parallel, + inner.up_counter, + inner.device_list, + )?; + Ok(()) + } else { + Err(io::Error::new(io::ErrorKind::Other, "Repeated start")) + } + } +}