Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4f52d58d6e | ||
|
|
441e374563 | ||
|
|
3272f3cdca | ||
|
|
5b40a9f147 | ||
|
|
12d4fc8e98 | ||
|
|
ca74827aaf | ||
|
|
0b570130e8 | ||
|
|
5bdc514606 | ||
|
|
137efe20b8 | ||
|
|
0cbc3e0f63 | ||
|
|
7fbcf0a832 | ||
|
|
7283863fe8 | ||
|
|
198f82fb2c | ||
|
|
c219af4f4b | ||
|
|
0352982c14 | ||
|
|
cc6cd6dc37 | ||
|
|
9155471c26 | ||
|
|
d916fd7573 | ||
|
|
5528557964 | ||
|
|
8dfc3b8c43 | ||
|
|
84824731a7 | ||
|
|
7131937d06 | ||
|
|
a657eae599 | ||
|
|
e9ec6e8903 |
@@ -68,10 +68,10 @@ pub fn out_ips_parse(ips: &Vec<String>) -> Result<Vec<(u32, u32)>, String> {
|
||||
|
||||
pub fn to_ip(mask: &str) -> Result<u32, String> {
|
||||
if let Ok(m) = mask.parse::<u32>() {
|
||||
if m >= 32 {
|
||||
if m > 32 {
|
||||
return Err("not netmask".to_string());
|
||||
}
|
||||
let mut mask = 0 as u32;
|
||||
let mut mask = 0u32;
|
||||
for i in 0..m {
|
||||
mask = mask | (1 << (31 - i));
|
||||
}
|
||||
|
||||
@@ -121,6 +121,8 @@ first_latency: false #是否优先低延迟通道,默认为false,表示优
|
||||
device_name: vnt-tun #网卡名称
|
||||
packet_loss: 0 #指定丢包率 取值0~1之间的数 用于模拟弱网
|
||||
packet_delay: 0 #指定延迟 单位毫秒 用于模拟弱网
|
||||
dns:
|
||||
- 8.8.8.8:53
|
||||
```
|
||||
|
||||
或者需要哪个配置就加哪个,当然token是必须的
|
||||
|
||||
@@ -36,5 +36,7 @@ pub struct DeviceItem {
|
||||
pub rt: String,
|
||||
pub status: String,
|
||||
pub client_secret: bool,
|
||||
pub client_secret_hash: Vec<u8>,
|
||||
pub current_client_secret: bool,
|
||||
pub current_client_secret_hash: Vec<u8>,
|
||||
}
|
||||
|
||||
@@ -85,6 +85,7 @@ pub fn command_list(vnt: &Vnt) -> Vec<DeviceItem> {
|
||||
let device_list = vnt.device_list();
|
||||
let mut list = Vec::new();
|
||||
let current_client_secret = vnt.client_encrypt();
|
||||
let client_encrypt_hash = vnt.client_encrypt_hash().unwrap_or(&[]);
|
||||
for peer in device_list {
|
||||
let name = peer.name;
|
||||
let virtual_ip = peer.virtual_ip.to_string();
|
||||
@@ -153,7 +154,9 @@ pub fn command_list(vnt: &Vnt) -> Vec<DeviceItem> {
|
||||
rt,
|
||||
status,
|
||||
client_secret,
|
||||
client_secret_hash: peer.client_secret_hash,
|
||||
current_client_secret,
|
||||
current_client_secret_hash: client_encrypt_hash.to_vec(),
|
||||
};
|
||||
list.push(item);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use std::io;
|
||||
use std::net::{Ipv4Addr, ToSocketAddrs};
|
||||
use std::net::Ipv4Addr;
|
||||
use std::str::FromStr;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
@@ -19,6 +19,7 @@ pub struct FileConfig {
|
||||
pub name: String,
|
||||
pub server_address: String,
|
||||
pub stun_server: Vec<String>,
|
||||
pub dns: Vec<String>,
|
||||
pub in_ips: Vec<String>,
|
||||
pub out_ips: Vec<String>,
|
||||
pub password: Option<String>,
|
||||
@@ -55,6 +56,7 @@ impl Default for FileConfig {
|
||||
"stun2.l.google.com:19302".to_string(),
|
||||
"stun.qq.com:3478".to_string(),
|
||||
],
|
||||
dns: vec![],
|
||||
in_ips: vec![],
|
||||
out_ips: vec![],
|
||||
password: None,
|
||||
@@ -91,24 +93,7 @@ pub fn read_config(file_path: &str) -> io::Result<(Config, bool)> {
|
||||
if file_conf.token.is_empty() {
|
||||
return Err(io::Error::new(io::ErrorKind::Other, "token is_empty"));
|
||||
}
|
||||
let server_address = match file_conf.server_address.to_socket_addrs() {
|
||||
Ok(mut addr) => {
|
||||
if let Some(addr) = addr.next() {
|
||||
addr
|
||||
} else {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
format!("server_address {:?} error", &file_conf.server_address),
|
||||
));
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
format!("server_address {:?} error:{}", &file_conf.server_address, e),
|
||||
));
|
||||
}
|
||||
};
|
||||
|
||||
let in_ips = match common::args_parse::ips_parse(&file_conf.in_ips) {
|
||||
Ok(in_ips) => in_ips,
|
||||
Err(e) => {
|
||||
@@ -150,8 +135,8 @@ pub fn read_config(file_path: &str) -> io::Result<(Config, bool)> {
|
||||
file_conf.token,
|
||||
file_conf.device_id,
|
||||
file_conf.name,
|
||||
server_address,
|
||||
file_conf.server_address,
|
||||
file_conf.dns,
|
||||
file_conf.stun_server,
|
||||
in_ips,
|
||||
out_ips,
|
||||
|
||||
@@ -21,6 +21,7 @@ pub fn console_info(status: Info) {
|
||||
println!("Up: {}", style(convert(status.up)).green());
|
||||
println!("Down: {}", style(convert(status.down)).green());
|
||||
}
|
||||
|
||||
fn convert(num: u64) -> String {
|
||||
let gigabytes = num / (1024 * 1024 * 1024);
|
||||
let remaining_bytes = num % (1024 * 1024 * 1024);
|
||||
@@ -90,13 +91,17 @@ pub fn console_device_list(mut list: Vec<DeviceItem>) {
|
||||
]);
|
||||
for item in list {
|
||||
if &item.status == "Online" {
|
||||
if item.client_secret != item.current_client_secret {
|
||||
if item.client_secret != item.current_client_secret
|
||||
|| (!item.current_client_secret_hash.is_empty()
|
||||
&& !item.client_secret_hash.is_empty()
|
||||
&& item.current_client_secret_hash != item.client_secret_hash)
|
||||
{
|
||||
//加密状态不一致,无法通信的
|
||||
out_list.push(vec![
|
||||
(item.name, Style::new().red()),
|
||||
(item.virtual_ip, Style::new().red()),
|
||||
(item.status, Style::new().red()),
|
||||
("".to_string(), Style::new().red()),
|
||||
("Mismatch".to_string(), Style::new().red()),
|
||||
("".to_string(), Style::new().red()),
|
||||
]);
|
||||
} else {
|
||||
|
||||
+7
-18
@@ -1,4 +1,4 @@
|
||||
use std::net::{Ipv4Addr, ToSocketAddrs};
|
||||
use std::net::Ipv4Addr;
|
||||
use std::path::PathBuf;
|
||||
use std::str::FromStr;
|
||||
use std::{io, thread};
|
||||
@@ -72,6 +72,7 @@ fn main() {
|
||||
opts.optopt("", "use-channel", "使用通道 relay/p2p", "<use-channel>");
|
||||
opts.optopt("", "packet-loss", "丢包率", "<packet-loss>");
|
||||
opts.optopt("", "packet-delay", "延迟", "<packet-delay>");
|
||||
opts.optmulti("", "dns", "dns", "<dns>");
|
||||
opts.optopt("f", "", "配置文件", "<conf>");
|
||||
//"后台运行时,查看其他设备列表"
|
||||
opts.optflag("", "list", "后台运行时,查看其他设备列表");
|
||||
@@ -150,27 +151,14 @@ fn main() {
|
||||
let server_address_str = matches
|
||||
.opt_get_default("s", "nat1.wherewego.top:29872".to_string())
|
||||
.unwrap();
|
||||
let server_address = match server_address_str.to_socket_addrs() {
|
||||
Ok(mut addr) => {
|
||||
if let Some(addr) = addr.next() {
|
||||
addr
|
||||
} else {
|
||||
println!("parameter '-s {}' error .", server_address_str);
|
||||
return;
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
println!("parameter '-s {}' error {}.", server_address_str, e);
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
let mut stun_server = matches.opt_strs("e");
|
||||
if stun_server.is_empty() {
|
||||
stun_server.push("stun1.l.google.com:19302".to_string());
|
||||
stun_server.push("stun2.l.google.com:19302".to_string());
|
||||
stun_server.push("stun.qq.com:3478".to_string());
|
||||
}
|
||||
|
||||
let dns = matches.opt_strs("dns");
|
||||
let in_ip = matches.opt_strs("i");
|
||||
let in_ip = match ips_parse(&in_ip) {
|
||||
Ok(in_ip) => in_ip,
|
||||
@@ -305,8 +293,8 @@ fn main() {
|
||||
token,
|
||||
device_id,
|
||||
name,
|
||||
server_address,
|
||||
server_address_str,
|
||||
dns,
|
||||
stun_server,
|
||||
in_ip,
|
||||
out_ip,
|
||||
@@ -423,7 +411,7 @@ fn print_usage(program: &str, _opts: Options) {
|
||||
);
|
||||
println!(" -n <name> 给设备一个名字,便于区分不同设备,默认使用系统版本");
|
||||
println!(" -d <id> 设备唯一标识符,不使用--ip参数时,服务端凭此参数分配虚拟ip,注意不能重复");
|
||||
println!(" -s <server> 注册和中继服务器地址");
|
||||
println!(" -s <server> 注册和中继服务器地址,以'TXT:'开头表示解析TXT记录");
|
||||
println!(" -e <stun-server> stun服务器,用于探测NAT类型,可多次指定,如-e addr1 -e addr2");
|
||||
println!(" -a 使用tap模式,默认使用tun模式");
|
||||
println!(" -i <in-ip> 配置点对网(IP代理)时使用,-i 192.168.0.0/24,10.26.0.3表示允许接收网段192.168.0.0/24的数据");
|
||||
@@ -486,6 +474,7 @@ fn print_usage(program: &str, _opts: Options) {
|
||||
println!(
|
||||
" --packet-delay <0> 模拟延迟,整数,单位毫秒(ms),程序会按设定的值延迟发包,可用于模拟弱网"
|
||||
);
|
||||
println!(" --dns <host:port> DNS服务器地址,可使用多个dns,默认使用114.114.114.114和8.8.8.8");
|
||||
|
||||
println!();
|
||||
println!(
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
/**
|
||||
* 异常回调
|
||||
*
|
||||
|
||||
@@ -50,6 +50,10 @@ public class Config {
|
||||
* 服务端地址
|
||||
*/
|
||||
private String server;
|
||||
/**
|
||||
* dns地址
|
||||
*/
|
||||
private String[] dns;
|
||||
/**
|
||||
* stun服务地址
|
||||
*/
|
||||
@@ -86,10 +90,6 @@ public class Config {
|
||||
* 虚拟网卡名称 仅在linux、windows、macos上支持
|
||||
*/
|
||||
private String deviceName;
|
||||
/**
|
||||
* 虚拟网卡fd 仅在android上支持
|
||||
*/
|
||||
private int deviceFd;
|
||||
/**
|
||||
* enum: relay/p2p/all
|
||||
*/
|
||||
@@ -194,6 +194,14 @@ public class Config {
|
||||
this.server = server;
|
||||
}
|
||||
|
||||
public String[] getDns() {
|
||||
return dns;
|
||||
}
|
||||
|
||||
public void setDns(String[] dns) {
|
||||
this.dns = dns;
|
||||
}
|
||||
|
||||
public String[] getStunServer() {
|
||||
return stunServer;
|
||||
}
|
||||
@@ -266,14 +274,6 @@ public class Config {
|
||||
this.deviceName = deviceName;
|
||||
}
|
||||
|
||||
public int getDeviceFd() {
|
||||
return deviceFd;
|
||||
}
|
||||
|
||||
public void setDeviceFd(int deviceFd) {
|
||||
this.deviceFd = deviceFd;
|
||||
}
|
||||
|
||||
public String getUseChannel() {
|
||||
return useChannel;
|
||||
}
|
||||
|
||||
@@ -6,6 +6,12 @@ package top.wherewego.vnt.jni;
|
||||
* @author https://github.com/lbl8603/vnt
|
||||
*/
|
||||
public class IpUtils {
|
||||
/**
|
||||
* 将整数的ip地址转成字符串,例如 0 转成 "0.0.0.0"
|
||||
*
|
||||
* @param ipAddress
|
||||
* @return
|
||||
*/
|
||||
public static String intToIpAddress(int ipAddress) {
|
||||
|
||||
return ((ipAddress & 0xFF000000) >>> 24) + "." +
|
||||
@@ -13,6 +19,13 @@ public class IpUtils {
|
||||
((ipAddress & 0x0000FF00) >>> 8) + "." +
|
||||
(ipAddress & 0x000000FF);
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回掩码的长度
|
||||
*
|
||||
* @param subnetMask
|
||||
* @return
|
||||
*/
|
||||
public static int subnetMaskToPrefixLength(int subnetMask) {
|
||||
int prefixLength = 0;
|
||||
int bit = 1 << 31;
|
||||
|
||||
+2
-2
@@ -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;
|
||||
@@ -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 +
|
||||
'}';
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
package top.wherewego.vnt.jni.param;
|
||||
|
||||
import top.wherewego.vnt.jni.IpUtils;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* 创建网卡所需信息,仅在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 final String[] externalRoute;
|
||||
|
||||
public DeviceConfig(int virtualIp, int virtualNetmask, int virtualGateway, int virtualNetwork, String[] externalRoute) {
|
||||
this.virtualIp = virtualIp;
|
||||
this.virtualNetmask = virtualNetmask;
|
||||
this.virtualGateway = virtualGateway;
|
||||
this.virtualNetwork = virtualNetwork;
|
||||
this.externalRoute = externalRoute;
|
||||
}
|
||||
|
||||
public int getVirtualIp() {
|
||||
return virtualIp;
|
||||
}
|
||||
|
||||
public int getVirtualNetmask() {
|
||||
return virtualNetmask;
|
||||
}
|
||||
|
||||
public int getVirtualGateway() {
|
||||
return virtualGateway;
|
||||
}
|
||||
|
||||
public int getVirtualNetwork() {
|
||||
return virtualNetwork;
|
||||
}
|
||||
|
||||
public String[] getExternalRoute() {
|
||||
return externalRoute;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "DeviceConfig{" +
|
||||
"virtualIp=" + IpUtils.intToIpAddress(virtualIp) +
|
||||
", virtualNetmask=" + IpUtils.intToIpAddress(virtualNetmask) +
|
||||
", virtualGateway=" + IpUtils.intToIpAddress(virtualGateway) +
|
||||
", virtualNetwork=" + IpUtils.intToIpAddress(virtualNetwork) +
|
||||
", externalRoute=" + Arrays.toString(externalRoute) +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
package top.wherewego.vnt.jni.param;
|
||||
|
||||
/**
|
||||
* 网卡信息
|
||||
* 网卡信息 仅在 windows/linux/macos上使用
|
||||
*
|
||||
* @author https://github.com/lbl8603/vnt
|
||||
*/
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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 +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -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) + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
||||
+148
-21
@@ -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<JavaVM>,
|
||||
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<GlobalRef> {
|
||||
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<Self> {
|
||||
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<bool> {
|
||||
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<bool> {
|
||||
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(u32::from(info.virtual_ip) as _),
|
||||
JValue::Int(u32::from(info.virtual_netmask) as _),
|
||||
JValue::Int(u32::from(info.virtual_gateway) as _),
|
||||
],
|
||||
)?;
|
||||
let rs = env.call_method(
|
||||
@@ -121,16 +172,78 @@ impl CallBack {
|
||||
)?;
|
||||
rs.z()
|
||||
}
|
||||
#[cfg(target_os = "android")]
|
||||
fn generate_tun0(&self, info: DeviceConfig) -> jni::errors::Result<u32> {
|
||||
let mut env = self.jvm.attach_current_thread_as_daemon()?;
|
||||
let class = unsafe { JClass::from_raw(self.device_config_class.as_raw()) };
|
||||
|
||||
let object_array = env.new_object_array(
|
||||
info.external_route.len() as _,
|
||||
"java/lang/String",
|
||||
JObject::null(),
|
||||
)?;
|
||||
for (index, (network, mask)) in info.external_route.into_iter().enumerate() {
|
||||
let param =
|
||||
env.new_string(format!("{}/{}", network, u32::from(mask).leading_ones()))?;
|
||||
env.set_object_array_element(&object_array, index as _, ¶m)?;
|
||||
}
|
||||
let param = env.new_object(
|
||||
class,
|
||||
"(IIII[Ljava/lang/String;)V",
|
||||
&[
|
||||
JValue::Int(u32::from(info.virtual_ip) as _),
|
||||
JValue::Int(u32::from(info.virtual_netmask) as _),
|
||||
JValue::Int(u32::from(info.virtual_gateway) as _),
|
||||
JValue::Int(u32::from(info.virtual_network) as _),
|
||||
JValue::Object(&object_array),
|
||||
],
|
||||
)?;
|
||||
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<PeerClientInfo>) -> 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(u32::from(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 +256,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 +268,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 +294,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<PeerClientInfo>) {
|
||||
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) {
|
||||
|
||||
+2
-25
@@ -1,4 +1,3 @@
|
||||
use std::net::ToSocketAddrs;
|
||||
use std::str::FromStr;
|
||||
|
||||
use jni::errors::Error;
|
||||
@@ -21,6 +20,7 @@ pub fn new_config(env: &mut JNIEnv, config: JObject) -> Result<Config, Error> {
|
||||
let password = to_string(env, &config, "password")?;
|
||||
let server_address_str = to_string_not_null(env, &config, "server")?;
|
||||
let stun_server = to_string_array_not_null(env, &config, "stunServer")?;
|
||||
let dns = to_string_array(env, &config, "dns")?.unwrap_or_else(|| vec![]);
|
||||
let cipher_model = to_string_not_null(env, &config, "cipherModel")?;
|
||||
let punch_model = to_string(env, &config, "punchModel")?;
|
||||
let mtu = to_integer(env, &config, "mtu")?.map(|v| v as u32);
|
||||
@@ -78,25 +78,6 @@ pub fn new_config(env: &mut JNIEnv, config: JObject) -> Result<Config, Error> {
|
||||
vec![]
|
||||
};
|
||||
|
||||
let server_address = match server_address_str.to_socket_addrs() {
|
||||
Ok(mut rs) => {
|
||||
if let Some(addr) = rs.next() {
|
||||
addr
|
||||
} else {
|
||||
env.throw_new("java/lang/RuntimeException", "server address err")
|
||||
.expect("throw");
|
||||
return Err(Error::JavaException);
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
env.throw_new(
|
||||
"java/lang/RuntimeException",
|
||||
format!("server address {}", e),
|
||||
)
|
||||
.expect("throw");
|
||||
return Err(Error::JavaException);
|
||||
}
|
||||
};
|
||||
let cipher_model = match CipherModel::from_str(&cipher_model) {
|
||||
Ok(cipher_model) => cipher_model,
|
||||
Err(e) => {
|
||||
@@ -107,16 +88,14 @@ pub fn new_config(env: &mut JNIEnv, config: JObject) -> Result<Config, Error> {
|
||||
};
|
||||
#[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,
|
||||
token,
|
||||
device_id,
|
||||
name,
|
||||
server_address,
|
||||
server_address_str,
|
||||
dns,
|
||||
stun_server,
|
||||
in_ips,
|
||||
out_ips,
|
||||
@@ -134,8 +113,6 @@ pub fn new_config(env: &mut JNIEnv, config: JObject) -> Result<Config, Error> {
|
||||
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,
|
||||
|
||||
+16
-11
@@ -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<jobject, Error> {
|
||||
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),
|
||||
|
||||
@@ -31,6 +31,9 @@ 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"
|
||||
anyhow = "1.0.82"
|
||||
dns-parser = "0.8.0"
|
||||
|
||||
[target.'cfg(target_os = "windows")'.dependencies]
|
||||
libloading = "0.8.0"
|
||||
|
||||
@@ -3,6 +3,7 @@ syntax = "proto3";
|
||||
message HandshakeRequest {
|
||||
string version = 1;
|
||||
bool secret = 2;
|
||||
string key_finger = 3;
|
||||
}
|
||||
message HandshakeResponse {
|
||||
string version = 1;
|
||||
@@ -23,6 +24,7 @@ message RegistrationRequest {
|
||||
fixed32 virtual_ip = 6;
|
||||
bool allow_ip_change = 7;
|
||||
bool client_secret = 8;
|
||||
bytes client_secret_hash = 9;
|
||||
}
|
||||
|
||||
message RegistrationResponse {
|
||||
@@ -40,6 +42,7 @@ message DeviceInfo {
|
||||
fixed32 virtual_ip = 2;
|
||||
uint32 device_status = 3;
|
||||
bool client_secret = 4;
|
||||
bytes client_secret_hash = 5;
|
||||
}
|
||||
|
||||
message DeviceList {
|
||||
|
||||
@@ -74,6 +74,7 @@ impl Deref for Context {
|
||||
/// 对称网络增加的udp socket数目,有助于增加打洞成功率
|
||||
pub const SYMMETRIC_CHANNEL_NUM: usize = 100;
|
||||
const PACKET_LOSS_RATE_DENOMINATOR: u32 = 100_0000;
|
||||
|
||||
pub struct ContextInner {
|
||||
// 核心udp socket
|
||||
pub(crate) main_udp_socket: Vec<UdpSocket>,
|
||||
@@ -198,6 +199,7 @@ impl ContextInner {
|
||||
self.send_main_udp(self.main_index.load(Ordering::Relaxed), buf, addr)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn change_main_index(&self) {
|
||||
let index = (self.main_index.load(Ordering::Relaxed) + 1) % self.main_udp_socket.len();
|
||||
self.main_index.store(index, Ordering::Relaxed);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#[cfg(feature = "aes_ecb")]
|
||||
#[cfg(not(any(feature = "openssl-vendored", feature = "openssl")))]
|
||||
use crate::cipher::aes_ecb::AesEcbCipher;
|
||||
use std::fmt::Display;
|
||||
|
||||
#[cfg(feature = "aes_cbc")]
|
||||
use crate::cipher::aes_cbc::AesCbcCipher;
|
||||
@@ -48,6 +49,18 @@ pub enum CipherModel {
|
||||
None,
|
||||
}
|
||||
|
||||
impl Display for CipherModel {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
let str = match self {
|
||||
CipherModel::AesGcm => "aes_gcm".to_string(),
|
||||
CipherModel::AesCbc => "aes_cbc".to_string(),
|
||||
CipherModel::AesEcb => "aes_ecb".to_string(),
|
||||
CipherModel::Sm4Cbc => "sm4_cbc".to_string(),
|
||||
CipherModel::None => "none".to_string(),
|
||||
};
|
||||
write!(f, "{}", str)
|
||||
}
|
||||
}
|
||||
impl FromStr for CipherModel {
|
||||
type Err = String;
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use crate::protocol::NetPacket;
|
||||
use std::io;
|
||||
|
||||
use {
|
||||
crate::protocol::body::{RsaSecretBody, RSA_ENCRYPTION_RESERVED},
|
||||
rand::Rng,
|
||||
@@ -9,6 +9,8 @@ use {
|
||||
spki::{DecodePublicKey, EncodePublicKey},
|
||||
};
|
||||
|
||||
use crate::protocol::NetPacket;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct RsaCipher {
|
||||
inner: Inner,
|
||||
@@ -16,13 +18,15 @@ pub struct RsaCipher {
|
||||
#[derive(Clone)]
|
||||
struct Inner {
|
||||
public_key: RsaPublicKey,
|
||||
finger: String,
|
||||
}
|
||||
|
||||
impl RsaCipher {
|
||||
pub fn new(der: &[u8]) -> io::Result<Self> {
|
||||
match RsaPublicKey::from_public_key_der(der) {
|
||||
Ok(public_key) => {
|
||||
let inner = Inner { public_key };
|
||||
let finger = finger(&public_key)?;
|
||||
let inner = Inner { public_key, finger };
|
||||
Ok(Self { inner })
|
||||
}
|
||||
Err(e) => Err(io::Error::new(
|
||||
@@ -31,30 +35,32 @@ impl RsaCipher {
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn finger(&self) -> io::Result<String> {
|
||||
match self.inner.public_key.to_public_key_der() {
|
||||
Ok(der) => match rsa::pkcs8::SubjectPublicKeyInfoRef::from_der(der.as_bytes()) {
|
||||
Ok(spki) => match spki.fingerprint_base64() {
|
||||
Ok(finger) => Ok(finger),
|
||||
Err(e) => Err(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
format!("fingerprint_base64 error {}", e),
|
||||
)),
|
||||
},
|
||||
pub fn finger(&self) -> &String {
|
||||
&self.inner.finger
|
||||
}
|
||||
pub fn public_key(&self) -> io::Result<&RsaPublicKey> {
|
||||
return Ok(&self.inner.public_key);
|
||||
}
|
||||
}
|
||||
pub fn finger(public_key: &RsaPublicKey) -> io::Result<String> {
|
||||
match public_key.to_public_key_der() {
|
||||
Ok(der) => match rsa::pkcs8::SubjectPublicKeyInfoRef::from_der(der.as_bytes()) {
|
||||
Ok(spki) => match spki.fingerprint_base64() {
|
||||
Ok(finger) => Ok(finger),
|
||||
Err(e) => Err(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
format!("from_der error {}", e),
|
||||
format!("fingerprint_base64 error {}", e),
|
||||
)),
|
||||
},
|
||||
Err(e) => Err(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
format!("to_public_key_der error {}", e),
|
||||
format!("from_der error {}", e),
|
||||
)),
|
||||
}
|
||||
}
|
||||
pub fn public_key(&self) -> io::Result<&RsaPublicKey> {
|
||||
return Ok(&self.inner.public_key);
|
||||
},
|
||||
Err(e) => Err(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
format!("to_public_key_der error {}", e),
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+57
-28
@@ -7,7 +7,8 @@ use std::time::Duration;
|
||||
use crossbeam_utils::atomic::AtomicCell;
|
||||
use parking_lot::{Mutex, RwLock};
|
||||
use rand::Rng;
|
||||
|
||||
use rsa::signature::digest::Digest;
|
||||
#[cfg(not(target_os = "android"))]
|
||||
use tun::device::IFace;
|
||||
|
||||
use crate::channel::context::Context;
|
||||
@@ -22,14 +23,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 {
|
||||
@@ -42,6 +44,7 @@ pub struct Vnt {
|
||||
peer_nat_info_map: Arc<RwLock<HashMap<Ipv4Addr, NatInfo>>>,
|
||||
down_count_watcher: WatchU64Adder,
|
||||
up_count_watcher: WatchSingleU64Adder,
|
||||
client_secret_hash: Option<[u8; 16]>,
|
||||
}
|
||||
|
||||
impl Vnt {
|
||||
@@ -78,9 +81,18 @@ impl Vnt {
|
||||
config.name.clone(),
|
||||
config.token.clone(),
|
||||
config.ip,
|
||||
config.password.is_some(),
|
||||
config.password.as_ref().map(|v| {
|
||||
let mut hasher = sha2::Sha256::new();
|
||||
hasher.update(config.cipher_model.to_string().as_bytes());
|
||||
hasher.update(v.as_bytes());
|
||||
hasher.update(config.token.as_bytes());
|
||||
let key: [u8; 32] = hasher.finalize().into();
|
||||
key[16..].try_into().unwrap()
|
||||
}),
|
||||
config.server_encrypt,
|
||||
config.device_id.clone(),
|
||||
config.server_address_str.clone(),
|
||||
config.name_servers.clone(),
|
||||
);
|
||||
let ports = config.ports.as_ref().map_or(vec![0, 0], |v| {
|
||||
if v.is_empty() {
|
||||
@@ -112,10 +124,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();
|
||||
@@ -144,14 +160,34 @@ impl Vnt {
|
||||
let down_counter =
|
||||
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();
|
||||
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(),
|
||||
@@ -176,22 +212,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(),
|
||||
@@ -208,6 +232,7 @@ impl Vnt {
|
||||
let device_list = device_list.clone();
|
||||
let down_count_watcher = down_count_watcher.clone();
|
||||
let up_count_watcher = up_count_watcher.clone();
|
||||
let config_info = config_info.clone();
|
||||
let current_device = current_device.clone();
|
||||
if !config.use_channel_type.is_only_relay() {
|
||||
// 定时nat探测
|
||||
@@ -248,6 +273,7 @@ impl Vnt {
|
||||
peer_nat_info_map,
|
||||
down_count_watcher,
|
||||
up_count_watcher,
|
||||
client_secret_hash: config_info.client_secret_hash,
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -336,6 +362,9 @@ impl Vnt {
|
||||
pub fn client_encrypt(&self) -> bool {
|
||||
self.config.password.is_some()
|
||||
}
|
||||
pub fn client_encrypt_hash(&self) -> Option<&[u8]> {
|
||||
self.client_secret_hash.as_ref().map(|v| v.as_ref())
|
||||
}
|
||||
pub fn current_device(&self) -> CurrentDeviceInfo {
|
||||
self.current_device.load()
|
||||
}
|
||||
|
||||
+24
-12
@@ -1,11 +1,13 @@
|
||||
use std::io;
|
||||
use std::net::{Ipv4Addr, SocketAddr};
|
||||
use anyhow::anyhow;
|
||||
use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr};
|
||||
use std::str::FromStr;
|
||||
|
||||
pub use conn::Vnt;
|
||||
|
||||
use crate::channel::punch::PunchModel;
|
||||
use crate::channel::UseChannelType;
|
||||
use crate::cipher::CipherModel;
|
||||
use crate::util::{address_choose, dns_query_all};
|
||||
|
||||
mod conn;
|
||||
|
||||
@@ -18,6 +20,7 @@ pub struct Config {
|
||||
pub name: String,
|
||||
pub server_address: SocketAddr,
|
||||
pub server_address_str: String,
|
||||
pub name_servers: Vec<String>,
|
||||
pub stun_server: Vec<String>,
|
||||
pub in_ips: Vec<(u32, u32, Ipv4Addr)>,
|
||||
pub out_ips: Vec<(u32, u32)>,
|
||||
@@ -36,8 +39,6 @@ pub struct Config {
|
||||
pub first_latency: bool,
|
||||
#[cfg(not(target_os = "android"))]
|
||||
pub device_name: Option<String>,
|
||||
#[cfg(target_os = "android")]
|
||||
pub device_fd: i32,
|
||||
pub use_channel_type: UseChannelType,
|
||||
//控制丢包率
|
||||
pub packet_loss_rate: Option<f64>,
|
||||
@@ -50,8 +51,8 @@ impl Config {
|
||||
token: String,
|
||||
device_id: String,
|
||||
name: String,
|
||||
server_address: SocketAddr,
|
||||
server_address_str: String,
|
||||
mut name_servers: Vec<String>,
|
||||
mut stun_server: Vec<String>,
|
||||
in_ips: Vec<(u32, u32, Ipv4Addr)>,
|
||||
out_ips: Vec<(u32, u32)>,
|
||||
@@ -68,25 +69,37 @@ impl Config {
|
||||
ports: Option<Vec<u16>>,
|
||||
first_latency: bool,
|
||||
#[cfg(not(target_os = "android"))] device_name: Option<String>,
|
||||
#[cfg(target_os = "android")] device_fd: i32,
|
||||
use_channel_type: UseChannelType,
|
||||
packet_loss_rate: Option<f64>,
|
||||
packet_delay: u32,
|
||||
) -> io::Result<Self> {
|
||||
) -> anyhow::Result<Self> {
|
||||
for x in stun_server.iter_mut() {
|
||||
if !x.contains(":") {
|
||||
x.push_str(":3478");
|
||||
}
|
||||
}
|
||||
for x in name_servers.iter_mut() {
|
||||
if Ipv6Addr::from_str(x).is_ok() {
|
||||
x.push_str(":53");
|
||||
} else if !x.contains(":") {
|
||||
x.push_str(":53");
|
||||
}
|
||||
}
|
||||
if token.is_empty() || token.len() > 128 {
|
||||
return Err(io::Error::new(io::ErrorKind::Other, "token too long"));
|
||||
return Err(anyhow!("token too long"));
|
||||
}
|
||||
if device_id.is_empty() || device_id.len() > 128 {
|
||||
return Err(io::Error::new(io::ErrorKind::Other, "device_id too long"));
|
||||
return Err(anyhow!("device_id too long"));
|
||||
}
|
||||
if name.is_empty() || name.len() > 128 {
|
||||
return Err(io::Error::new(io::ErrorKind::Other, "name too long"));
|
||||
return Err(anyhow!("name too long"));
|
||||
}
|
||||
if name_servers.is_empty() {
|
||||
name_servers.push("114.114.114.114:53".to_string());
|
||||
name_servers.push("8.8.8.8:53".to_string());
|
||||
}
|
||||
let server_address =
|
||||
address_choose(dns_query_all(&server_address_str, name_servers.clone())?)?;
|
||||
Ok(Self {
|
||||
#[cfg(any(target_os = "windows", target_os = "linux"))]
|
||||
tap,
|
||||
@@ -95,6 +108,7 @@ impl Config {
|
||||
name,
|
||||
server_address,
|
||||
server_address_str,
|
||||
name_servers,
|
||||
stun_server,
|
||||
in_ips,
|
||||
out_ips,
|
||||
@@ -113,8 +127,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,
|
||||
|
||||
@@ -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<u8> 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<PeerClientInfo>) {}
|
||||
/// 异常信息
|
||||
fn error(&self, _info: ErrorInfo) {}
|
||||
/// 服务停止
|
||||
|
||||
@@ -4,6 +4,7 @@ use std::sync::Arc;
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
use crossbeam_utils::atomic::AtomicCell;
|
||||
use parking_lot::Mutex;
|
||||
use protobuf::Message;
|
||||
|
||||
use crate::channel::context::Context;
|
||||
@@ -27,11 +28,13 @@ pub enum HandshakeEnum {
|
||||
#[derive(Clone)]
|
||||
pub struct Handshake {
|
||||
time: Arc<AtomicCell<Instant>>,
|
||||
rsa_cipher: Arc<Mutex<Option<RsaCipher>>>,
|
||||
}
|
||||
impl Handshake {
|
||||
pub fn new() -> Self {
|
||||
pub fn new(rsa_cipher: Arc<Mutex<Option<RsaCipher>>>) -> Self {
|
||||
Handshake {
|
||||
time: Arc::new(AtomicCell::new(Instant::now() - Duration::from_secs(60))),
|
||||
rsa_cipher,
|
||||
}
|
||||
}
|
||||
pub fn send(&self, context: &Context, secret: bool, addr: SocketAddr) -> io::Result<()> {
|
||||
@@ -40,36 +43,38 @@ impl Handshake {
|
||||
if last.elapsed() < Duration::from_secs(3) {
|
||||
return Ok(());
|
||||
}
|
||||
let request_packet = handshake_request_packet(secret)?;
|
||||
let request_packet = self.handshake_request_packet(secret)?;
|
||||
log::info!("发送握手请求,secret={},{:?}", secret, addr);
|
||||
context.send_default(request_packet.buffer(), addr)?;
|
||||
self.time.store(Instant::now());
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// 第一次握手数据
|
||||
pub fn handshake_request_packet(secret: bool) -> io::Result<NetPacket<Vec<u8>>> {
|
||||
let mut request = HandshakeRequest::new();
|
||||
request.secret = secret;
|
||||
request.version = crate::VNT_VERSION.to_string();
|
||||
let bytes = request.write_to_bytes().map_err(|e| {
|
||||
io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
format!("handshake_request_packet {:?}", e),
|
||||
)
|
||||
})?;
|
||||
let buf = vec![0u8; 12 + bytes.len()];
|
||||
let mut net_packet = NetPacket::new(buf)?;
|
||||
net_packet.set_version(Version::V1);
|
||||
net_packet.set_gateway_flag(true);
|
||||
net_packet.set_destination(GATEWAY_IP);
|
||||
net_packet.set_source(SELF_IP);
|
||||
net_packet.set_protocol(Protocol::Service);
|
||||
net_packet.set_transport_protocol(service_packet::Protocol::HandshakeRequest.into());
|
||||
net_packet.first_set_ttl(MAX_TTL);
|
||||
net_packet.set_payload(&bytes)?;
|
||||
Ok(net_packet)
|
||||
/// 第一次握手数据
|
||||
pub fn handshake_request_packet(&self, secret: bool) -> io::Result<NetPacket<Vec<u8>>> {
|
||||
let mut request = HandshakeRequest::new();
|
||||
request.secret = secret;
|
||||
request.version = crate::VNT_VERSION.to_string();
|
||||
if let Some(finger) = self.rsa_cipher.lock().as_ref().map(|v| v.finger().clone()) {
|
||||
request.key_finger = finger;
|
||||
}
|
||||
let bytes = request.write_to_bytes().map_err(|e| {
|
||||
io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
format!("handshake_request_packet {:?}", e),
|
||||
)
|
||||
})?;
|
||||
let buf = vec![0u8; 12 + bytes.len()];
|
||||
let mut net_packet = NetPacket::new(buf)?;
|
||||
net_packet.set_version(Version::V1);
|
||||
net_packet.set_gateway_flag(true);
|
||||
net_packet.set_destination(GATEWAY_IP);
|
||||
net_packet.set_source(SELF_IP);
|
||||
net_packet.set_protocol(Protocol::Service);
|
||||
net_packet.set_transport_protocol(service_packet::Protocol::HandshakeRequest.into());
|
||||
net_packet.first_set_ttl(MAX_TTL);
|
||||
net_packet.set_payload(&bytes)?;
|
||||
Ok(net_packet)
|
||||
}
|
||||
}
|
||||
|
||||
/// 第二次加密握手
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use std::io;
|
||||
use std::net::{SocketAddr, ToSocketAddrs};
|
||||
use std::net::SocketAddr;
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
|
||||
@@ -11,8 +11,8 @@ use crate::channel::idle::{Idle, IdleType};
|
||||
use crate::channel::sender::AcceptSocketSender;
|
||||
use crate::handle::callback::{ConnectInfo, ErrorType};
|
||||
use crate::handle::handshaker::Handshake;
|
||||
use crate::handle::{handshaker, BaseConfigInfo, ConnectStatus, CurrentDeviceInfo};
|
||||
use crate::util::Scheduler;
|
||||
use crate::handle::{BaseConfigInfo, ConnectStatus, CurrentDeviceInfo};
|
||||
use crate::util::{address_choose, dns_query_all, Scheduler};
|
||||
use crate::{ErrorInfo, VntCallback};
|
||||
|
||||
pub fn idle_route<Call: VntCallback>(
|
||||
@@ -133,11 +133,11 @@ fn check_gateway_channel<Call: VntCallback>(
|
||||
//需要重连
|
||||
call.connect(ConnectInfo::new(*count, current_device.connect_server));
|
||||
log::info!("发送握手请求,{:?}", config);
|
||||
if let Err(e) = handshake.send(context, config.client_secret, current_device.connect_server)
|
||||
if let Err(e) = handshake.send(context, config.server_secret, current_device.connect_server)
|
||||
{
|
||||
log::warn!("{:?}", e);
|
||||
if context.is_main_tcp() {
|
||||
let request_packet = handshaker::handshake_request_packet(config.client_secret)?;
|
||||
let request_packet = handshake.handshake_request_packet(config.server_secret)?;
|
||||
//tcp需要重连
|
||||
let tcp_stream = std::net::TcpStream::connect_timeout(
|
||||
¤t_device.connect_server,
|
||||
@@ -162,24 +162,42 @@ pub fn domain_request0(
|
||||
config: &BaseConfigInfo,
|
||||
) -> CurrentDeviceInfo {
|
||||
let mut current_dev = current_device.load();
|
||||
|
||||
// 探测服务端地址变化
|
||||
if let Ok(mut addr) = config.server_addr.to_socket_addrs() {
|
||||
if let Some(addr) = addr.next() {
|
||||
if addr != current_dev.connect_server {
|
||||
let mut tmp = current_dev.clone();
|
||||
tmp.connect_server = addr;
|
||||
let rs = current_device.compare_exchange(current_dev, tmp);
|
||||
log::info!(
|
||||
"服务端地址变化,旧地址:{},新地址:{},替换结果:{}",
|
||||
current_dev.connect_server,
|
||||
addr,
|
||||
rs.is_ok()
|
||||
);
|
||||
if rs.is_ok() {
|
||||
current_dev.connect_server = addr;
|
||||
match dns_query_all(&config.server_addr, config.name_servers.clone()) {
|
||||
Ok(addrs) => {
|
||||
log::info!(
|
||||
"domain {} dns {:?} addr {:?}",
|
||||
config.server_addr,
|
||||
config.name_servers,
|
||||
addrs
|
||||
);
|
||||
|
||||
match address_choose(addrs) {
|
||||
Ok(addr) => {
|
||||
if addr != current_dev.connect_server {
|
||||
let mut tmp = current_dev.clone();
|
||||
tmp.connect_server = addr;
|
||||
let rs = current_device.compare_exchange(current_dev, tmp);
|
||||
log::info!(
|
||||
"服务端地址变化,旧地址:{},新地址:{},替换结果:{}",
|
||||
current_dev.connect_server,
|
||||
addr,
|
||||
rs.is_ok()
|
||||
);
|
||||
if rs.is_ok() {
|
||||
current_dev.connect_server = addr;
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
log::error!("域名地址选择失败:{:?},domain={}", e, config.server_addr);
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
log::error!("域名解析失败:{:?},domain={}", e, config.server_addr);
|
||||
}
|
||||
}
|
||||
current_dev
|
||||
}
|
||||
|
||||
+18
-4
@@ -32,15 +32,23 @@ pub struct PeerDeviceInfo {
|
||||
pub name: String,
|
||||
pub status: PeerDeviceStatus,
|
||||
pub client_secret: bool,
|
||||
pub client_secret_hash: Vec<u8>,
|
||||
}
|
||||
|
||||
impl PeerDeviceInfo {
|
||||
pub fn new(virtual_ip: Ipv4Addr, name: String, status: u8, client_secret: bool) -> Self {
|
||||
pub fn new(
|
||||
virtual_ip: Ipv4Addr,
|
||||
name: String,
|
||||
status: u8,
|
||||
client_secret: bool,
|
||||
client_secret_hash: Vec<u8>,
|
||||
) -> Self {
|
||||
Self {
|
||||
virtual_ip,
|
||||
name,
|
||||
status: PeerDeviceStatus::from(status),
|
||||
client_secret,
|
||||
client_secret_hash,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -50,9 +58,11 @@ pub struct BaseConfigInfo {
|
||||
pub name: String,
|
||||
pub token: String,
|
||||
pub ip: Option<Ipv4Addr>,
|
||||
pub client_secret: bool,
|
||||
pub client_secret_hash: Option<[u8; 16]>,
|
||||
pub server_secret: bool,
|
||||
pub device_id: String,
|
||||
pub server_addr: String,
|
||||
pub name_servers: Vec<String>,
|
||||
}
|
||||
|
||||
impl BaseConfigInfo {
|
||||
@@ -60,17 +70,21 @@ impl BaseConfigInfo {
|
||||
name: String,
|
||||
token: String,
|
||||
ip: Option<Ipv4Addr>,
|
||||
client_secret: bool,
|
||||
client_secret_hash: Option<[u8; 16]>,
|
||||
server_secret: bool,
|
||||
device_id: String,
|
||||
server_addr: String,
|
||||
name_servers: Vec<String>,
|
||||
) -> Self {
|
||||
Self {
|
||||
name,
|
||||
token,
|
||||
ip,
|
||||
client_secret,
|
||||
client_secret_hash,
|
||||
server_secret,
|
||||
device_id,
|
||||
server_addr,
|
||||
name_servers,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>,
|
||||
device: DeviceAdapter,
|
||||
client_cipher: Cipher,
|
||||
punch_sender: PunchSender,
|
||||
peer_nat_info_map: Arc<RwLock<HashMap<Ipv4Addr, NatInfo>>>,
|
||||
@@ -45,7 +44,7 @@ pub struct ClientPacketHandler {
|
||||
|
||||
impl ClientPacketHandler {
|
||||
pub fn new(
|
||||
device: Arc<Device>,
|
||||
device: DeviceAdapter,
|
||||
client_cipher: Cipher,
|
||||
punch_sender: PunchSender,
|
||||
peer_nat_info_map: Arc<RwLock<HashMap<Ipv4Addr, NatInfo>>>,
|
||||
|
||||
@@ -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<Call: VntCallback> RecvDataHandler<Call> {
|
||||
server_cipher: Cipher,
|
||||
client_cipher: Cipher,
|
||||
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
||||
device: Arc<Device>,
|
||||
device: DeviceAdapter,
|
||||
device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>,
|
||||
config_info: BaseConfigInfo,
|
||||
nat_test: NatTest,
|
||||
@@ -111,6 +110,7 @@ impl<Call: VntCallback> RecvDataHandler<Call> {
|
||||
self.counter.add(buf.len() as _);
|
||||
let net_packet = NetPacket::new(buf)?;
|
||||
if net_packet.ttl() == 0 || net_packet.source_ttl() < net_packet.ttl() {
|
||||
log::warn!("丢弃过时包:{:?}", net_packet.head());
|
||||
return Ok(());
|
||||
}
|
||||
let current_device = self.current_device.load();
|
||||
|
||||
@@ -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<Call> {
|
||||
rsa_cipher: Arc<Mutex<Option<RsaCipher>>>,
|
||||
server_cipher: Cipher,
|
||||
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
||||
device: Arc<Device>,
|
||||
device: DeviceAdapter,
|
||||
device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>,
|
||||
config_info: BaseConfigInfo,
|
||||
nat_test: NatTest,
|
||||
callback: Call,
|
||||
#[cfg(feature = "server_encrypt")]
|
||||
up_key_time: Arc<AtomicCell<Instant>>,
|
||||
#[cfg(not(target_os = "android"))]
|
||||
route_record: Arc<Mutex<Vec<(Ipv4Addr, Ipv4Addr)>>>,
|
||||
external_route: ExternalRoute,
|
||||
handshake: Handshake,
|
||||
@@ -60,7 +62,7 @@ impl<Call> ServerPacketHandler<Call> {
|
||||
#[cfg(feature = "server_encrypt")] rsa_cipher: Arc<Mutex<Option<RsaCipher>>>,
|
||||
server_cipher: Cipher,
|
||||
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
||||
device: Arc<Device>,
|
||||
device: DeviceAdapter,
|
||||
device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>,
|
||||
config_info: BaseConfigInfo,
|
||||
nat_test: NatTest,
|
||||
@@ -80,6 +82,7 @@ impl<Call> ServerPacketHandler<Call> {
|
||||
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,
|
||||
@@ -136,13 +139,45 @@ impl<Call: VntCallback> PacketHandler for ServerPacketHandler<Call> {
|
||||
HandshakeResponse::parse_from_bytes(net_packet.payload()).map_err(|e| {
|
||||
io::Error::new(io::ErrorKind::Other, format!("HandshakeResponse {:?}", e))
|
||||
})?;
|
||||
log::info!("握手响应:{:?},{}", route_key, response);
|
||||
//如果开启了加密,则发送加密握手请求
|
||||
#[cfg(feature = "server_encrypt")]
|
||||
if let Some(key) = self.server_cipher.key() {
|
||||
{
|
||||
let guard = self.rsa_cipher.lock();
|
||||
if let Some(rsa_cipher) = guard.as_ref() {
|
||||
if rsa_cipher.finger() == &response.key_finger {
|
||||
let packet = handshaker::secret_handshake_request_packet(
|
||||
rsa_cipher,
|
||||
self.config_info.token.clone(),
|
||||
key,
|
||||
)?;
|
||||
drop(guard);
|
||||
context.send_by_key(packet.buffer(), route_key)?;
|
||||
return Ok(());
|
||||
}
|
||||
log::warn!(
|
||||
"拒绝服务端密钥对变化,原指纹:{:?},新指纹:{:?},addr:{:?}",
|
||||
rsa_cipher.finger(),
|
||||
response.key_finger,
|
||||
route_key
|
||||
);
|
||||
return Ok(());
|
||||
}
|
||||
drop(guard);
|
||||
}
|
||||
let rsa_cipher = RsaCipher::new(&response.public_key)?;
|
||||
if rsa_cipher.finger() != &response.key_finger {
|
||||
log::info!(
|
||||
"服务端密钥和指纹不匹 配拒绝握手,指纹1:{:?},指纹2:{:?}",
|
||||
rsa_cipher.finger(),
|
||||
response.key_finger
|
||||
);
|
||||
return Ok(());
|
||||
}
|
||||
let handshake_info = HandshakeInfo::new(
|
||||
rsa_cipher.public_key()?.clone(),
|
||||
rsa_cipher.finger()?,
|
||||
response.key_finger,
|
||||
response.version,
|
||||
);
|
||||
log::info!("加密握手请求:{:?}", handshake_info);
|
||||
@@ -158,7 +193,9 @@ impl<Call: VntCallback> PacketHandler for ServerPacketHandler<Call> {
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
if let Ok(rsa_cipher) = RsaCipher::new(&response.public_key) {
|
||||
self.rsa_cipher.lock().replace(rsa_cipher);
|
||||
}
|
||||
let handshake_info = HandshakeInfo::new_no_secret(response.version);
|
||||
if self.callback.handshake(handshake_info) {
|
||||
//没有加密,则发送注册请求
|
||||
@@ -267,6 +304,31 @@ impl<Call: VntCallback> ServerPacketHandler<Call> {
|
||||
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) {
|
||||
@@ -356,23 +418,36 @@ impl<Call: VntCallback> ServerPacketHandler<Call> {
|
||||
info.name,
|
||||
info.device_status as u8,
|
||||
info.client_secret,
|
||||
info.client_secret_hash,
|
||||
)
|
||||
})
|
||||
.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() {
|
||||
//已连接的不需要注册
|
||||
log::info!("已连接的不需要注册,{:?}", self.config_info);
|
||||
return Ok(());
|
||||
}
|
||||
let token = self.config_info.token.clone();
|
||||
let device_id = self.config_info.device_id.clone();
|
||||
let name = self.config_info.name.clone();
|
||||
let client_secret = self.config_info.client_secret;
|
||||
let client_secret = self
|
||||
.config_info
|
||||
.client_secret_hash
|
||||
.as_ref()
|
||||
.map(|v| v.as_ref());
|
||||
let mut ip = self.config_info.ip;
|
||||
if ip.is_none() {
|
||||
ip = Some(current_device.virtual_ip)
|
||||
@@ -415,7 +490,7 @@ impl<Call: VntCallback> ServerPacketHandler<Call> {
|
||||
drop(dev);
|
||||
}
|
||||
self.handshake
|
||||
.send(context, self.config_info.client_secret, route_key.addr)?;
|
||||
.send(context, self.config_info.server_secret, route_key.addr)?;
|
||||
// self.register(current_device, context, route_key)?;
|
||||
}
|
||||
InErrorPacket::AddressExhausted => {
|
||||
@@ -469,7 +544,7 @@ impl<Call: VntCallback> ServerPacketHandler<Call> {
|
||||
poll_device.first_set_ttl(MAX_TTL);
|
||||
poll_device.set_protocol(Protocol::Service);
|
||||
poll_device
|
||||
.set_transport_protocol(service_packet::Protocol::PollDeviceList.into());
|
||||
.set_transport_protocol(service_packet::Protocol::PullDeviceList.into());
|
||||
self.server_cipher.encrypt_ipv4(&mut poll_device)?;
|
||||
//发送到默认服务端即可
|
||||
context.send_default(poll_device.buffer(), current_device.connect_server)?;
|
||||
|
||||
@@ -33,12 +33,12 @@ impl PacketHandler for TurnPacketHandler {
|
||||
return Ok(());
|
||||
}
|
||||
if route.metric <= ttl {
|
||||
context.send_by_key(net_packet.buffer(), route.route_key())?;
|
||||
return context.send_by_key(net_packet.buffer(), route.route_key());
|
||||
}
|
||||
}
|
||||
//其他没有路由的不转发
|
||||
}
|
||||
|
||||
log::info!("没有路由 {:?},{:?}", route_key, net_packet.head());
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ pub fn registration_request_packet(
|
||||
ip: Option<Ipv4Addr>,
|
||||
is_fast: bool,
|
||||
allow_ip_change: bool,
|
||||
client_secret: bool,
|
||||
client_secret_hash: Option<&[u8]>,
|
||||
) -> io::Result<NetPacket<Vec<u8>>> {
|
||||
let mut request = RegistrationRequest::new();
|
||||
request.token = token;
|
||||
@@ -30,7 +30,12 @@ pub fn registration_request_packet(
|
||||
request.allow_ip_change = allow_ip_change;
|
||||
request.is_fast = is_fast;
|
||||
request.version = crate::VNT_VERSION.to_string();
|
||||
request.client_secret = client_secret;
|
||||
if let Some(client_secret_hash) = client_secret_hash {
|
||||
request.client_secret = true;
|
||||
request
|
||||
.client_secret_hash
|
||||
.extend_from_slice(client_secret_hash);
|
||||
}
|
||||
let bytes = request.write_to_bytes().map_err(|e| {
|
||||
io::Error::new(io::ErrorKind::Other, format!("RegistrationRequest {:?}", e))
|
||||
})?;
|
||||
|
||||
@@ -87,14 +87,14 @@ pub fn start(
|
||||
device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>,
|
||||
) -> 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") {
|
||||
|
||||
+1
-1
@@ -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::*;
|
||||
|
||||
+80
-32
@@ -1,24 +1,24 @@
|
||||
use std::collections::HashSet;
|
||||
use std::io;
|
||||
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
|
||||
use std::time::Duration;
|
||||
use std::{io, thread};
|
||||
|
||||
use crate::channel::punch::NatType;
|
||||
use std::net::UdpSocket;
|
||||
use stun_format::Attr;
|
||||
|
||||
pub fn stun_test_nat(stun_servers: Vec<String>) -> io::Result<(NatType, Vec<Ipv4Addr>, u16)> {
|
||||
let mut h = Vec::new();
|
||||
for x in stun_servers {
|
||||
let handle = thread::spawn(move || test_nat(x));
|
||||
h.push(handle);
|
||||
let mut th = Vec::new();
|
||||
for _ in 0..2 {
|
||||
let stun_servers = stun_servers.clone();
|
||||
let handle = std::thread::spawn(move || stun_test_nat0(stun_servers));
|
||||
th.push(handle);
|
||||
}
|
||||
let mut nat_type = NatType::Cone;
|
||||
let mut port_range = 0;
|
||||
let mut hash_set = HashSet::new();
|
||||
for x in h {
|
||||
if let Ok(rs) = x.join() {
|
||||
if let Ok((nat_type_t, ip_list_t, port_range_t)) = rs {
|
||||
for x in th {
|
||||
match x.join().unwrap() {
|
||||
Ok((nat_type_t, ip_list_t, port_range_t)) => {
|
||||
if nat_type_t == NatType::Symmetric {
|
||||
nat_type = NatType::Symmetric;
|
||||
}
|
||||
@@ -29,44 +29,91 @@ pub fn stun_test_nat(stun_servers: Vec<String>) -> io::Result<(NatType, Vec<Ipv4
|
||||
port_range = port_range_t;
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
log::warn!("{:?}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok((nat_type, hash_set.into_iter().collect(), port_range))
|
||||
}
|
||||
|
||||
fn test_nat(stun_server: String) -> io::Result<(NatType, Vec<Ipv4Addr>, u16)> {
|
||||
pub fn stun_test_nat0(stun_servers: Vec<String>) -> io::Result<(NatType, Vec<Ipv4Addr>, u16)> {
|
||||
let udp = UdpSocket::bind("0.0.0.0:0")?;
|
||||
udp.set_read_timeout(Some(Duration::from_millis(300)))?;
|
||||
let mut nat_type = NatType::Cone;
|
||||
let mut port_range = 0;
|
||||
let mut hash_set = HashSet::new();
|
||||
let mut pub_addrs = HashSet::new();
|
||||
for x in &stun_servers {
|
||||
match test_nat(&udp, x) {
|
||||
Ok((addr, nat_type_t, ip_list_t, port_range_t)) => {
|
||||
if nat_type_t == NatType::Symmetric {
|
||||
nat_type = NatType::Symmetric;
|
||||
}
|
||||
for x in ip_list_t {
|
||||
hash_set.insert(x);
|
||||
}
|
||||
if port_range < port_range_t {
|
||||
port_range = port_range_t;
|
||||
}
|
||||
pub_addrs.insert(addr);
|
||||
}
|
||||
Err(e) => {
|
||||
log::warn!("stun {} error {:?} ", x, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
if pub_addrs.len() > 1 {
|
||||
nat_type = NatType::Symmetric;
|
||||
}
|
||||
Ok((nat_type, hash_set.into_iter().collect(), port_range))
|
||||
}
|
||||
|
||||
fn test_nat(
|
||||
udp: &UdpSocket,
|
||||
stun_server: &String,
|
||||
) -> io::Result<(SocketAddr, NatType, Vec<Ipv4Addr>, u16)> {
|
||||
udp.connect(stun_server)?;
|
||||
let mut port_range = 0;
|
||||
let mut hash_set = HashSet::new();
|
||||
let mut nat_type = NatType::Cone;
|
||||
match test_nat_(&udp, true, true) {
|
||||
Ok((mapped_addr1, changed_addr1)) => {
|
||||
match mapped_addr1.ip() {
|
||||
IpAddr::V4(ip) => {
|
||||
hash_set.insert(ip);
|
||||
}
|
||||
IpAddr::V6(_) => {}
|
||||
}
|
||||
if udp.connect(changed_addr1).is_ok() {
|
||||
if let Ok((mapped_addr2, _)) = test_nat_(&udp, false, false) {
|
||||
match mapped_addr2.ip() {
|
||||
IpAddr::V4(ip) => {
|
||||
hash_set.insert(ip);
|
||||
if mapped_addr1 != mapped_addr2 {
|
||||
nat_type = NatType::Symmetric;
|
||||
}
|
||||
let (mapped_addr1, changed_addr1) = test_nat_(&udp, true, true)?;
|
||||
match mapped_addr1.ip() {
|
||||
IpAddr::V4(ip) => {
|
||||
hash_set.insert(ip);
|
||||
}
|
||||
IpAddr::V6(_) => {}
|
||||
}
|
||||
if udp.connect(changed_addr1).is_ok() {
|
||||
match test_nat_(&udp, false, false) {
|
||||
Ok((mapped_addr2, _)) => {
|
||||
match mapped_addr2.ip() {
|
||||
IpAddr::V4(ip) => {
|
||||
hash_set.insert(ip);
|
||||
if mapped_addr1 != mapped_addr2 {
|
||||
nat_type = NatType::Symmetric;
|
||||
}
|
||||
IpAddr::V6(_) => {}
|
||||
}
|
||||
port_range = mapped_addr2.port().abs_diff(mapped_addr1.port());
|
||||
IpAddr::V6(_) => {}
|
||||
}
|
||||
port_range = mapped_addr2.port().abs_diff(mapped_addr1.port());
|
||||
}
|
||||
Err(e) => {
|
||||
log::warn!("stun {} error {:?} ", stun_server, e);
|
||||
}
|
||||
}
|
||||
Err(_) => {}
|
||||
}
|
||||
Ok((nat_type, hash_set.into_iter().collect(), port_range))
|
||||
log::warn!(
|
||||
"stun {} mapped_addr {:?} nat_type {:?}",
|
||||
stun_server,
|
||||
mapped_addr1,
|
||||
nat_type
|
||||
);
|
||||
Ok((
|
||||
mapped_addr1,
|
||||
nat_type,
|
||||
hash_set.into_iter().collect(),
|
||||
port_range,
|
||||
))
|
||||
}
|
||||
|
||||
fn test_nat_(
|
||||
@@ -88,7 +135,8 @@ fn test_nat_(
|
||||
let mut buf = [0; 10240];
|
||||
let (len, _addr) = match udp.recv_from(&mut buf) {
|
||||
Ok(rs) => rs,
|
||||
Err(_) => {
|
||||
Err(e) => {
|
||||
log::warn!("stun error {:?}", e);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -5,14 +5,20 @@ use std::{fmt, io};
|
||||
pub enum Protocol {
|
||||
/// ping请求
|
||||
/*
|
||||
0 1 2 3
|
||||
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| time | echo |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
0 15 31
|
||||
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| time | echo |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
*/
|
||||
Ping,
|
||||
/// 维持连接,内容同ping
|
||||
/*
|
||||
0 15 31
|
||||
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| time | echo |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
*/
|
||||
Pong,
|
||||
/// 打洞请求
|
||||
PunchRequest,
|
||||
@@ -85,8 +91,8 @@ pub type PongPacket<B> = PingPacket<B>;
|
||||
impl<B: AsRef<[u8]>> PingPacket<B> {
|
||||
pub fn new(buffer: B) -> io::Result<PingPacket<B>> {
|
||||
let len = buffer.as_ref().len();
|
||||
if len != 4 {
|
||||
return Err(io::Error::new(io::ErrorKind::InvalidData, "len != 4"));
|
||||
if len < 4 {
|
||||
return Err(io::Error::new(io::ErrorKind::InvalidData, "len < 4"));
|
||||
}
|
||||
Ok(PingPacket { buffer })
|
||||
}
|
||||
@@ -126,8 +132,8 @@ pub struct AddrPacket<B> {
|
||||
impl<B: AsRef<[u8]>> AddrPacket<B> {
|
||||
pub fn new(buffer: B) -> io::Result<AddrPacket<B>> {
|
||||
let len = buffer.as_ref().len();
|
||||
if len != 6 {
|
||||
return Err(io::Error::new(io::ErrorKind::InvalidData, "len != 6"));
|
||||
if len < 6 {
|
||||
return Err(io::Error::new(io::ErrorKind::InvalidData, "len < 6"));
|
||||
}
|
||||
Ok(AddrPacket { buffer })
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ pub enum Protocol {
|
||||
/// 注册响应
|
||||
RegistrationResponse,
|
||||
/// 拉取设备列表
|
||||
PollDeviceList,
|
||||
PullDeviceList,
|
||||
/// 推送设备列表
|
||||
PushDeviceList,
|
||||
/// 和服务端握手
|
||||
@@ -23,7 +23,7 @@ impl From<u8> for Protocol {
|
||||
match value {
|
||||
1 => Self::RegistrationRequest,
|
||||
2 => Self::RegistrationResponse,
|
||||
3 => Self::PollDeviceList,
|
||||
3 => Self::PullDeviceList,
|
||||
4 => Self::PushDeviceList,
|
||||
5 => Self::HandshakeRequest,
|
||||
6 => Self::HandshakeResponse,
|
||||
@@ -40,7 +40,7 @@ impl Into<u8> for Protocol {
|
||||
match self {
|
||||
Self::RegistrationRequest => 1,
|
||||
Self::RegistrationResponse => 2,
|
||||
Self::PollDeviceList => 3,
|
||||
Self::PullDeviceList => 3,
|
||||
Self::PushDeviceList => 4,
|
||||
Self::HandshakeRequest => 5,
|
||||
Self::HandshakeResponse => 6,
|
||||
|
||||
@@ -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<Arc<Device>> {
|
||||
#[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);
|
||||
}
|
||||
}
|
||||
@@ -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<Arc<Device>> {
|
||||
#[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;
|
||||
|
||||
@@ -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<Device>,
|
||||
}
|
||||
impl DeviceAdapter {
|
||||
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
|
||||
pub fn new(tun: Arc<Device>) -> 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<Device>;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.tun
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "android")]
|
||||
#[derive(Clone)]
|
||||
pub struct DeviceAdapter {
|
||||
tun: Arc<Mutex<Option<Arc<Device>>>>,
|
||||
tun_device_helper: TunDeviceHelper,
|
||||
}
|
||||
#[cfg(target_os = "android")]
|
||||
impl DeviceAdapter {
|
||||
pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
|
||||
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<Device>) -> io::Result<()> {
|
||||
self.tun_device_helper.start(device.clone())?;
|
||||
self.tun.lock().replace(device);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct TunDeviceHelper {
|
||||
inner: Arc<AtomicCell<Option<TunDeviceHelperInner>>>,
|
||||
}
|
||||
|
||||
struct TunDeviceHelperInner {
|
||||
stop_manager: StopManager,
|
||||
context: Context,
|
||||
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
||||
ip_route: ExternalRoute,
|
||||
#[cfg(feature = "ip_proxy")]
|
||||
ip_proxy_map: Option<IpProxyMap>,
|
||||
client_cipher: Cipher,
|
||||
server_cipher: Cipher,
|
||||
parallel: usize,
|
||||
up_counter: SingleU64Adder,
|
||||
device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>,
|
||||
}
|
||||
|
||||
impl TunDeviceHelper {
|
||||
pub fn new(
|
||||
stop_manager: StopManager,
|
||||
context: Context,
|
||||
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
||||
ip_route: ExternalRoute,
|
||||
#[cfg(feature = "ip_proxy")] ip_proxy_map: Option<IpProxyMap>,
|
||||
client_cipher: Cipher,
|
||||
server_cipher: Cipher,
|
||||
parallel: usize,
|
||||
up_counter: SingleU64Adder,
|
||||
device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>,
|
||||
) -> 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<Device>) -> 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"))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,225 @@
|
||||
use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr, UdpSocket};
|
||||
use std::str::FromStr;
|
||||
use std::time::Duration;
|
||||
use std::{io, thread};
|
||||
|
||||
use anyhow::Context;
|
||||
use dns_parser::{Builder, Packet, QueryClass, QueryType, RData, ResponseCode};
|
||||
|
||||
/// 后续实现选择延迟最低的可用地址,需要服务端配合
|
||||
/// 现在是选择第一个地址,优先ipv6
|
||||
pub fn address_choose(addrs: Vec<SocketAddr>) -> anyhow::Result<SocketAddr> {
|
||||
let v4: Vec<SocketAddr> = addrs.iter().filter(|v| v.is_ipv4()).map(|v| *v).collect();
|
||||
let v6: Vec<SocketAddr> = addrs.iter().filter(|v| v.is_ipv6()).map(|v| *v).collect();
|
||||
let check_addr = |addrs: &Vec<SocketAddr>| -> anyhow::Result<SocketAddr> {
|
||||
if !addrs.is_empty() {
|
||||
let udp = if addrs[0].is_ipv6() {
|
||||
UdpSocket::bind("[::]:0")?
|
||||
} else {
|
||||
UdpSocket::bind("0.0.0.0:0")?
|
||||
};
|
||||
for addr in addrs {
|
||||
if udp.connect(addr).is_ok() {
|
||||
return Ok(*addr);
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(anyhow::anyhow!("Unable to connect to address {:?}", addrs))
|
||||
};
|
||||
if v6.is_empty() {
|
||||
return check_addr(&v4);
|
||||
}
|
||||
if v4.is_empty() {
|
||||
return check_addr(&v6);
|
||||
}
|
||||
match check_addr(&v6) {
|
||||
Ok(addr) => Ok(addr),
|
||||
Err(e1) => match check_addr(&v4) {
|
||||
Ok(addr) => Ok(addr),
|
||||
Err(e2) => Err(anyhow::anyhow!("{} , {}", e1, e2)),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn dns_query_all(domain: &str, name_servers: Vec<String>) -> anyhow::Result<Vec<SocketAddr>> {
|
||||
match SocketAddr::from_str(domain) {
|
||||
Ok(addr) => {
|
||||
return Ok(vec![addr]);
|
||||
}
|
||||
Err(_) => {
|
||||
if name_servers.is_empty() {
|
||||
Err(anyhow::anyhow!("name server is none"))?
|
||||
}
|
||||
let mut err: Option<anyhow::Error> = None;
|
||||
for name_server in name_servers {
|
||||
if let Some(domain) = domain.to_lowercase().strip_prefix("txt:") {
|
||||
return txt_dns(domain, name_server);
|
||||
}
|
||||
let end_index = domain
|
||||
.rfind(":")
|
||||
.with_context(|| format!("{:?} not port", domain))?;
|
||||
let host = &domain[..end_index];
|
||||
let port = u16::from_str(&domain[end_index + 1..])
|
||||
.with_context(|| format!("{:?} not port", domain))?;
|
||||
let th1 = {
|
||||
let host = host.to_string();
|
||||
let name_server = name_server.clone();
|
||||
thread::spawn(move || a_dns(host, name_server))
|
||||
};
|
||||
let th2 = {
|
||||
let host = host.to_string();
|
||||
let name_server = name_server.clone();
|
||||
thread::spawn(move || aaaa_dns(host, name_server))
|
||||
};
|
||||
let mut addr = Vec::new();
|
||||
match th1.join().unwrap() {
|
||||
Ok(rs) => {
|
||||
for ip in rs {
|
||||
addr.push(SocketAddr::new(ip.into(), port));
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
err.replace(anyhow::anyhow!("{}", e));
|
||||
}
|
||||
}
|
||||
match th2.join().unwrap() {
|
||||
Ok(rs) => {
|
||||
for ip in rs {
|
||||
addr.push(SocketAddr::new(ip.into(), port));
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
if addr.is_empty() {
|
||||
if let Some(err) = &mut err {
|
||||
*err = anyhow::anyhow!("{},{}", err, e);
|
||||
} else {
|
||||
err.replace(anyhow::anyhow!("{}", e));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
if addr.is_empty() {
|
||||
continue;
|
||||
}
|
||||
return Ok(addr);
|
||||
}
|
||||
if let Some(e) = err {
|
||||
Err(e)
|
||||
} else {
|
||||
Err(anyhow::anyhow!("DNS query failed"))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn query<'a>(
|
||||
udp: &UdpSocket,
|
||||
domain: &str,
|
||||
name_server: SocketAddr,
|
||||
record_type: QueryType,
|
||||
buf: &'a mut [u8],
|
||||
) -> anyhow::Result<Packet<'a>> {
|
||||
let mut builder = Builder::new_query(1, true);
|
||||
builder.add_question(domain, false, record_type, QueryClass::IN);
|
||||
let packet = builder.build().unwrap();
|
||||
|
||||
udp.connect(name_server)
|
||||
.with_context(|| format!("DNS {:?} error ", name_server))?;
|
||||
let mut count = 0;
|
||||
let len = loop {
|
||||
udp.send(&packet)?;
|
||||
|
||||
match udp.recv(buf) {
|
||||
Ok(len) => {
|
||||
break len;
|
||||
}
|
||||
Err(e) => {
|
||||
if e.kind() == io::ErrorKind::TimedOut || e.kind() == io::ErrorKind::WouldBlock {
|
||||
count += 1;
|
||||
if count < 3 {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
Err(e).with_context(|| format!("DNS {:?} recv error ", name_server))?
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
let pkt = Packet::parse(&buf[..len])
|
||||
.with_context(|| format!("domain {:?} DNS {:?} data error ", domain, name_server))?;
|
||||
if pkt.header.response_code != ResponseCode::NoError {
|
||||
return Err(anyhow::anyhow!(
|
||||
"response_code {} DNS {:?} domain {:?}",
|
||||
pkt.header.response_code,
|
||||
name_server,
|
||||
domain
|
||||
));
|
||||
}
|
||||
if pkt.answers.len() == 0 {
|
||||
return Err(anyhow::anyhow!(
|
||||
"No records received DNS {:?} domain {:?}",
|
||||
name_server,
|
||||
domain
|
||||
));
|
||||
}
|
||||
|
||||
Ok(pkt)
|
||||
}
|
||||
|
||||
pub fn txt_dns(domain: &str, name_server: String) -> anyhow::Result<Vec<SocketAddr>> {
|
||||
let name_server: SocketAddr = name_server.parse()?;
|
||||
let udp = bind_udp(name_server)?;
|
||||
let mut buf = [0; 65536];
|
||||
let message = query(&udp, domain, name_server, QueryType::TXT, &mut buf)?;
|
||||
let mut rs = Vec::new();
|
||||
for record in message.answers {
|
||||
if let RData::TXT(txt) = record.data {
|
||||
for x in txt.iter() {
|
||||
let txt = std::str::from_utf8(x).context("record type txt is not string")?;
|
||||
let addr = SocketAddr::from_str(&txt.to_string())
|
||||
.context("record type txt is not SocketAddr")?;
|
||||
rs.push(addr);
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(rs)
|
||||
}
|
||||
|
||||
fn bind_udp(name_server: SocketAddr) -> anyhow::Result<UdpSocket> {
|
||||
let udp = if name_server.is_ipv4() {
|
||||
UdpSocket::bind("0.0.0.0:0")?
|
||||
} else {
|
||||
UdpSocket::bind("[::]:0")?
|
||||
};
|
||||
udp.set_read_timeout(Some(Duration::from_millis(800)))?;
|
||||
Ok(udp)
|
||||
}
|
||||
|
||||
pub fn a_dns(domain: String, name_server: String) -> anyhow::Result<Vec<Ipv4Addr>> {
|
||||
let name_server: SocketAddr = name_server.parse()?;
|
||||
let udp = bind_udp(name_server)?;
|
||||
let mut buf = [0; 65536];
|
||||
let message = query(&udp, &domain, name_server, QueryType::A, &mut buf)?;
|
||||
let mut rs = Vec::new();
|
||||
for record in message.answers {
|
||||
if let RData::A(a) = record.data {
|
||||
rs.push(a.0);
|
||||
}
|
||||
}
|
||||
Ok(rs)
|
||||
}
|
||||
|
||||
pub fn aaaa_dns(domain: String, name_server: String) -> anyhow::Result<Vec<Ipv6Addr>> {
|
||||
let name_server: SocketAddr = name_server.parse()?;
|
||||
let udp = bind_udp(name_server)?;
|
||||
let mut buf = [0; 65536];
|
||||
let message = query(&udp, &domain, name_server, QueryType::AAAA, &mut buf)?;
|
||||
let mut rs = Vec::new();
|
||||
for record in message.answers {
|
||||
if let RData::AAAA(a) = record.data {
|
||||
rs.push(a.0);
|
||||
}
|
||||
}
|
||||
Ok(rs)
|
||||
}
|
||||
@@ -7,3 +7,6 @@ pub use scheduler::Scheduler;
|
||||
|
||||
mod counter;
|
||||
pub use counter::*;
|
||||
|
||||
mod dns_query;
|
||||
pub use dns_query::*;
|
||||
|
||||
Reference in New Issue
Block a user