Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ff4580b9bf | ||
|
|
6daa75d2f2 | ||
|
|
59f07f2d75 | ||
|
|
44035685c8 | ||
|
|
c8d0f3850f | ||
|
|
b846f54d79 | ||
|
|
bb7b1d23af | ||
|
|
9e700b3094 | ||
|
|
38f28e313c | ||
|
|
63f03fb11f | ||
|
|
cf7854906f | ||
|
|
78ae5f3036 | ||
|
|
c412a256b8 | ||
|
|
94def558fc | ||
|
|
25e9c523d3 | ||
|
|
a009d06000 | ||
|
|
675e0c52ff | ||
|
|
dc4219753a | ||
|
|
c003b9acbb | ||
|
|
f4869ebd1d | ||
|
|
de4f42537d | ||
|
|
b9ebe80ef3 | ||
|
|
ea5ba750d4 | ||
|
|
b594afce16 | ||
|
|
ed3c44d6cf | ||
|
|
35ed7f7e45 | ||
|
|
068580e036 | ||
|
|
ea61b06e58 | ||
|
|
f260c26e4f | ||
|
|
9cea433a8b | ||
|
|
38dce9c13b | ||
|
|
04731f1ce5 | ||
|
|
3ddcb629c0 | ||
|
|
12bd058152 | ||
|
|
c9b1bf5a5e | ||
|
|
18df3c2c92 | ||
|
|
c08b9cefe9 | ||
|
|
258a35740f | ||
|
|
32cfe9a3a8 | ||
|
|
930a4fcf29 | ||
|
|
5a778d5fc3 | ||
|
|
1d64cfc930 | ||
|
|
3eab02bc68 | ||
|
|
dcdd03b746 | ||
|
|
51acb2da9b | ||
|
|
0d2c107e20 | ||
|
|
2089ba7997 | ||
|
|
8a032f86d8 | ||
|
|
5dcda4d088 | ||
|
|
8d76214193 |
@@ -0,0 +1,154 @@
|
|||||||
|
name: Rust
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags:
|
||||||
|
- '*'
|
||||||
|
|
||||||
|
env:
|
||||||
|
CARGO_TERM_COLOR: always
|
||||||
|
|
||||||
|
defaults:
|
||||||
|
run:
|
||||||
|
# necessary for windows
|
||||||
|
shell: bash
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
# test:
|
||||||
|
# runs-on: ubuntu-latest
|
||||||
|
# steps:
|
||||||
|
# - uses: actions/checkout@v2
|
||||||
|
# - name: Init submodules
|
||||||
|
# uses: snickerbockers/submodules-init@v4
|
||||||
|
# - name: Cargo cache
|
||||||
|
# uses: actions/cache@v2
|
||||||
|
# with:
|
||||||
|
# path: |
|
||||||
|
# ~/.cargo/registry
|
||||||
|
# ./target
|
||||||
|
# key: test-cargo-registry
|
||||||
|
# - name: List
|
||||||
|
# run: find ./
|
||||||
|
# - name: Run tests
|
||||||
|
# run: cargo test --verbose
|
||||||
|
|
||||||
|
build:
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
# a list of all the targets
|
||||||
|
include:
|
||||||
|
- TARGET: i686-unknown-linux-musl # test in an alpine container on a mac
|
||||||
|
OS: ubuntu-latest
|
||||||
|
- TARGET: x86_64-unknown-linux-gnu # tested in a debian container on a mac
|
||||||
|
OS: ubuntu-latest
|
||||||
|
- TARGET: x86_64-unknown-linux-musl # test in an alpine container on a mac
|
||||||
|
OS: ubuntu-latest
|
||||||
|
- TARGET: aarch64-unknown-linux-gnu # tested on aws t4g.nano
|
||||||
|
OS: ubuntu-latest
|
||||||
|
- TARGET: aarch64-unknown-linux-musl # tested on aws t4g.nano in alpine container
|
||||||
|
OS: ubuntu-latest
|
||||||
|
- TARGET: armv7-unknown-linux-gnueabihf # raspberry pi 2-3-4, not tested
|
||||||
|
OS: ubuntu-latest
|
||||||
|
- TARGET: armv7-unknown-linux-musleabihf # raspberry pi 2-3-4, not tested
|
||||||
|
OS: ubuntu-latest
|
||||||
|
- TARGET: arm-unknown-linux-gnueabihf # raspberry pi 0-1, not tested
|
||||||
|
OS: ubuntu-latest
|
||||||
|
- TARGET: arm-unknown-linux-musleabihf # raspberry pi 0-1, not tested
|
||||||
|
OS: ubuntu-latest
|
||||||
|
- TARGET: x86_64-apple-darwin # tested on a mac, is not properly signed so there are security warnings
|
||||||
|
OS: macos-latest
|
||||||
|
- TARGET: i686-pc-windows-msvc # tested on a windows machine
|
||||||
|
OS: windows-latest
|
||||||
|
- TARGET: x86_64-pc-windows-msvc # tested on a windows machine
|
||||||
|
OS: windows-latest
|
||||||
|
# needs: test
|
||||||
|
runs-on: ${{ matrix.OS }}
|
||||||
|
env:
|
||||||
|
NAME: switch-desktop # change with the name of your project
|
||||||
|
TARGET: ${{ matrix.TARGET }}
|
||||||
|
OS: ${{ matrix.OS }}
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- name: Init submodules
|
||||||
|
uses: snickerbockers/submodules-init@v4
|
||||||
|
- name: Cargo cache
|
||||||
|
uses: actions/cache@v2
|
||||||
|
with:
|
||||||
|
path: |
|
||||||
|
~/.cargo/registry
|
||||||
|
./target
|
||||||
|
key: build-cargo-registry-${{matrix.TARGET}}
|
||||||
|
- name: List
|
||||||
|
run: find ./
|
||||||
|
- name: Install and configure dependencies
|
||||||
|
run: |
|
||||||
|
# dependencies are only needed on ubuntu as that's the only place where
|
||||||
|
# we make cross-compilation
|
||||||
|
if [[ $OS =~ ^ubuntu.*$ ]]; then
|
||||||
|
sudo apt-get update && sudo apt-get install -qq crossbuild-essential-arm64 crossbuild-essential-armhf
|
||||||
|
fi
|
||||||
|
# some additional configuration for cross-compilation on linux
|
||||||
|
cat >>~/.cargo/config <<EOF
|
||||||
|
[target.aarch64-unknown-linux-gnu]
|
||||||
|
linker = "aarch64-linux-gnu-gcc"
|
||||||
|
[target.aarch64-unknown-linux-musl]
|
||||||
|
linker = "aarch64-linux-gnu-gcc"
|
||||||
|
[target.armv7-unknown-linux-gnueabihf]
|
||||||
|
linker = "arm-linux-gnueabihf-gcc"
|
||||||
|
[target.armv7-unknown-linux-musleabihf]
|
||||||
|
linker = "arm-linux-gnueabihf-gcc"
|
||||||
|
[target.arm-unknown-linux-gnueabihf]
|
||||||
|
linker = "arm-linux-gnueabihf-gcc"
|
||||||
|
[target.arm-unknown-linux-musleabihf]
|
||||||
|
linker = "arm-linux-gnueabihf-gcc"
|
||||||
|
EOF
|
||||||
|
- name: Install rust target
|
||||||
|
run: rustup target add $TARGET
|
||||||
|
- name: Run build
|
||||||
|
run: cargo build --package switch-desktop --release --verbose --target $TARGET
|
||||||
|
- name: List target
|
||||||
|
run: find ./target
|
||||||
|
- name: Compress
|
||||||
|
run: |
|
||||||
|
mkdir -p ./artifacts
|
||||||
|
# windows is the only OS using a different convention for executable file name
|
||||||
|
if [[ $OS =~ ^windows.*$ ]]; then
|
||||||
|
EXEC=$NAME.exe
|
||||||
|
else
|
||||||
|
EXEC=$NAME
|
||||||
|
fi
|
||||||
|
if [[ $GITHUB_REF_TYPE =~ ^tag$ ]]; then
|
||||||
|
TAG=$GITHUB_REF_NAME
|
||||||
|
else
|
||||||
|
TAG=$GITHUB_SHA
|
||||||
|
fi
|
||||||
|
mv ./target/$TARGET/release/$EXEC ./$EXEC
|
||||||
|
tar -czf ./artifacts/$NAME-$TARGET-$TAG.tar.gz $EXEC
|
||||||
|
- name: Archive artifact
|
||||||
|
uses: actions/upload-artifact@v2
|
||||||
|
with:
|
||||||
|
name: switch-desktop
|
||||||
|
path: |
|
||||||
|
./artifacts
|
||||||
|
# deploys to github releases on tag
|
||||||
|
deploy:
|
||||||
|
if: startsWith(github.ref, 'refs/tags/')
|
||||||
|
needs: build
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Download artifacts
|
||||||
|
uses: actions/download-artifact@v2
|
||||||
|
with:
|
||||||
|
name: switch-desktop
|
||||||
|
path: ./artifacts
|
||||||
|
- name: List
|
||||||
|
run: find ./artifacts
|
||||||
|
- name: Release
|
||||||
|
uses: svenstaro/upload-release-action@v2
|
||||||
|
with:
|
||||||
|
repo_token: ${{ secrets.YOURTOKEN }}
|
||||||
|
file: ./artifacts/*.tar.gz
|
||||||
|
tag: ${{ github.ref }}
|
||||||
|
overwrite: true
|
||||||
|
file_glob: true
|
||||||
+1
-1
@@ -1,3 +1,3 @@
|
|||||||
[submodule "switch/p2p_channel"]
|
[submodule "switch/p2p_channel"]
|
||||||
path = switch/p2p_channel
|
path = switch/p2p_channel
|
||||||
url = git@github.com:lbl8603/p2p_channel.git
|
url = https://github.com/lbl8603/p2p_channel
|
||||||
|
|||||||
+13
-1
@@ -1,2 +1,14 @@
|
|||||||
[workspace]
|
[workspace]
|
||||||
members = ["switch","switch-desktop","switch-jni"]
|
members = ["switch","switch-desktop"]
|
||||||
|
|
||||||
|
[profile.release]
|
||||||
|
opt-level = 'z'
|
||||||
|
debug = 0
|
||||||
|
debug-assertions = false
|
||||||
|
strip= "debuginfo"
|
||||||
|
overflow-checks = true
|
||||||
|
lto = true
|
||||||
|
panic = 'abort'
|
||||||
|
incremental = false
|
||||||
|
codegen-units = 1
|
||||||
|
rpath = false
|
||||||
|
|||||||
@@ -4,13 +4,13 @@
|
|||||||
将不同网络下的多个设备虚拟到一个局域网下
|
将不同网络下的多个设备虚拟到一个局域网下
|
||||||
|
|
||||||
|
|
||||||
### 示例:
|
### 快速使用:
|
||||||
|
|
||||||
1. 指定一个token,在多台设备上运行该程序,例如:
|
1. 指定一个token,在多台设备上运行该程序,例如:
|
||||||
```shell
|
```shell
|
||||||
# linux上
|
# linux上
|
||||||
root@DESKTOP-0BCHNIO:/opt# ./switch-desktop start --token 123456
|
root@DESKTOP-0BCHNIO:/opt# ./switch-desktop start --token 123456
|
||||||
# 在另一台linux上使用nohup后台运行,不在命令行指定配置时,将在home/.switch/config文件中读取配置
|
# 在另一台linux上使用nohup后台运行,不在命令行指定配置时,将在home/.switch_desktop/config文件中读取配置
|
||||||
[root@izj6cemne76ykdzkataftfz switch]# nohup ./switch-desktop start &
|
[root@izj6cemne76ykdzkataftfz switch]# nohup ./switch-desktop start &
|
||||||
# windows上
|
# windows上
|
||||||
D:\switch\bin_v1>switch-desktop.exe start --token 123456
|
D:\switch\bin_v1>switch-desktop.exe start --token 123456
|
||||||
@@ -42,12 +42,14 @@
|
|||||||
2. ssh
|
2. ssh
|
||||||
|
|
||||||
<img width="506" alt="ssh" src="https://raw.githubusercontent.com/lbl8603/switch/dev/documents/img/ssh.jpg">
|
<img width="506" alt="ssh" src="https://raw.githubusercontent.com/lbl8603/switch/dev/documents/img/ssh.jpg">
|
||||||
|
5. 帮助,使用-h命令查看
|
||||||
|
|
||||||
### 更多玩法
|
### 更多玩法
|
||||||
|
|
||||||
1. 和远程桌面(如mstsc)搭配,超低延迟的体验
|
1. 和远程桌面(如mstsc)搭配,超低延迟的体验
|
||||||
2. 安装samba服务,共享磁盘
|
2. 安装samba服务,共享磁盘
|
||||||
3. 搭配公网服务器nginx反向代理,在公网访问本地文件
|
3. 搭配公网服务器nginx反向代理,在公网访问本地文件
|
||||||
|
4. 点对网(结合启动参数'--in-ip'和'--out-ip')
|
||||||
|
|
||||||
|
|
||||||
### 使用须知
|
### 使用须知
|
||||||
@@ -67,17 +69,28 @@
|
|||||||
- Mac
|
- Mac
|
||||||
- Linux
|
- Linux
|
||||||
- Windows
|
- Windows
|
||||||
- 依赖 wintun.dll(https://www.wintun.net/)
|
- 使用tun网卡 依赖wintun.dll(https://www.wintun.net/)
|
||||||
|
- 使用tap网卡 依赖tap-windows(https://build.openvpn.net/downloads/releases/)
|
||||||
|
|
||||||
### 特性
|
### 特性
|
||||||
- IP层数据转发
|
- IP层数据转发
|
||||||
- tun虚拟网卡
|
- tun虚拟网卡
|
||||||
|
- tap虚拟网卡
|
||||||
- NAT穿透
|
- NAT穿透
|
||||||
- 点对点穿透
|
- 点对点穿透
|
||||||
- 服务端中继转发
|
- 服务端中继转发
|
||||||
- 客户端中继转发
|
- 客户端中继转发
|
||||||
|
- IP代理
|
||||||
|
|
||||||
### Todo
|
### Todo
|
||||||
- 支持安卓
|
- 支持安卓
|
||||||
- 数据加密
|
- 数据加密
|
||||||
|
|
||||||
|
### 常见问题
|
||||||
|
#### 问题1: 设置网络地址失败
|
||||||
|
##### 可能原因:
|
||||||
|
switch默认使用10.26.0.0/24网段,和本地网络适配器的ip冲突
|
||||||
|
##### 解决方法:
|
||||||
|
1. 方法一:找到冲突的IP,将其改成别的
|
||||||
|
2. 方法二:自建服务器,指定其他不会冲突的网段
|
||||||
|
3. 方法三:增加参数--device-id,设置不同的id会让switch-server分配不同的IP,从而绕开有冲突的IP
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "switch-desktop"
|
name = "switch-desktop"
|
||||||
version = "0.1.0"
|
version = "1.0.5"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
@@ -13,7 +13,7 @@ console = "0.15.2"
|
|||||||
dirs = "4.0.0"
|
dirs = "4.0.0"
|
||||||
log = "0.4.17"
|
log = "0.4.17"
|
||||||
log4rs = "1.2.0"
|
log4rs = "1.2.0"
|
||||||
#tokio = { version = "1.24.1", features = ["full"] }
|
tokio = { version = "1.28.1", features = ["full"] }
|
||||||
chrono = "0.4.23"
|
chrono = "0.4.23"
|
||||||
|
|
||||||
serde = "1.0"
|
serde = "1.0"
|
||||||
@@ -28,9 +28,10 @@ fs2 = "0.4.3"
|
|||||||
os_info = "3.5.1"
|
os_info = "3.5.1"
|
||||||
[target.'cfg(any(target_os = "linux",target_os = "macos"))'.dependencies]
|
[target.'cfg(any(target_os = "linux",target_os = "macos"))'.dependencies]
|
||||||
sudo = "0.6.0"
|
sudo = "0.6.0"
|
||||||
|
libc = "0.2"
|
||||||
|
|
||||||
[target.'cfg(target_os = "windows")'.dependencies]
|
[target.'cfg(target_os = "windows")'.dependencies]
|
||||||
winapi = { version = "0.3.9", features = ["handleapi", "processthreadsapi", "winnt", "securitybaseapi", "impl-default"] }
|
winapi = { version = "0.3.9", features = ["handleapi", "processthreadsapi", "winnt", "securitybaseapi", "impl-default"] }
|
||||||
#runas = "0.2.1"
|
#runas = "0.2.1"
|
||||||
windows-service = "0.5.0"
|
windows-service = "0.6.0"
|
||||||
|
|
||||||
|
|||||||
@@ -1,22 +1,17 @@
|
|||||||
use std::io;
|
use std::io;
|
||||||
use crate::config::SWITCH_HOME_PATH;
|
use std::path::PathBuf;
|
||||||
|
use crate::config::get_home;
|
||||||
|
|
||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
pub fn log_service_init() -> io::Result<()> {
|
pub fn log_service_init() -> io::Result<()> {
|
||||||
log_init_("switch-service.log")
|
log_init_(crate::config::get_win_server_home().join("switch-service.log"))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn log_init() -> io::Result<()> {
|
pub fn log_init() -> io::Result<()> {
|
||||||
log_init_("switch.log")
|
log_init_(get_home().join("switch-desktop.log"))
|
||||||
}
|
}
|
||||||
pub fn log_init_(file_name:&str) -> io::Result<()> {
|
|
||||||
let home = SWITCH_HOME_PATH.lock().clone();
|
fn log_init_(file_name: PathBuf) -> io::Result<()> {
|
||||||
let home = if let Some(home) = home {
|
|
||||||
home
|
|
||||||
} else {
|
|
||||||
return Err(io::Error::new(io::ErrorKind::Other, "not found"));
|
|
||||||
};
|
|
||||||
if !home.exists() {
|
|
||||||
std::fs::create_dir(&home)?;
|
|
||||||
}
|
|
||||||
let stderr = log4rs::append::console::ConsoleAppender::builder()
|
let stderr = log4rs::append::console::ConsoleAppender::builder()
|
||||||
.target(log4rs::append::console::Target::Stderr)
|
.target(log4rs::append::console::Target::Stderr)
|
||||||
.build();
|
.build();
|
||||||
@@ -25,7 +20,7 @@ pub fn log_init_(file_name:&str) -> io::Result<()> {
|
|||||||
.encoder(Box::new(log4rs::encode::pattern::PatternEncoder::new(
|
.encoder(Box::new(log4rs::encode::pattern::PatternEncoder::new(
|
||||||
"{d(%+)(utc)} [{f}:{L}] {h({l})} {M}:{m}{n}\n",
|
"{d(%+)(utc)} [{f}:{L}] {h({l})} {M}:{m}{n}\n",
|
||||||
)))
|
)))
|
||||||
.build(home.join(file_name))?;
|
.build(file_name)?;
|
||||||
match log4rs::Config::builder()
|
match log4rs::Config::builder()
|
||||||
.appender(log4rs::config::Appender::builder().build("logfile", Box::new(logfile)))
|
.appender(log4rs::config::Appender::builder().build("logfile", Box::new(logfile)))
|
||||||
.appender(
|
.appender(
|
||||||
@@ -47,4 +42,4 @@ pub fn log_init_(file_name:&str) -> io::Result<()> {
|
|||||||
Err(_) => {}
|
Err(_) => {}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
+343
-103
@@ -1,7 +1,7 @@
|
|||||||
use std::fs::{File, OpenOptions};
|
use std::fs::{File, OpenOptions};
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::io::{Read, Write};
|
use std::io::{Read, Write};
|
||||||
use std::net::{SocketAddr, ToSocketAddrs};
|
use std::net::{Ipv4Addr, SocketAddr, ToSocketAddrs};
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
@@ -11,33 +11,107 @@ use serde::{Deserialize, Serialize};
|
|||||||
use crate::StartArgs;
|
use crate::StartArgs;
|
||||||
|
|
||||||
pub mod log_config;
|
pub mod log_config;
|
||||||
|
lazy_static! {
|
||||||
|
pub static ref SWITCH_HOME_PATH: Mutex<Option<PathBuf>> = Mutex::new(None);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(windows)]
|
||||||
|
pub fn get_win_server_home() -> PathBuf {
|
||||||
|
SWITCH_HOME_PATH.lock().as_ref().unwrap().clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(windows)]
|
||||||
|
pub fn set_win_server_home(home: PathBuf) {
|
||||||
|
let _ = SWITCH_HOME_PATH.lock().insert(home);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone,Debug)]
|
||||||
pub struct StartConfig {
|
pub struct StartConfig {
|
||||||
|
pub tap: bool,
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub token: String,
|
pub token: String,
|
||||||
pub server: SocketAddr,
|
pub server: SocketAddr,
|
||||||
pub nat_test_server: Vec<SocketAddr>,
|
pub nat_test_server: Vec<SocketAddr>,
|
||||||
pub device_id: String,
|
pub device_id: String,
|
||||||
|
pub in_ips: Vec<(u32, u32, Ipv4Addr)>,
|
||||||
|
pub out_ips: Vec<(u32, u32, Ipv4Addr)>,
|
||||||
|
#[cfg(any(unix))]
|
||||||
|
pub off_command_server: bool,
|
||||||
|
pub log: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ips_parse(ips: &Vec<String>) -> Result<Vec<(u32, u32, Ipv4Addr)>, String> {
|
||||||
|
let mut in_ips_c = vec![];
|
||||||
|
for x in ips {
|
||||||
|
let mut split = x.split(",");
|
||||||
|
let net = if let Some(net) = split.next() {
|
||||||
|
net
|
||||||
|
} else {
|
||||||
|
return Err("参数错误".to_string());
|
||||||
|
};
|
||||||
|
let ip = if let Some(ip) = split.next() {
|
||||||
|
ip
|
||||||
|
} else {
|
||||||
|
return Err("参数错误".to_string());
|
||||||
|
};
|
||||||
|
let ip = if let Ok(ip) = ip.parse::<Ipv4Addr>() {
|
||||||
|
ip
|
||||||
|
} else {
|
||||||
|
return Err("参数错误".to_string());
|
||||||
|
};
|
||||||
|
let mut split = net.split("/");
|
||||||
|
let dest = if let Some(dest) = split.next() {
|
||||||
|
dest
|
||||||
|
} else {
|
||||||
|
return Err("参数错误".to_string());
|
||||||
|
};
|
||||||
|
let mask = if let Some(mask) = split.next() {
|
||||||
|
mask
|
||||||
|
} else {
|
||||||
|
return Err("参数错误".to_string());
|
||||||
|
};
|
||||||
|
let dest = if let Ok(dest) = dest.parse::<Ipv4Addr>() {
|
||||||
|
dest
|
||||||
|
} else {
|
||||||
|
return Err("参数错误".to_string());
|
||||||
|
};
|
||||||
|
let mask = if let Ok(m) = mask.parse::<u32>() {
|
||||||
|
let mut mask = 0 as u32;
|
||||||
|
for i in 0..m {
|
||||||
|
mask = mask | (1 << (31 - i));
|
||||||
|
}
|
||||||
|
mask
|
||||||
|
} else {
|
||||||
|
return Err("参数错误".to_string());
|
||||||
|
};
|
||||||
|
in_ips_c.push((u32::from_be_bytes(dest.octets()), mask, ip));
|
||||||
|
}
|
||||||
|
Ok(in_ips_c)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn default_config(start_args: StartArgs) -> Result<StartConfig, String> {
|
pub fn default_config(start_args: StartArgs) -> Result<StartConfig, String> {
|
||||||
let args_config = read_config();
|
println!("========参数配置========");
|
||||||
if args_config.is_none() && start_args.token.is_none() {
|
if start_args.log {
|
||||||
|
println!("print log");
|
||||||
|
}
|
||||||
|
let tap = start_args.tap;
|
||||||
|
if tap {
|
||||||
|
println!("use tap");
|
||||||
|
} else {
|
||||||
|
println!("use tun");
|
||||||
|
}
|
||||||
|
if start_args.token.is_none() {
|
||||||
return Err("找不到token(Token not found)".to_string());
|
return Err("找不到token(Token not found)".to_string());
|
||||||
}
|
}
|
||||||
let token = start_args.token.unwrap_or_else(|| args_config.as_ref().unwrap().token.clone()).trim().to_string();
|
let token = start_args.token.unwrap();
|
||||||
if token.is_empty() {
|
if token.is_empty() {
|
||||||
return Err("token不能为空(Token cannot be empty)".to_string());
|
return Err("token不能为空(Token cannot be empty)".to_string());
|
||||||
}
|
}
|
||||||
if token.len() > 64 {
|
if token.len() > 64 {
|
||||||
return Err("token不能超过64字符(Token cannot exceed 64 characters)".to_string());
|
return Err("token不能超过64字符(Token cannot exceed 64 characters)".to_string());
|
||||||
}
|
}
|
||||||
|
println!("token:{:?}", token);
|
||||||
let name = start_args.name.unwrap_or_else(|| {
|
let name = start_args.name.unwrap_or_else(|| {
|
||||||
if let Some(c) = &args_config {
|
|
||||||
if !c.name.is_empty() {
|
|
||||||
return c.name.clone();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
os_info::get().to_string()
|
os_info::get().to_string()
|
||||||
});
|
});
|
||||||
let name = name.trim();
|
let name = name.trim();
|
||||||
@@ -46,12 +120,8 @@ pub fn default_config(start_args: StartArgs) -> Result<StartConfig, String> {
|
|||||||
} else {
|
} else {
|
||||||
name.to_string()
|
name.to_string()
|
||||||
};
|
};
|
||||||
|
println!("name:{:?}", name);
|
||||||
let device_id = start_args.device_id.unwrap_or_else(|| {
|
let device_id = start_args.device_id.unwrap_or_else(|| {
|
||||||
if let Some(c) = &args_config {
|
|
||||||
if !c.device_id.is_empty() {
|
|
||||||
return c.device_id.clone();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if let Ok(Some(mac_address)) = mac_address::get_mac_address() {
|
if let Ok(Some(mac_address)) = mac_address::get_mac_address() {
|
||||||
mac_address.to_string()
|
mac_address.to_string()
|
||||||
} else {
|
} else {
|
||||||
@@ -61,12 +131,28 @@ pub fn default_config(start_args: StartArgs) -> Result<StartConfig, String> {
|
|||||||
if device_id.is_empty() || device_id.len() > 64 {
|
if device_id.is_empty() || device_id.len() > 64 {
|
||||||
return Err("设备id不能为空并且长度不能大于64字符(The device id cannot be empty and the length cannot be greater than 64 characters)".to_string());
|
return Err("设备id不能为空并且长度不能大于64字符(The device id cannot be empty and the length cannot be greater than 64 characters)".to_string());
|
||||||
}
|
}
|
||||||
|
println!("device_id:{:?}", device_id);
|
||||||
|
let in_ips = start_args.in_ip.unwrap_or_else(|| {
|
||||||
|
vec![]
|
||||||
|
});
|
||||||
|
let out_ips = start_args.out_ip.unwrap_or_else(|| {
|
||||||
|
vec![]
|
||||||
|
});
|
||||||
|
println!("in_ips:{:?}", in_ips);
|
||||||
|
let in_ips_c = if let Ok(in_ips_c) = ips_parse(&in_ips) {
|
||||||
|
in_ips_c
|
||||||
|
} else {
|
||||||
|
return Err("in_ips 参数错误 示例:--in_ip 192.168.10.0/24,10.26.0.3".to_string());
|
||||||
|
};
|
||||||
|
println!("out_ips:{:?}", out_ips);
|
||||||
|
let out_ips_c = if let Ok(out_ips_c) = ips_parse(&out_ips) {
|
||||||
|
out_ips_c
|
||||||
|
} else {
|
||||||
|
return Err("out_ips 参数错误 示例:--out_ip 192.168.10.0/24,192.168.0.5".to_string());
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
let server = match start_args.server.unwrap_or_else(|| {
|
let server = match start_args.server.unwrap_or_else(|| {
|
||||||
if let Some(c) = &args_config {
|
|
||||||
if !c.server.is_empty() {
|
|
||||||
return c.server.clone();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"nat1.wherewego.top:29871".to_string()
|
"nat1.wherewego.top:29871".to_string()
|
||||||
}).to_socket_addrs() {
|
}).to_socket_addrs() {
|
||||||
Ok(mut server) => {
|
Ok(mut server) => {
|
||||||
@@ -80,50 +166,210 @@ pub fn default_config(start_args: StartArgs) -> Result<StartConfig, String> {
|
|||||||
return Err(format!("中继服务器地址错误( Relay server address error) :{:?}", e));
|
return Err(format!("中继服务器地址错误( Relay server address error) :{:?}", e));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
println!("中继服务器:{:?}", server);
|
||||||
let nat_test_server = start_args.nat_test_server.unwrap_or_else(|| {
|
let nat_test_server = start_args.nat_test_server.unwrap_or_else(|| {
|
||||||
if let Some(c) = &args_config {
|
|
||||||
if !c.nat_test_server.is_empty() {
|
|
||||||
return c.nat_test_server.join(",");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"nat1.wherewego.top:35061,nat1.wherewego.top:35062,nat2.wherewego.top:35061,nat2.wherewego.top:35062".to_string()
|
"nat1.wherewego.top:35061,nat1.wherewego.top:35062,nat2.wherewego.top:35061,nat2.wherewego.top:35062".to_string()
|
||||||
}).split(",").flat_map(|a| a.to_socket_addrs()).flatten()
|
}).split(",").flat_map(|a| a.to_socket_addrs()).flatten()
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
if nat_test_server.is_empty() {
|
if nat_test_server.is_empty() {
|
||||||
return Err("NAT检测服务地址错误(NAT detection service address error)".to_string());
|
return Err("NAT检测服务地址错误(NAT detection service address error)".to_string());
|
||||||
}
|
}
|
||||||
|
println!("NAT探测服务器:{:?}", nat_test_server);
|
||||||
let base_config = StartConfig {
|
let base_config = StartConfig {
|
||||||
|
tap,
|
||||||
name,
|
name,
|
||||||
token,
|
token,
|
||||||
server,
|
server,
|
||||||
nat_test_server,
|
nat_test_server,
|
||||||
device_id,
|
device_id,
|
||||||
|
in_ips: in_ips_c,
|
||||||
|
out_ips: out_ips_c,
|
||||||
|
#[cfg(any(unix))]
|
||||||
|
off_command_server: start_args.off_command_server,
|
||||||
|
log: start_args.log,
|
||||||
};
|
};
|
||||||
|
println!("========参数配置========");
|
||||||
Ok(base_config)
|
Ok(base_config)
|
||||||
}
|
}
|
||||||
|
|
||||||
lazy_static! {
|
pub fn read_config_file(config_path: PathBuf) -> Result<StartConfig, String> {
|
||||||
static ref CONFIG: Mutex<Option<ArgsConfig>> = Mutex::new(None);
|
println!("========读取配置文件========");
|
||||||
pub static ref SWITCH_HOME_PATH: Mutex<Option<PathBuf>> = Mutex::new(None);
|
let args_config = if let Ok(config) = read_config(config_path) {
|
||||||
|
config
|
||||||
|
} else {
|
||||||
|
return Err("读取配置文件失败".to_string());
|
||||||
|
};
|
||||||
|
let log = args_config.log;
|
||||||
|
if log {
|
||||||
|
println!("print log");
|
||||||
|
}
|
||||||
|
let tap = args_config.tap;
|
||||||
|
if tap {
|
||||||
|
println!("use tap");
|
||||||
|
} else {
|
||||||
|
println!("use tun");
|
||||||
|
}
|
||||||
|
let token = args_config.token;
|
||||||
|
if token.is_empty() {
|
||||||
|
return Err("token不能为空(Token cannot be empty)".to_string());
|
||||||
|
}
|
||||||
|
if token.len() > 64 {
|
||||||
|
return Err("token不能超过64字符(Token cannot exceed 64 characters)".to_string());
|
||||||
|
}
|
||||||
|
println!("token:{:?}", token);
|
||||||
|
let name = args_config.name;
|
||||||
|
let name = name.trim();
|
||||||
|
let name = if name.len() > 64 {
|
||||||
|
name[..64].to_string()
|
||||||
|
} else {
|
||||||
|
name.to_string()
|
||||||
|
};
|
||||||
|
println!("name:{:?}", name);
|
||||||
|
let device_id = if !args_config.device_id.is_empty() {
|
||||||
|
args_config.device_id
|
||||||
|
} else {
|
||||||
|
if let Ok(Some(mac_address)) = mac_address::get_mac_address() {
|
||||||
|
mac_address.to_string()
|
||||||
|
} else {
|
||||||
|
"".to_string()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if device_id.is_empty() || device_id.len() > 64 {
|
||||||
|
return Err("设备id不能为空并且长度不能大于64字符(The device id cannot be empty and the length cannot be greater than 64 characters)".to_string());
|
||||||
|
}
|
||||||
|
println!("device_id:{:?}", device_id);
|
||||||
|
let in_ips = args_config.in_ips;
|
||||||
|
let out_ips = args_config.out_ips;
|
||||||
|
println!("in_ips:{:?}", in_ips);
|
||||||
|
let in_ips_c = if let Ok(in_ips_c) = ips_parse(&in_ips) {
|
||||||
|
in_ips_c
|
||||||
|
} else {
|
||||||
|
return Err("in_ips 参数错误 示例:--in_ip 192.168.10.0/24,10.26.0.3".to_string());
|
||||||
|
};
|
||||||
|
println!("out_ips:{:?}", out_ips);
|
||||||
|
let out_ips_c = if let Ok(out_ips_c) = ips_parse(&out_ips) {
|
||||||
|
out_ips_c
|
||||||
|
} else {
|
||||||
|
return Err("out_ips 参数错误 示例:--out_ip 192.168.10.0/24,192.168.0.5".to_string());
|
||||||
|
};
|
||||||
|
let server = match {
|
||||||
|
if !args_config.server.is_empty() {
|
||||||
|
args_config.server
|
||||||
|
} else {
|
||||||
|
"nat1.wherewego.top:29871".to_string()
|
||||||
|
}
|
||||||
|
}.to_socket_addrs()
|
||||||
|
{
|
||||||
|
Ok(mut server) => {
|
||||||
|
if let Some(addr) = server.next() {
|
||||||
|
addr
|
||||||
|
} else {
|
||||||
|
return Err("中继服务器地址错误( Relay server address error)".to_string());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
return Err(format!("中继服务器地址错误( Relay server address error) :{:?}", e));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
println!("中继服务器:{:?}", server);
|
||||||
|
let nat_test_server = if args_config.nat_test_server.is_empty() {
|
||||||
|
vec!["nat1.wherewego.top:35061".to_string(), "nat1.wherewego.top:35062".to_string(), "nat2.wherewego.top:35061".to_string(), "nat2.wherewego.top:35062".to_string()]
|
||||||
|
} else {
|
||||||
|
args_config.nat_test_server
|
||||||
|
}.iter().flat_map(|a| a.to_socket_addrs()).flatten()
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
if nat_test_server.is_empty() {
|
||||||
|
return Err("NAT检测服务地址错误(NAT detection service address error)".to_string());
|
||||||
|
}
|
||||||
|
println!("NAT探测服务器:{:?}", nat_test_server);
|
||||||
|
let base_config = StartConfig {
|
||||||
|
tap,
|
||||||
|
name,
|
||||||
|
token,
|
||||||
|
server,
|
||||||
|
nat_test_server,
|
||||||
|
device_id,
|
||||||
|
in_ips: in_ips_c,
|
||||||
|
out_ips: out_ips_c,
|
||||||
|
#[cfg(any(unix))]
|
||||||
|
off_command_server: args_config.off_command_server,
|
||||||
|
log,
|
||||||
|
};
|
||||||
|
println!("========参数配置========");
|
||||||
|
Ok(base_config)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
|
pub struct RuntimeData {
|
||||||
|
#[serde(default = "default_pid")]
|
||||||
|
pub pid: u32,
|
||||||
|
pub command_port: Option<u16>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
pub struct ArgsConfig {
|
pub struct ArgsConfig {
|
||||||
|
#[serde(default = "default_false")]
|
||||||
|
pub tap: bool,
|
||||||
#[serde(default = "default_version")]
|
#[serde(default = "default_version")]
|
||||||
pub version: String,
|
pub version: String,
|
||||||
#[serde(default = "default_str")]
|
#[serde(default = "default_str")]
|
||||||
pub token: String,
|
pub token: String,
|
||||||
#[serde(default = "default_str")]
|
#[serde(default = "default_str")]
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub command_port: Option<u16>,
|
|
||||||
#[serde(default = "default_str")]
|
#[serde(default = "default_str")]
|
||||||
pub server: String,
|
pub server: String,
|
||||||
#[serde(default = "default_resource_vec")]
|
#[serde(default = "default_vec")]
|
||||||
pub nat_test_server: Vec<String>,
|
pub nat_test_server: Vec<String>,
|
||||||
#[serde(default = "default_str")]
|
#[serde(default = "default_str")]
|
||||||
pub device_id: String,
|
pub device_id: String,
|
||||||
#[serde(default = "default_pid")]
|
#[serde(default = "default_vec")]
|
||||||
pub pid: u32,
|
pub in_ips: Vec<String>,
|
||||||
|
#[serde(default = "default_vec")]
|
||||||
|
pub out_ips: Vec<String>,
|
||||||
|
#[cfg(any(unix))]
|
||||||
|
#[serde(default = "default_false")]
|
||||||
|
pub off_command_server: bool,
|
||||||
|
#[serde(default = "default_false")]
|
||||||
|
pub log: bool,
|
||||||
|
}
|
||||||
|
#[cfg(windows)]
|
||||||
|
impl ArgsConfig {
|
||||||
|
pub fn new(start_config: StartConfig) -> ArgsConfig {
|
||||||
|
let in_ips = start_config.in_ips.iter().map(|(ip, mask, dest)| {
|
||||||
|
format!("{}/{},{}", Ipv4Addr::from(*ip), subnet_mask_to_integer(*mask), dest)
|
||||||
|
}).collect::<Vec<String>>();
|
||||||
|
let out_ips = start_config.out_ips.iter().map(|(ip, mask, dest)| {
|
||||||
|
format!("{}/{},{}", Ipv4Addr::from(*ip), subnet_mask_to_integer(*mask), dest)
|
||||||
|
}).collect::<Vec<String>>();
|
||||||
|
ArgsConfig {
|
||||||
|
tap: start_config.tap,
|
||||||
|
version: "1.0.5".to_string(),
|
||||||
|
token: start_config.token.to_string(),
|
||||||
|
name: start_config.name.to_string(),
|
||||||
|
server: start_config.server.to_string(),
|
||||||
|
nat_test_server: start_config.nat_test_server.iter().map(|v| v.to_string()).collect(),
|
||||||
|
device_id: start_config.device_id,
|
||||||
|
in_ips,
|
||||||
|
out_ips,
|
||||||
|
log: start_config.log,
|
||||||
|
#[cfg(any(unix))]
|
||||||
|
off_command_server: start_config.off_command_server,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[cfg(windows)]
|
||||||
|
fn subnet_mask_to_integer(subnet_mask: u32) -> u8 {
|
||||||
|
let mut mask_bits = subnet_mask;
|
||||||
|
let mut num_bits = 0;
|
||||||
|
while mask_bits != 0 {
|
||||||
|
num_bits += 1;
|
||||||
|
mask_bits <<= 1;
|
||||||
|
}
|
||||||
|
num_bits as u8
|
||||||
|
}
|
||||||
|
|
||||||
|
fn default_false() -> bool {
|
||||||
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
fn default_version() -> String {
|
fn default_version() -> String {
|
||||||
@@ -134,7 +380,7 @@ fn default_str() -> String {
|
|||||||
"".to_string()
|
"".to_string()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn default_resource_vec() -> Vec<String> {
|
fn default_vec() -> Vec<String> {
|
||||||
vec![]
|
vec![]
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -142,74 +388,61 @@ fn default_pid() -> u32 {
|
|||||||
0
|
0
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ArgsConfig {
|
// impl ArgsConfig {
|
||||||
pub fn new(token: String, name: String, server: String, nat_test_server: Vec<String>, device_id: String) -> Self {
|
// pub fn new(tap: bool, token: String, name: String, server: SocketAddr,
|
||||||
Self {
|
// nat_test_server: &Vec<SocketAddr>, device_id: String,
|
||||||
version: "1.0".to_string(),
|
// in_ips: Vec<(u32, u32, Ipv4Addr)>, out_ips: Vec<(u32, u32, Ipv4Addr)>, ) -> Self {
|
||||||
token,
|
//
|
||||||
name,
|
// Self {
|
||||||
command_port: None,
|
// tap,
|
||||||
server,
|
// version: "1.0".to_string(),
|
||||||
nat_test_server,
|
// token,
|
||||||
device_id,
|
// name,
|
||||||
pid: 0,
|
// command_port: None,
|
||||||
}
|
// server: server.to_string(),
|
||||||
}
|
// nat_test_server: nat_test_server.iter().map(|v| v.to_string()).collect::<Vec<String>>(),
|
||||||
}
|
// device_id,
|
||||||
|
// pid: 0,
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
pub fn lock_file() -> io::Result<File> {
|
pub fn lock_file() -> io::Result<File> {
|
||||||
let path = SWITCH_HOME_PATH.lock().clone().unwrap().join(".lock");
|
let path = get_home().join(".lock");
|
||||||
Ok(File::create(path)?)
|
let file = File::create(path)?;
|
||||||
|
file.sync_all()?;
|
||||||
|
Ok(file)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn save_config(config: ArgsConfig) -> io::Result<()> {
|
|
||||||
let config_path = SWITCH_HOME_PATH.lock().clone().unwrap().join("config");
|
|
||||||
save_config_(config, config_path)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn save_config_(config: ArgsConfig, config_path: PathBuf) -> io::Result<()> {
|
fn save_runtime_data(config: RuntimeData) -> io::Result<()> {
|
||||||
let mut config_lock = CONFIG.lock();
|
let config_path = get_runtime_data_path();
|
||||||
config_lock.take();
|
|
||||||
let str = serde_yaml::to_string(&config).unwrap();
|
let str = serde_yaml::to_string(&config).unwrap();
|
||||||
let mut file = File::create(config_path)?;
|
let mut file = File::create(config_path)?;
|
||||||
file.write_all(str.as_bytes())
|
file.write_all(str.as_bytes())?;
|
||||||
|
file.sync_all()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update_pid(pid: u32) -> io::Result<()> {
|
pub fn update_pid(pid: u32) -> io::Result<()> {
|
||||||
let home_lock = SWITCH_HOME_PATH.lock();
|
let mut config = read_runtime_data()?;
|
||||||
if let Some(home) = home_lock.clone() {
|
config.pid = pid;
|
||||||
drop(home_lock);
|
return save_runtime_data(config);
|
||||||
let config_path = home.join("config");
|
|
||||||
if let Some(mut config) = read_config() {
|
|
||||||
config.pid = pid;
|
|
||||||
return save_config_(config, config_path);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(io::Error::new(io::ErrorKind::Other, "not found"))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(unix))]
|
#[cfg(any(unix))]
|
||||||
pub fn read_pid() -> io::Result<u32> {
|
pub fn read_pid() -> io::Result<u32> {
|
||||||
let home = SWITCH_HOME_PATH.lock().clone().unwrap();
|
let config = read_runtime_data()?;
|
||||||
let config = read_config_(home)?;
|
|
||||||
Ok(config.pid)
|
Ok(config.pid)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update_command_port(port: u16) -> io::Result<()> {
|
pub fn update_command_port(port: u16) -> io::Result<()> {
|
||||||
let home_lock = SWITCH_HOME_PATH.lock();
|
let mut config = read_runtime_data()?;
|
||||||
if let Some(home) = home_lock.clone() {
|
config.command_port = Some(port);
|
||||||
drop(home_lock);
|
return save_runtime_data(config);
|
||||||
let config_path = home.join("config");
|
|
||||||
if let Some(mut config) = read_config() {
|
|
||||||
config.command_port = Some(port);
|
|
||||||
return save_config_(config, config_path);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(io::Error::new(io::ErrorKind::Other, "not found"))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn read_command_port() -> io::Result<u16> {
|
pub fn read_command_port() -> io::Result<u16> {
|
||||||
let home = SWITCH_HOME_PATH.lock().clone().unwrap();
|
let config = read_runtime_data()?;
|
||||||
let config = read_config_(home)?;
|
|
||||||
if let Some(p) = config.command_port {
|
if let Some(p) = config.command_port {
|
||||||
Ok(p)
|
Ok(p)
|
||||||
} else {
|
} else {
|
||||||
@@ -217,34 +450,28 @@ pub fn read_command_port() -> io::Result<u16> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn read_config() -> Option<ArgsConfig> {
|
|
||||||
let mut lock = CONFIG.lock();
|
pub fn get_home() -> PathBuf {
|
||||||
let c = lock.clone();
|
#[cfg(windows)]
|
||||||
if c.is_some() {
|
{
|
||||||
return c;
|
if let Some(path) = SWITCH_HOME_PATH.lock().as_ref() {
|
||||||
}
|
return path.clone();
|
||||||
if let Some(home) = SWITCH_HOME_PATH.lock().clone() {
|
|
||||||
match read_config_(home.to_path_buf()) {
|
|
||||||
Ok(config) => {
|
|
||||||
lock.replace(config.clone());
|
|
||||||
Some(config)
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
log::error!("{:?},path:{:?}", e,home);
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
}
|
||||||
|
let home = dirs::home_dir().unwrap().join(".switch_desktop");
|
||||||
|
if !home.exists() {
|
||||||
|
std::fs::create_dir(&home).unwrap();
|
||||||
|
}
|
||||||
|
home
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_home(home: PathBuf) {
|
pub fn get_runtime_data_path() -> PathBuf {
|
||||||
SWITCH_HOME_PATH.lock().replace(home);
|
let home = get_home();
|
||||||
|
home.join(".data")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_config_(home: PathBuf) -> io::Result<ArgsConfig> {
|
fn read_runtime_data() -> io::Result<RuntimeData> {
|
||||||
let config_path = home.join("config");
|
let config_path = get_runtime_data_path();
|
||||||
let mut file = if config_path.exists() {
|
let mut file = if config_path.exists() {
|
||||||
File::open(config_path)?
|
File::open(config_path)?
|
||||||
} else {
|
} else {
|
||||||
@@ -252,6 +479,19 @@ fn read_config_(home: PathBuf) -> io::Result<ArgsConfig> {
|
|||||||
};
|
};
|
||||||
let mut str = String::new();
|
let mut str = String::new();
|
||||||
file.read_to_string(&mut str)?;
|
file.read_to_string(&mut str)?;
|
||||||
|
match serde_yaml::from_str::<RuntimeData>(&str) {
|
||||||
|
Ok(config) => Ok(config),
|
||||||
|
Err(e) => {
|
||||||
|
log::warn!("{:?}", e);
|
||||||
|
Err(io::Error::new(io::ErrorKind::Other, "config error"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_config(config_path: PathBuf) -> io::Result<ArgsConfig> {
|
||||||
|
let mut file = File::open(config_path)?;
|
||||||
|
let mut str = String::new();
|
||||||
|
file.read_to_string(&mut str)?;
|
||||||
match serde_yaml::from_str::<ArgsConfig>(&str) {
|
match serde_yaml::from_str::<ArgsConfig>(&str) {
|
||||||
Ok(config) => Ok(config),
|
Ok(config) => Ok(config),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
@@ -259,4 +499,4 @@ fn read_config_(home: PathBuf) -> io::Result<ArgsConfig> {
|
|||||||
Err(io::Error::new(io::ErrorKind::Other, "config error"))
|
Err(io::Error::new(io::ErrorKind::Other, "config error"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+42
-16
@@ -1,3 +1,5 @@
|
|||||||
|
use std::thread;
|
||||||
|
use std::time::Duration;
|
||||||
use clap::{Parser, Subcommand};
|
use clap::{Parser, Subcommand};
|
||||||
use console::style;
|
use console::style;
|
||||||
|
|
||||||
@@ -58,7 +60,7 @@ enum Commands {
|
|||||||
Status,
|
Status,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Parser, Debug)]
|
#[derive(Parser, Debug,Default)]
|
||||||
pub struct StartArgs {
|
pub struct StartArgs {
|
||||||
/// 不超过64个字符
|
/// 不超过64个字符
|
||||||
/// 相同token的设备之间才能通信。
|
/// 相同token的设备之间才能通信。
|
||||||
@@ -89,10 +91,25 @@ pub struct StartArgs {
|
|||||||
#[cfg(any(unix))]
|
#[cfg(any(unix))]
|
||||||
#[arg(long)]
|
#[arg(long)]
|
||||||
off_command_server: bool,
|
off_command_server: bool,
|
||||||
/// 记录日志,输出在 home/.switch 目录下,长时间使用时不建议开启
|
/// 记录日志,输出在 home/.switch_desktop 目录下,长时间使用时不建议开启
|
||||||
/// Output the log in the "home/.switch" directory
|
/// Output the log in the "home/.switch_desktop" directory
|
||||||
#[arg(long)]
|
#[arg(long)]
|
||||||
log: bool,
|
log: bool,
|
||||||
|
/// 使用tap网卡
|
||||||
|
#[arg(long)]
|
||||||
|
tap: bool,
|
||||||
|
/// 配置点对网时使用,--in-ip 192.168.10.0/24,10.26.0.3,表示允许接收网段192.168.10.0/24的数据并转发到10.26.0.3
|
||||||
|
/// Use when configuring peer-to-peer networks
|
||||||
|
#[arg(long)]
|
||||||
|
in_ip:Option<Vec<String>>,
|
||||||
|
/// 配置点对网时使用,--out-ip 192.168.10.0/24,192.168.1.10,表示允许目标为192.168.10.0/24的数据从网卡192.168.1.10转发出去
|
||||||
|
/// Use when configuring peer-to-peer networks
|
||||||
|
#[arg(long)]
|
||||||
|
out_ip:Option<Vec<String>>,
|
||||||
|
/// 读取配置文件 --config config_file_path
|
||||||
|
/// Read configuration file
|
||||||
|
#[arg(long)]
|
||||||
|
config:Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
@@ -119,43 +136,48 @@ pub struct ConfigArgs {
|
|||||||
|
|
||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
fn main() {
|
#[tokio::main]
|
||||||
|
async fn main() {
|
||||||
let args: Vec<_> = std::env::args().collect();
|
let args: Vec<_> = std::env::args().collect();
|
||||||
if args.len() == 3 && args[1] == windows::SERVICE_FLAG {
|
if args.len() == 3 && args[1] == windows::SERVICE_FLAG {
|
||||||
//以服务的方式启动
|
//以服务的方式启动
|
||||||
config::set_home(std::path::PathBuf::from(&args[2]));
|
config::set_win_server_home(std::path::PathBuf::from(&args[2]));
|
||||||
windows::service::start();
|
windows::service::start();
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
let home = dirs::home_dir().unwrap().join(".switch");
|
|
||||||
config::set_home(home);
|
|
||||||
let args = BaseArgs::parse();
|
let args = BaseArgs::parse();
|
||||||
if let Commands::Start(start_args) = &args.command {
|
if let Commands::Start(start_args) = &args.command {
|
||||||
if start_args.log {
|
if start_args.log {
|
||||||
let _ = log_init();
|
let _ = log_init();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
windows::main0(args);
|
windows::main0(args).await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(target_os = "linux", target_os = "macos"))]
|
#[cfg(any(target_os = "linux", target_os = "macos"))]
|
||||||
fn main() {
|
#[tokio::main]
|
||||||
let home = dirs::home_dir().unwrap().join(".switch");
|
async fn main() {
|
||||||
config::set_home(home);
|
if sudo::RunningAs::Root != sudo::check() {
|
||||||
|
println!(
|
||||||
|
"{}",
|
||||||
|
style("需要使用root权限执行(Need to execute with root permission)...").red()
|
||||||
|
);
|
||||||
|
sudo::escalate_if_needed().unwrap();
|
||||||
|
}
|
||||||
let args = BaseArgs::parse();
|
let args = BaseArgs::parse();
|
||||||
if let Commands::Start(start_args) = &args.command {
|
if let Commands::Start(start_args) = &args.command {
|
||||||
if start_args.log {
|
if start_args.log {
|
||||||
let _ = log_init();
|
let _ = log_init();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
unix::main0(args);
|
unix::main0(args).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn console_listen(switch: &Switch) {
|
pub fn console_listen(switch: &Switch) {
|
||||||
use console::Term;
|
use console::Term;
|
||||||
let term = Term::stdout();
|
let term = Term::stdout();
|
||||||
println!("{}", style("started").green());
|
println!("{}", style("启动成功 started").green());
|
||||||
let current_device = switch.current_device();
|
let current_device = switch.current_device();
|
||||||
println!(
|
println!(
|
||||||
"当前虚拟ip(virtual ip): {:?}",
|
"当前虚拟ip(virtual ip): {:?}",
|
||||||
@@ -172,15 +194,19 @@ pub fn console_listen(switch: &Switch) {
|
|||||||
);
|
);
|
||||||
match term.read_line() {
|
match term.read_line() {
|
||||||
Ok(cmd) => {
|
Ok(cmd) => {
|
||||||
|
#[cfg(unix)]
|
||||||
if cmd.is_empty() {
|
if cmd.is_empty() {
|
||||||
log::warn!("非正常返回");
|
use libc::{STDIN_FILENO, isatty};
|
||||||
return;
|
if !unsafe { isatty(STDIN_FILENO) != 0 }{
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if command(cmd.trim(), &switch).is_err() {
|
if command(cmd.trim(), &switch).is_err() {
|
||||||
println!("{}", style("stopping").red());
|
println!("{}", style("stopping").red());
|
||||||
if let Err(e) = switch.stop() {
|
if let Err(e) = switch.stop() {
|
||||||
println!("stop:{:?}", e);
|
println!("stop:{:?}", e);
|
||||||
}
|
}
|
||||||
|
thread::sleep(Duration::from_secs(2));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -190,7 +216,7 @@ pub fn console_listen(switch: &Switch) {
|
|||||||
if let Err(e) = switch.stop() {
|
if let Err(e) = switch.stop() {
|
||||||
log::error!("stop:{:?}", e);
|
log::error!("stop:{:?}", e);
|
||||||
}
|
}
|
||||||
std::thread::sleep(std::time::Duration::from_secs(1));
|
thread::sleep(Duration::from_secs(1));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,100 +9,93 @@ use crate::{BaseArgs, Commands, config};
|
|||||||
use crate::command::{command, CommandEnum};
|
use crate::command::{command, CommandEnum};
|
||||||
|
|
||||||
|
|
||||||
pub fn main0(base_args: BaseArgs) {
|
pub async fn main0(base_args: BaseArgs) {
|
||||||
match base_args.command {
|
match base_args.command {
|
||||||
Commands::Start(args) => {
|
Commands::Start(args) => {
|
||||||
let off_command_server = args.off_command_server;
|
let start_config = if let Some(config_path) = &args.config {
|
||||||
match config::default_config(args) {
|
match config::read_config_file(config_path.into()) {
|
||||||
Ok(start_config) => {
|
Ok(start_config) => {
|
||||||
if sudo::RunningAs::Root != sudo::check() {
|
start_config
|
||||||
println!(
|
|
||||||
"{}",
|
|
||||||
style("需要使用root权限执行(Need to execute with root permission)...").red()
|
|
||||||
);
|
|
||||||
sudo::escalate_if_needed().unwrap();
|
|
||||||
}
|
}
|
||||||
|
Err(e) => {
|
||||||
let config = Config::new(
|
println!("{}", style(&e).red());
|
||||||
start_config.token.clone(),
|
log::error!("{:?}", e);
|
||||||
start_config.device_id.clone(),
|
|
||||||
start_config.name.clone(),
|
|
||||||
start_config.server,
|
|
||||||
start_config.nat_test_server.clone(),
|
|
||||||
);
|
|
||||||
let nat_test_server = start_config.nat_test_server.iter().map(|v| v.to_string()).collect::<Vec<String>>();
|
|
||||||
let args_config = config::ArgsConfig::new(
|
|
||||||
start_config.token.clone(),
|
|
||||||
start_config.name.clone(),
|
|
||||||
start_config.server.to_string(),
|
|
||||||
nat_test_server,
|
|
||||||
start_config.device_id.clone(),
|
|
||||||
);
|
|
||||||
let lock = match config::lock_file() {
|
|
||||||
Ok(lock) => {
|
|
||||||
lock
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
log::error!("{:?}",e);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
if lock.try_lock_exclusive().is_err() {
|
|
||||||
println!("{}", style("文件被重复打开").red());
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if let Err(e) = config::save_config(args_config) {
|
}
|
||||||
log::error!("{:?}",e);
|
} else {
|
||||||
lock.unlock().unwrap();
|
match config::default_config(args) {
|
||||||
|
Ok(start_config) => {
|
||||||
|
start_config
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
println!("{}", style(&e).red());
|
||||||
|
log::error!("{:?}", e);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let switch = match Switch::start(config) {
|
}
|
||||||
Ok(switch) => {
|
};
|
||||||
switch
|
let off_command_server = start_config.off_command_server;
|
||||||
}
|
let config = Config::new(
|
||||||
Err(e) => {
|
start_config.tap,
|
||||||
log::error!("{:?}", e);
|
start_config.token.clone(),
|
||||||
lock.unlock().unwrap();
|
start_config.device_id.clone(),
|
||||||
return;
|
start_config.name.clone(),
|
||||||
}
|
start_config.server,
|
||||||
};
|
start_config.nat_test_server.clone(),
|
||||||
let switch = Arc::new(switch);
|
start_config.in_ips.clone(),
|
||||||
let command_server = crate::command::server::CommandServer::new();
|
start_config.out_ips.clone(),
|
||||||
if off_command_server {
|
);
|
||||||
crate::console_listen(&switch);
|
let lock = match config::lock_file() {
|
||||||
log::info!("前台任务结束");
|
Ok(lock) => {
|
||||||
} else {
|
lock
|
||||||
if let Err(e) = config::update_pid(std::process::id()) {
|
}
|
||||||
log::error!("{:?}", e);
|
Err(e) => {
|
||||||
}
|
log::error!("{:?}",e);
|
||||||
let switch1 = switch.clone();
|
println!("文件锁定失败:{:?}", e);
|
||||||
let handle = std::thread::spawn(move || {
|
return;
|
||||||
if let Err(e) = command_server.start(switch1) {
|
}
|
||||||
log::error!("{:?}", e);
|
};
|
||||||
}
|
if lock.try_lock_exclusive().is_err() {
|
||||||
});
|
println!("{}", style("文件被重复打开").red());
|
||||||
crate::console_listen(&switch);
|
return;
|
||||||
if let Err(e) = handle.join() {
|
}
|
||||||
log::error!("后台任务异常{:?}",e);
|
let switch = match Switch::start(config).await {
|
||||||
} else {
|
Ok(switch) => {
|
||||||
log::info!("后台任务结束");
|
switch
|
||||||
}
|
|
||||||
}
|
|
||||||
lock.unlock().unwrap();
|
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
log::error!("{:?}", e);
|
log::error!("{:?}", e);
|
||||||
|
println!("启动switch失败:{:?}", e);
|
||||||
|
lock.unlock().unwrap();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let switch = Arc::new(switch);
|
||||||
|
let command_server = crate::command::server::CommandServer::new();
|
||||||
|
if off_command_server {
|
||||||
|
crate::console_listen(&switch);
|
||||||
|
log::info!("前台任务结束");
|
||||||
|
} else {
|
||||||
|
if let Err(e) = config::update_pid(std::process::id()) {
|
||||||
|
log::error!("{:?}", e);
|
||||||
|
}
|
||||||
|
let switch1 = switch.clone();
|
||||||
|
let handle = std::thread::Builder::new().name("cmd-server".into()).spawn(move || {
|
||||||
|
if let Err(e) = command_server.start(switch1) {
|
||||||
|
log::error!("{:?}", e);
|
||||||
|
}
|
||||||
|
}).unwrap();
|
||||||
|
crate::console_listen(&switch);
|
||||||
|
if let Err(e) = handle.join() {
|
||||||
|
log::error!("后台任务异常{:?}",e);
|
||||||
|
} else {
|
||||||
|
log::info!("后台任务结束");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
lock.unlock().unwrap();
|
||||||
}
|
}
|
||||||
Commands::Stop => {
|
Commands::Stop => {
|
||||||
if sudo::RunningAs::Root != sudo::check() {
|
|
||||||
println!(
|
|
||||||
"{}",
|
|
||||||
style("需要使用root权限执行(Need to execute with root permission)...").red()
|
|
||||||
);
|
|
||||||
sudo::escalate_if_needed().unwrap();
|
|
||||||
}
|
|
||||||
command(CommandEnum::Stop);
|
command(CommandEnum::Stop);
|
||||||
if let Ok(pid) = config::read_pid() {
|
if let Ok(pid) = config::read_pid() {
|
||||||
if pid != 0 {
|
if pid != 0 {
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ fn not_started() -> bool {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn main0(base_args: BaseArgs) {
|
pub async fn main0(base_args: BaseArgs) {
|
||||||
match base_args.command {
|
match base_args.command {
|
||||||
Commands::Start(args) => {
|
Commands::Start(args) => {
|
||||||
if admin_check() {
|
if admin_check() {
|
||||||
@@ -62,87 +62,94 @@ pub fn main0(base_args: BaseArgs) {
|
|||||||
// 允许应用通过防火墙
|
// 允许应用通过防火墙
|
||||||
let _udp = UdpSocket::bind("0.0.0.0:0").unwrap();
|
let _udp = UdpSocket::bind("0.0.0.0:0").unwrap();
|
||||||
}
|
}
|
||||||
let out_log = args.log;
|
let start_config = if let Some(config_path) = &args.config {
|
||||||
match config::default_config(args) {
|
match config::read_config_file(config_path.into()) {
|
||||||
Ok(start_config) => {
|
Ok(start_config) => {
|
||||||
match service_state() {
|
start_config
|
||||||
Ok(state) => {
|
}
|
||||||
if state == ServiceState::Stopped {
|
Err(e) => {
|
||||||
if let Err(e) = config::save_config(config::ArgsConfig::new(
|
println!("{}", style(&e).red());
|
||||||
start_config.token.clone(),
|
log::error!("{:?}", e);
|
||||||
start_config.name.clone(),
|
return;
|
||||||
start_config.server.to_string(),
|
}
|
||||||
start_config.nat_test_server.iter().map(|v| v.to_string()).collect::<Vec<String>>(),
|
}
|
||||||
start_config.device_id.clone(),
|
} else {
|
||||||
)) {
|
match config::default_config(args) {
|
||||||
log::error!("{:?}",e);
|
Ok(start_config) => {
|
||||||
return;
|
start_config
|
||||||
}
|
}
|
||||||
match start(out_log) {
|
Err(e) => {
|
||||||
Ok(_) => {
|
println!("{}", style(&e).red());
|
||||||
//需要检查启动状态
|
log::error!("{:?}", e);
|
||||||
thread::sleep(Duration::from_secs(2));
|
return;
|
||||||
println!("{}", style("启动成功(Start successfully)").green())
|
}
|
||||||
}
|
}
|
||||||
Err(e) => {
|
};
|
||||||
log::error!("{:?}", e);
|
match service_state() {
|
||||||
}
|
Ok(state) => {
|
||||||
}
|
if state == ServiceState::Stopped {
|
||||||
} else {
|
match start() {
|
||||||
println!("服务未停止(Service not stopped)");
|
Ok(_) => {
|
||||||
|
//需要检查启动状态
|
||||||
|
thread::sleep(Duration::from_secs(2));
|
||||||
|
println!("{}", style("启动成功(Start successfully)").green());
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
log::error!("{:?}", e);
|
||||||
|
println!("{}:{}", style("启动失败").red(),e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(e) => {
|
} else {
|
||||||
match e {
|
println!("服务未停止(Service not stopped)");
|
||||||
Error::Winapi(ref e) => {
|
|
||||||
if let Some(code) = e.raw_os_error() {
|
|
||||||
if code == 1060 {
|
|
||||||
//指定的服务未安装。
|
|
||||||
println!(
|
|
||||||
"{}",
|
|
||||||
style("服务未安装,在当前进程启动(The service is not installed and started in the current process)").red()
|
|
||||||
);
|
|
||||||
let config = Config::new(
|
|
||||||
start_config.token,
|
|
||||||
start_config.device_id,
|
|
||||||
start_config.name,
|
|
||||||
start_config.server,
|
|
||||||
start_config.nat_test_server,
|
|
||||||
);
|
|
||||||
let lock = match config::lock_file() {
|
|
||||||
Ok(lock) => {
|
|
||||||
lock
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
log::error!("{:?}",e);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
if lock.try_lock_exclusive().is_err() {
|
|
||||||
println!("{}", style("文件被重复打开").red());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
match Switch::start(config) {
|
|
||||||
Ok(switch) => {
|
|
||||||
crate::console_listen(&switch);
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
log::error!("{:?}", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
lock.unlock().unwrap();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
println!("{:?}", e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
println!("{}", style(e).red());
|
match e {
|
||||||
|
Error::Winapi(ref e) => {
|
||||||
|
if let Some(code) = e.raw_os_error() {
|
||||||
|
if code == 1060 {
|
||||||
|
//指定的服务未安装。
|
||||||
|
let config = Config::new(
|
||||||
|
start_config.tap,
|
||||||
|
start_config.token,
|
||||||
|
start_config.device_id,
|
||||||
|
start_config.name,
|
||||||
|
start_config.server,
|
||||||
|
start_config.nat_test_server,
|
||||||
|
start_config.in_ips,
|
||||||
|
start_config.out_ips,
|
||||||
|
);
|
||||||
|
let lock = match config::lock_file() {
|
||||||
|
Ok(lock) => {
|
||||||
|
lock
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
log::error!("文件锁定失败:{:?}",e);
|
||||||
|
println!("文件锁定失败:{:?}", e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if lock.try_lock_exclusive().is_err() {
|
||||||
|
println!("{}", style("文件被重复打开").red());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
match Switch::start(config).await {
|
||||||
|
Ok(switch) => {
|
||||||
|
crate::console_listen(&switch);
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
log::error!("{:?}", e);
|
||||||
|
println!("启动switch失败:{:?}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lock.unlock().unwrap();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
println!("{:?}", e);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
pause();
|
pause();
|
||||||
@@ -160,6 +167,7 @@ pub fn main0(base_args: BaseArgs) {
|
|||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
log::error!("{:?}", e);
|
log::error!("{:?}", e);
|
||||||
|
println!("停止失败:{}",e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pause();
|
pause();
|
||||||
@@ -177,6 +185,7 @@ pub fn main0(base_args: BaseArgs) {
|
|||||||
} else {
|
} else {
|
||||||
if let Err(e) = install(path, args.auto) {
|
if let Err(e) = install(path, args.auto) {
|
||||||
log::error!("{:?}", e);
|
log::error!("{:?}", e);
|
||||||
|
println!("安装失败:{}",e);
|
||||||
} else {
|
} else {
|
||||||
println!("{}", style("安装成功(Installation succeeded)").green())
|
println!("{}", style("安装成功(Installation succeeded)").green())
|
||||||
}
|
}
|
||||||
@@ -189,6 +198,7 @@ pub fn main0(base_args: BaseArgs) {
|
|||||||
}
|
}
|
||||||
if let Err(e) = uninstall() {
|
if let Err(e) = uninstall() {
|
||||||
log::error!("{:?}", e);
|
log::error!("{:?}", e);
|
||||||
|
println!("卸载失败:{}",e);
|
||||||
} else {
|
} else {
|
||||||
println!("{}", style("卸载成功(Uninstall succeeded)").green())
|
println!("{}", style("卸载成功(Uninstall succeeded)").green())
|
||||||
}
|
}
|
||||||
@@ -197,6 +207,7 @@ pub fn main0(base_args: BaseArgs) {
|
|||||||
Commands::Config(args) => {
|
Commands::Config(args) => {
|
||||||
if let Err(e) = change(args.auto) {
|
if let Err(e) = change(args.auto) {
|
||||||
log::error!("{:?}", e);
|
log::error!("{:?}", e);
|
||||||
|
println!("配置失败:{}",e);
|
||||||
} else {
|
} else {
|
||||||
println!("{}", style("配置成功(Config succeeded)").green())
|
println!("{}", style("配置成功(Config succeeded)").green())
|
||||||
}
|
}
|
||||||
@@ -237,7 +248,10 @@ fn pause() {
|
|||||||
let _ = term.read_char().unwrap();
|
let _ = term.read_char().unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn install(path: PathBuf, auto: bool) -> Result<(), Error> {
|
fn install(mut path: PathBuf, auto: bool) -> Result<(), Error> {
|
||||||
|
if !path.is_absolute(){
|
||||||
|
path = path.canonicalize().unwrap();
|
||||||
|
}
|
||||||
let manager_access = ServiceManagerAccess::CONNECT | ServiceManagerAccess::CREATE_SERVICE;
|
let manager_access = ServiceManagerAccess::CONNECT | ServiceManagerAccess::CREATE_SERVICE;
|
||||||
let service_manager = ServiceManager::local_computer(None::<&str>, manager_access)?;
|
let service_manager = ServiceManager::local_computer(None::<&str>, manager_access)?;
|
||||||
let current_exe_path = std::env::current_exe().unwrap();
|
let current_exe_path = std::env::current_exe().unwrap();
|
||||||
@@ -254,7 +268,7 @@ fn install(path: PathBuf, auto: bool) -> Result<(), Error> {
|
|||||||
let mut launch_arguments = Vec::new();
|
let mut launch_arguments = Vec::new();
|
||||||
launch_arguments.push(OsString::from(SERVICE_FLAG));
|
launch_arguments.push(OsString::from(SERVICE_FLAG));
|
||||||
launch_arguments.push(OsString::from(
|
launch_arguments.push(OsString::from(
|
||||||
dirs::home_dir().unwrap().join(".switch").to_str().unwrap(),
|
config::get_home().to_str().unwrap(),
|
||||||
));
|
));
|
||||||
let start_type = if auto {
|
let start_type = if auto {
|
||||||
ServiceStartType::AutoStart
|
ServiceStartType::AutoStart
|
||||||
@@ -290,18 +304,28 @@ fn change(auto: bool) -> Result<(), Error> {
|
|||||||
} else {
|
} else {
|
||||||
ServiceStartType::OnDemand
|
ServiceStartType::OnDemand
|
||||||
};
|
};
|
||||||
let mut launch_arguments = Vec::new();
|
let executable_path = config.executable_path.to_string_lossy().to_string();
|
||||||
launch_arguments.push(OsString::from(SERVICE_FLAG));
|
let executable_path = if executable_path.starts_with('"') && executable_path.ends_with('"') {
|
||||||
launch_arguments.push(OsString::from(
|
&executable_path[1..executable_path.len() - 1]
|
||||||
dirs::home_dir().unwrap().join(".switch").to_str().unwrap(),
|
} else {
|
||||||
));
|
&executable_path
|
||||||
|
};
|
||||||
|
let mut split = executable_path.split(SERVICE_FLAG);
|
||||||
|
let executable_path = split.next().unwrap().trim();
|
||||||
|
let executable_path = if executable_path.starts_with('"') && executable_path.ends_with('"') {
|
||||||
|
PathBuf::from(&executable_path[1..executable_path.len() - 1])
|
||||||
|
} else {
|
||||||
|
PathBuf::from(executable_path)
|
||||||
|
};
|
||||||
|
let home_path = split.next().unwrap().trim();
|
||||||
|
let launch_arguments = vec![OsString::from(SERVICE_FLAG),OsString::from(home_path)];
|
||||||
let service_info = ServiceInfo {
|
let service_info = ServiceInfo {
|
||||||
name: OsString::from(SERVICE_NAME),
|
name: OsString::from(SERVICE_NAME),
|
||||||
display_name: config.display_name,
|
display_name: config.display_name,
|
||||||
service_type: SERVICE_TYPE,
|
service_type: SERVICE_TYPE,
|
||||||
start_type,
|
start_type,
|
||||||
error_control: config.error_control,
|
error_control: config.error_control,
|
||||||
executable_path: config.executable_path,
|
executable_path,
|
||||||
launch_arguments,
|
launch_arguments,
|
||||||
dependencies: config.dependencies,
|
dependencies: config.dependencies,
|
||||||
account_name: None, // run as System
|
account_name: None, // run as System
|
||||||
@@ -328,15 +352,12 @@ fn uninstall() -> Result<(), Error> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn start(out_log: bool) -> Result<(), Error> {
|
fn start() -> Result<(), Error> {
|
||||||
let manager_access = ServiceManagerAccess::CONNECT;
|
let manager_access = ServiceManagerAccess::CONNECT;
|
||||||
let service_manager = ServiceManager::local_computer(None::<&str>, manager_access)?;
|
let service_manager = ServiceManager::local_computer(None::<&str>, manager_access)?;
|
||||||
let service = service_manager.open_service(SERVICE_NAME, ServiceAccess::START)?;
|
let service = service_manager.open_service(SERVICE_NAME, ServiceAccess::START)?;
|
||||||
if out_log {
|
let args: Vec<_> = std::env::args().collect();
|
||||||
service.start(&["log"])
|
service.start(&args[1..])
|
||||||
} else {
|
|
||||||
service.start(&[""])
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn service_state() -> Result<ServiceState, Error> {
|
fn service_state() -> Result<ServiceState, Error> {
|
||||||
|
|||||||
@@ -2,10 +2,12 @@
|
|||||||
// extern crate windows_service;
|
// extern crate windows_service;
|
||||||
|
|
||||||
use std::ffi::OsString;
|
use std::ffi::OsString;
|
||||||
use std::net::ToSocketAddrs;
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::thread;
|
use std::io;
|
||||||
|
use std::io::Write;
|
||||||
|
use std::path::PathBuf;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
use clap::Parser;
|
||||||
|
|
||||||
use windows_service::{define_windows_service, service_control_handler, service_dispatcher};
|
use windows_service::{define_windows_service, service_control_handler, service_dispatcher};
|
||||||
use windows_service::service::{
|
use windows_service::service::{
|
||||||
@@ -15,28 +17,26 @@ use windows_service::service_control_handler::ServiceControlHandlerResult;
|
|||||||
|
|
||||||
use switch::core::{Config, Switch};
|
use switch::core::{Config, Switch};
|
||||||
|
|
||||||
use crate::config;
|
use crate::{BaseArgs, Commands, config};
|
||||||
use crate::windows::config::read_config;
|
|
||||||
use crate::windows::SERVICE_NAME;
|
use crate::windows::SERVICE_NAME;
|
||||||
|
|
||||||
define_windows_service!(ffi_service_main, switch_service_main);
|
define_windows_service!(ffi_service_main, switch_service_main);
|
||||||
pub fn switch_service_main(arguments: Vec<OsString>) {
|
pub fn switch_service_main(arguments: Vec<OsString>) {
|
||||||
if !arguments.is_empty() {
|
tokio::runtime::Builder::new_multi_thread()
|
||||||
if let Some(str) = arguments[0].to_str() {
|
.enable_all()
|
||||||
if str == "log" {
|
.build()
|
||||||
let _ = config::log_config::log_service_init();
|
.unwrap()
|
||||||
|
.block_on(async {
|
||||||
|
match service_main(arguments).await {
|
||||||
|
Ok(_) => {}
|
||||||
|
Err(e) => {
|
||||||
|
log::error!("启动服务失败:{:?}",e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
}
|
|
||||||
thread::spawn(|| match service_main() {
|
|
||||||
Ok(_) => {}
|
|
||||||
Err(e) => {
|
|
||||||
log::error!("{:?}", e);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn service_main() -> windows_service::Result<()> {
|
async fn service_main(arguments: Vec<OsString>) -> windows_service::Result<()> {
|
||||||
let parker = crossbeam::sync::Parker::new();
|
let parker = crossbeam::sync::Parker::new();
|
||||||
let un_parker = parker.unparker().clone();
|
let un_parker = parker.unparker().clone();
|
||||||
let event_handler = move |control_event| -> ServiceControlHandlerResult {
|
let event_handler = move |control_event| -> ServiceControlHandlerResult {
|
||||||
@@ -70,15 +70,13 @@ fn service_main() -> windows_service::Result<()> {
|
|||||||
wait_hint: Duration::default(),
|
wait_hint: Duration::default(),
|
||||||
process_id: None,
|
process_id: None,
|
||||||
})?;
|
})?;
|
||||||
match start_switch() {
|
match start_switch(arguments).await {
|
||||||
Ok(switch) => {
|
Ok(_) => {
|
||||||
parker.park();
|
parker.park();
|
||||||
if let Err(e) = switch.stop() {
|
|
||||||
log::warn!("switch stop:{:?}",e)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
log::error!("{:?}",e);
|
log::error!("服务启动失败 {:?}",e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
status_handle.set_service_status(ServiceStatus {
|
status_handle.set_service_status(ServiceStatus {
|
||||||
@@ -92,51 +90,113 @@ fn service_main() -> windows_service::Result<()> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn start_switch() -> switch::Result<Arc<Switch>> {
|
fn auto_config_path() -> io::Result<PathBuf> {
|
||||||
if let Some(config) = read_config() {
|
Ok(config::get_win_server_home().join("auto_config.yaml"))
|
||||||
let device_id = config.device_id;
|
}
|
||||||
if device_id.trim().is_empty() {
|
|
||||||
return Err(switch::error::Error::Stop("Device id error".to_string()));
|
fn save_auto_config(start_config: config::StartConfig) -> io::Result<()> {
|
||||||
|
let mut file = std::fs::File::create(auto_config_path()?)?;
|
||||||
|
log::error!("auto_config_path()? {:?}",auto_config_path()?);
|
||||||
|
let config = config::ArgsConfig::new(start_config);
|
||||||
|
match serde_yaml::to_string(&config) {
|
||||||
|
Ok(yaml) => {
|
||||||
|
file.write_all(yaml.as_bytes())
|
||||||
}
|
}
|
||||||
let server_address = if let Some(server_address) = config.server
|
Err(e) => {
|
||||||
.to_socket_addrs()?
|
Err(io::Error::new(io::ErrorKind::Other, format!("{:?}", e)))
|
||||||
.next() {
|
|
||||||
server_address
|
|
||||||
} else {
|
|
||||||
return Err(switch::error::Error::Stop("server address error".to_string()));
|
|
||||||
};
|
|
||||||
let nat_test_server = config.nat_test_server.iter()
|
|
||||||
.flat_map(|a| a.to_socket_addrs())
|
|
||||||
.flatten()
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
if nat_test_server.is_empty() {
|
|
||||||
return Err(switch::error::Error::Stop("nat test server address error".to_string()));
|
|
||||||
}
|
}
|
||||||
let config = Config::new(
|
|
||||||
config.token,
|
|
||||||
device_id,
|
|
||||||
config.name,
|
|
||||||
server_address,
|
|
||||||
nat_test_server);
|
|
||||||
let switch = Switch::start(config)?;
|
|
||||||
log::info!("switch-service服务启动");
|
|
||||||
let switch = Arc::new(switch);
|
|
||||||
let command_server = crate::command::server::CommandServer::new();
|
|
||||||
let switch1 = switch.clone();
|
|
||||||
thread::spawn(move || {
|
|
||||||
if let Err(e) = config::update_pid(std::process::id()) {
|
|
||||||
log::error!("{:?}", e);
|
|
||||||
}
|
|
||||||
if let Err(e) = command_server.start(switch1) {
|
|
||||||
log::error!("{:?}", e);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
Ok(switch)
|
|
||||||
} else {
|
|
||||||
Err(switch::error::Error::Stop("配置文件为空".to_string()))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn start_switch(arguments: Vec<OsString>) -> switch::Result<()> {
|
||||||
|
let start_config = match BaseArgs::try_parse_from(arguments) {
|
||||||
|
Ok(args) => {
|
||||||
|
match args.command {
|
||||||
|
Commands::Start(args) => {
|
||||||
|
if args.log {
|
||||||
|
let _ = config::log_config::log_service_init();
|
||||||
|
}
|
||||||
|
if let Some(config_path) = &args.config {
|
||||||
|
match config::read_config_file(config_path.into()) {
|
||||||
|
Ok(start_config) => {
|
||||||
|
if let Err(e) = save_auto_config(start_config.clone()) {
|
||||||
|
log::warn!("配置文件保存失败:{:?}",e);
|
||||||
|
}
|
||||||
|
start_config
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
log::error!("{:?}", e);
|
||||||
|
return Err(switch::error::Error::Stop(e));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
match config::default_config(args) {
|
||||||
|
Ok(start_config) => {
|
||||||
|
if let Err(e) = save_auto_config(start_config.clone()) {
|
||||||
|
log::warn!("配置文件保存失败:{:?}",e);
|
||||||
|
}
|
||||||
|
start_config
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
log::error!("{:?}", e);
|
||||||
|
return Err(switch::error::Error::Stop(e));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
return Err(switch::error::Error::Stop("配置文件错误".to_string()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(_) => {
|
||||||
|
match config::read_config_file(auto_config_path()?) {
|
||||||
|
Ok(start_config) => {
|
||||||
|
if start_config.log {
|
||||||
|
let _ = config::log_config::log_service_init();
|
||||||
|
}
|
||||||
|
start_config
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
return Err(switch::error::Error::Stop(e));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let config = Config::new(
|
||||||
|
start_config.tap,
|
||||||
|
start_config.token,
|
||||||
|
start_config.device_id,
|
||||||
|
start_config.name,
|
||||||
|
start_config.server,
|
||||||
|
start_config.nat_test_server,
|
||||||
|
start_config.in_ips,
|
||||||
|
start_config.out_ips,
|
||||||
|
);
|
||||||
|
log::info!("switch-service服务启动");
|
||||||
|
|
||||||
|
|
||||||
|
tokio::spawn(async move {
|
||||||
|
match Switch::start(config).await {
|
||||||
|
Ok(switch) => {
|
||||||
|
let switch = Arc::new(switch);
|
||||||
|
let command_server = crate::command::server::CommandServer::new();
|
||||||
|
if let Err(e) = config::update_pid(std::process::id()) {
|
||||||
|
log::error!("{:?}", e);
|
||||||
|
}
|
||||||
|
if let Err(e) = command_server.start(switch) {
|
||||||
|
log::error!("{:?}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
log::error!("{:?}", e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
});
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn start() {
|
pub fn start() {
|
||||||
log::info!("以服务的方式启动");
|
log::info!("以服务的方式启动");
|
||||||
service_dispatcher::start(SERVICE_NAME, ffi_service_main).unwrap();
|
service_dispatcher::start(SERVICE_NAME, ffi_service_main).unwrap();
|
||||||
|
|||||||
@@ -1,13 +0,0 @@
|
|||||||
[package]
|
|
||||||
name = "switch-jni"
|
|
||||||
version = "0.1.0"
|
|
||||||
edition = "2021"
|
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
|
||||||
[lib]
|
|
||||||
crate-type = ['cdylib']
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
switch = {path="../switch"}
|
|
||||||
jni = "0.20.0"
|
|
||||||
anyhow = "1.0.65"
|
|
||||||
@@ -1,267 +0,0 @@
|
|||||||
use std::net::{IpAddr, Ipv4Addr, ToSocketAddrs};
|
|
||||||
|
|
||||||
use jni::errors::Error;
|
|
||||||
use jni::objects::{JClass, JObject, JString, JValue};
|
|
||||||
use jni::sys::{jbyte, jint, jlong, jobject, jobjectArray, jsize};
|
|
||||||
use jni::JNIEnv;
|
|
||||||
|
|
||||||
use switch::handle::{CurrentDeviceInfo, PeerDeviceInfo, Route};
|
|
||||||
use switch::{Config, Switch};
|
|
||||||
|
|
||||||
fn to_string_not_null(env: &JNIEnv, config: JObject, name: &'static str) -> Result<String, Error> {
|
|
||||||
let value = env.get_field(config, name, "Ljava/lang/String;")?.l()?;
|
|
||||||
if value.is_null() {
|
|
||||||
env.throw_new("Ljava/lang/NullPointerException", name)
|
|
||||||
.expect("throw");
|
|
||||||
return Err(Error::NullPtr(name));
|
|
||||||
}
|
|
||||||
let value = env.get_string(JString::from(value))?;
|
|
||||||
match value.to_str() {
|
|
||||||
Ok(value) => Ok(value.to_string()),
|
|
||||||
Err(_) => {
|
|
||||||
env.throw_new("Ljava/lang/RuntimeException", "not utf-8")
|
|
||||||
.expect("throw");
|
|
||||||
return Err(Error::JavaException);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn to_string(env: &JNIEnv, config: JObject, name: &str) -> Result<Option<String>, Error> {
|
|
||||||
let value = env.get_field(config, name, "Ljava/lang/String;")?.l()?;
|
|
||||||
if value.is_null() {
|
|
||||||
return Ok(None);
|
|
||||||
}
|
|
||||||
let value = env.get_string(JString::from(value))?;
|
|
||||||
match value.to_str() {
|
|
||||||
Ok(value) => Ok(Some(value.to_string())),
|
|
||||||
Err(_) => {
|
|
||||||
env.throw_new("Ljava/lang/RuntimeException", "not utf-8")
|
|
||||||
.expect("throw");
|
|
||||||
return Err(Error::JavaException);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn start(env: &JNIEnv, config: JObject) -> Result<Option<Switch>, Error> {
|
|
||||||
let token = to_string_not_null(&env, config, "token")?;
|
|
||||||
let mac_address = to_string_not_null(&env, config, "macAddress")?;
|
|
||||||
let name = to_string(&env, config, "name")?;
|
|
||||||
let server_address = "nat1.wherewego.top:29875"
|
|
||||||
.to_socket_addrs()
|
|
||||||
.unwrap()
|
|
||||||
.next()
|
|
||||||
.unwrap();
|
|
||||||
let nat_test_server = vec![
|
|
||||||
"nat1.wherewego.top:35061"
|
|
||||||
.to_socket_addrs()
|
|
||||||
.unwrap()
|
|
||||||
.next()
|
|
||||||
.unwrap(),
|
|
||||||
"nat1.wherewego.top:35062"
|
|
||||||
.to_socket_addrs()
|
|
||||||
.unwrap()
|
|
||||||
.next()
|
|
||||||
.unwrap(),
|
|
||||||
"nat2.wherewego.top:35061"
|
|
||||||
.to_socket_addrs()
|
|
||||||
.unwrap()
|
|
||||||
.next()
|
|
||||||
.unwrap(),
|
|
||||||
"nat2.wherewego.top:35062"
|
|
||||||
.to_socket_addrs()
|
|
||||||
.unwrap()
|
|
||||||
.next()
|
|
||||||
.unwrap(),
|
|
||||||
];
|
|
||||||
let config = match Config::new(
|
|
||||||
token,
|
|
||||||
mac_address,
|
|
||||||
name,
|
|
||||||
server_address,
|
|
||||||
nat_test_server,
|
|
||||||
|| {},
|
|
||||||
) {
|
|
||||||
Ok(config) => config,
|
|
||||||
Err(e) => {
|
|
||||||
env.throw_new(
|
|
||||||
"Ljava/lang/RuntimeException",
|
|
||||||
format!("switch start failed {:?}", e),
|
|
||||||
)
|
|
||||||
.expect("throw");
|
|
||||||
return Ok(None);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
match Switch::start(config) {
|
|
||||||
Ok(switch) => {
|
|
||||||
return Ok(Some(switch));
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
env.throw_new(
|
|
||||||
"Ljava/lang/RuntimeException",
|
|
||||||
format!("switch start failed {:?}", e),
|
|
||||||
)
|
|
||||||
.expect("throw");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(None)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub unsafe extern "C" fn Java_org_switches_jni_Switch_start0(
|
|
||||||
env: JNIEnv,
|
|
||||||
_class: JClass,
|
|
||||||
config: JObject,
|
|
||||||
) -> jlong {
|
|
||||||
match start(&env, config) {
|
|
||||||
Ok(switch) => {
|
|
||||||
if let Some(switch) = switch {
|
|
||||||
return Box::into_raw(Box::new(switch)) as jlong;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(_) => {}
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub unsafe extern "C" fn Java_org_switches_jni_Switch_stop0(
|
|
||||||
_env: JNIEnv,
|
|
||||||
_class: JClass,
|
|
||||||
raw_switch: jlong,
|
|
||||||
) {
|
|
||||||
let switch = Box::from_raw(raw_switch as *mut Switch);
|
|
||||||
switch.stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub unsafe extern "C" fn Java_org_switches_jni_Switch_currentDevice0(
|
|
||||||
env: JNIEnv,
|
|
||||||
_class: JClass,
|
|
||||||
raw_switch: jlong,
|
|
||||||
) -> jobject {
|
|
||||||
let switch = raw_switch as *mut Switch;
|
|
||||||
let dev_info = (&*switch).current_device();
|
|
||||||
match current_device(&env, dev_info) {
|
|
||||||
Ok(obj) => obj,
|
|
||||||
Err(_) => std::ptr::null_mut(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub unsafe extern "C" fn Java_org_switches_jni_Switch_deviceList0(
|
|
||||||
env: JNIEnv,
|
|
||||||
_class: JClass,
|
|
||||||
raw_switch: jlong,
|
|
||||||
) -> jobjectArray {
|
|
||||||
let switch = raw_switch as *mut Switch;
|
|
||||||
match device_list(&env, (&*switch).device_list()) {
|
|
||||||
Ok(arr) => arr,
|
|
||||||
Err(_) => std::ptr::null_mut(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub unsafe extern "C" fn Java_org_switches_jni_Switch_route0(
|
|
||||||
env: JNIEnv,
|
|
||||||
_class: JClass,
|
|
||||||
raw_switch: jlong,
|
|
||||||
ip: jint,
|
|
||||||
) -> jobject {
|
|
||||||
let ip = Ipv4Addr::from(ip as u32);
|
|
||||||
let switch = raw_switch as *mut Switch;
|
|
||||||
match route(&env, (&*switch).route(&ip)) {
|
|
||||||
Ok(arr) => arr,
|
|
||||||
Err(_) => std::ptr::null_mut(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub unsafe extern "C" fn Java_org_switches_jni_Switch_serverRt0(
|
|
||||||
_env: JNIEnv,
|
|
||||||
_class: JClass,
|
|
||||||
raw_switch: jlong,
|
|
||||||
) -> jlong {
|
|
||||||
let switch = raw_switch as *mut Switch;
|
|
||||||
let rt = (&*switch).server_rt();
|
|
||||||
rt as jlong
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub unsafe extern "C" fn Java_org_switches_jni_Switch_connectionStatus0(
|
|
||||||
_env: JNIEnv,
|
|
||||||
_class: JClass,
|
|
||||||
raw_switch: jlong,
|
|
||||||
) -> jbyte {
|
|
||||||
let switch = raw_switch as *mut Switch;
|
|
||||||
let connection_status: u8 = (&*switch).connection_status().into();
|
|
||||||
connection_status as jbyte
|
|
||||||
}
|
|
||||||
|
|
||||||
fn route(env: &JNIEnv, route: Route) -> Result<jobject, Error> {
|
|
||||||
let route_type: u8 = route.route_type.into();
|
|
||||||
let rt = route.rt;
|
|
||||||
let route = env.new_object(
|
|
||||||
"org/switches/jni/Route",
|
|
||||||
"(BJ)V",
|
|
||||||
&[JValue::Byte(route_type as jbyte), JValue::Long(rt as jlong)],
|
|
||||||
)?;
|
|
||||||
Ok(route.into_raw())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn device_list(env: &JNIEnv, device_list: Vec<PeerDeviceInfo>) -> Result<jobjectArray, Error> {
|
|
||||||
if device_list.is_empty() {
|
|
||||||
return Ok(std::ptr::null_mut());
|
|
||||||
}
|
|
||||||
let arr = env.new_object_array(
|
|
||||||
device_list.len() as jsize,
|
|
||||||
"org/switches/jni/PeerDeviceInfo",
|
|
||||||
JObject::null(),
|
|
||||||
)?;
|
|
||||||
let mut index = 0;
|
|
||||||
for peer_info in device_list {
|
|
||||||
let virtual_ip: u32 = peer_info.virtual_ip.into();
|
|
||||||
let name = peer_info.name;
|
|
||||||
let status: u8 = peer_info.status.into();
|
|
||||||
let info = env.new_object(
|
|
||||||
"org/switches/jni/PeerDeviceInfo",
|
|
||||||
"(BLjava/lang/String;J)V",
|
|
||||||
&[
|
|
||||||
JValue::Int(virtual_ip as jint),
|
|
||||||
JValue::Object(env.new_string(name)?.into()),
|
|
||||||
JValue::Byte(status as jbyte),
|
|
||||||
],
|
|
||||||
)?;
|
|
||||||
env.set_object_array_element(arr, index, info)?;
|
|
||||||
index += 1;
|
|
||||||
}
|
|
||||||
Ok(arr)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn current_device(env: &JNIEnv, dev_info: &CurrentDeviceInfo) -> Result<jobject, Error> {
|
|
||||||
let virtual_ip: u32 = dev_info.virtual_ip.into();
|
|
||||||
let virtual_gateway: u32 = dev_info.virtual_gateway.into();
|
|
||||||
let virtual_netmask: u32 = dev_info.virtual_netmask.into();
|
|
||||||
let virtual_network: u32 = dev_info.virtual_network.into();
|
|
||||||
let broadcast_address: u32 = dev_info.broadcast_address.into();
|
|
||||||
let connect_server_host: u32 = match dev_info.connect_server.ip() {
|
|
||||||
IpAddr::V4(ip) => ip.into(),
|
|
||||||
IpAddr::V6(_) => {
|
|
||||||
panic!()
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let connect_server_port = dev_info.connect_server.port() as u32;
|
|
||||||
let current_device = env.new_object(
|
|
||||||
"org/switches/jni/CurrentDevice",
|
|
||||||
"(IIIIIII)V",
|
|
||||||
&[
|
|
||||||
JValue::Int(virtual_ip as jint),
|
|
||||||
JValue::Int(virtual_gateway as jint),
|
|
||||||
JValue::Int(virtual_netmask as jint),
|
|
||||||
JValue::Int(virtual_network as jint),
|
|
||||||
JValue::Int(broadcast_address as jint),
|
|
||||||
JValue::Int(connect_server_host as jint),
|
|
||||||
JValue::Int(connect_server_port as jint),
|
|
||||||
],
|
|
||||||
)?;
|
|
||||||
Ok(current_device.into_raw())
|
|
||||||
}
|
|
||||||
+5
-5
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "switch"
|
name = "switch"
|
||||||
version = "0.1.0"
|
version = "1.0.2"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
@@ -27,14 +27,14 @@ chrono = "0.4.23"
|
|||||||
#moka = "0.9.6"
|
#moka = "0.9.6"
|
||||||
protobuf = "3.2.0"
|
protobuf = "3.2.0"
|
||||||
#local-ip-address = "0.4.9"
|
#local-ip-address = "0.4.9"
|
||||||
|
socket2 ={ version = "0.5.2", features = ["all"] }
|
||||||
#mio = {version = "0.8.6",features = ["os-poll", "net"]}
|
tokio = { version = "1.28.1", features = ["full"] }
|
||||||
#tokio = { version = "1.24.1", features = ["full"] }
|
|
||||||
[target.'cfg(any(unix))'.dependencies]
|
[target.'cfg(any(unix))'.dependencies]
|
||||||
tun = { path = "./rust-tun" }
|
tun = { path = "./rust-tun" }
|
||||||
|
|
||||||
[target.'cfg(target_os = "windows")'.dependencies]
|
[target.'cfg(target_os = "windows")'.dependencies]
|
||||||
wintun = "0.2.1"
|
|
||||||
|
win-tun-tap = {path = "./win-tun-tap"}
|
||||||
libloading = "0.7.4"
|
libloading = "0.7.4"
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
|
|||||||
+1
-1
Submodule switch/p2p_channel updated: a9c49f79c6...9d2e02f629
@@ -0,0 +1,123 @@
|
|||||||
|
use std::fmt;
|
||||||
|
|
||||||
|
/// 地址解析协议,由IP地址找到MAC地址
|
||||||
|
/// https://www.ietf.org/rfc/rfc6747.txt
|
||||||
|
/*
|
||||||
|
0 2 4 5 6 8 10 (字节)
|
||||||
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
| 硬件类型|协议类型|硬件地址长度|协议地址长度|操作类型|
|
||||||
|
| 源MAC地址 | 源ip地址 |
|
||||||
|
| 目的MAC地址 | 目的ip地址 |
|
||||||
|
*/
|
||||||
|
use crate::error::*;
|
||||||
|
|
||||||
|
pub struct ArpPacket<B> {
|
||||||
|
buffer: B,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<B: AsRef<[u8]>> ArpPacket<B> {
|
||||||
|
pub fn unchecked(buffer: B) -> Self {
|
||||||
|
Self { buffer }
|
||||||
|
}
|
||||||
|
pub fn new(buffer: B) -> Result<Self> {
|
||||||
|
if buffer.as_ref().len() != 28 {
|
||||||
|
Err(Error::InvalidPacket)?
|
||||||
|
}
|
||||||
|
let packet = Self::unchecked(buffer);
|
||||||
|
Ok(packet)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<B: AsRef<[u8]>> ArpPacket<B> {
|
||||||
|
/// 硬件类型 以太网类型为1
|
||||||
|
pub fn hardware_type(&self) -> u16 {
|
||||||
|
u16::from_be_bytes(self.buffer.as_ref()[0..2].try_into().unwrap())
|
||||||
|
}
|
||||||
|
/// 上层协议类型,ipv4是0x0800
|
||||||
|
pub fn protocol_type(&self) -> u16 {
|
||||||
|
u16::from_be_bytes(self.buffer.as_ref()[2..4].try_into().unwrap())
|
||||||
|
}
|
||||||
|
/// 如果是MAC地址 则长度为6
|
||||||
|
pub fn hardware_size(&self) -> u8 {
|
||||||
|
self.buffer.as_ref()[4]
|
||||||
|
}
|
||||||
|
/// 如果是IPv4 则长度为4
|
||||||
|
pub fn protocol_size(&self) -> u8 {
|
||||||
|
self.buffer.as_ref()[5]
|
||||||
|
}
|
||||||
|
/// 操作类型,请求和响应 1:ARP请求,2:ARP响应,3:RARP请求,4:RARP响应
|
||||||
|
pub fn op_code(&self) -> u16 {
|
||||||
|
u16::from_be_bytes(self.buffer.as_ref()[6..8].try_into().unwrap())
|
||||||
|
}
|
||||||
|
/// 发送端硬件地址,仅支持以太网
|
||||||
|
pub fn sender_hardware_addr(&self) -> &[u8] {
|
||||||
|
&self.buffer.as_ref()[8..14]
|
||||||
|
}
|
||||||
|
/// 发送端协议地址,仅支持IPv4
|
||||||
|
pub fn sender_protocol_addr(&self) -> &[u8] {
|
||||||
|
&self.buffer.as_ref()[14..18]
|
||||||
|
}
|
||||||
|
/// 接收端硬件地址,仅支持以太网
|
||||||
|
pub fn target_hardware_addr(&self) -> &[u8] {
|
||||||
|
&self.buffer.as_ref()[18..24]
|
||||||
|
}
|
||||||
|
/// 接收端协议地址,仅支持IPv4
|
||||||
|
pub fn target_protocol_addr(&self) -> &[u8] {
|
||||||
|
&self.buffer.as_ref()[24..28]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<B: AsRef<[u8]> + AsMut<[u8]>> ArpPacket<B> {
|
||||||
|
/// 硬件类型 以太网类型为1
|
||||||
|
pub fn set_hardware_type(&mut self, value: u16) {
|
||||||
|
self.buffer.as_mut()[0..2].copy_from_slice(&value.to_be_bytes())
|
||||||
|
}
|
||||||
|
/// 上层协议类型,ipv4是0x0800
|
||||||
|
pub fn set_protocol_type(&mut self, value: u16) {
|
||||||
|
self.buffer.as_mut()[2..4].copy_from_slice(&value.to_be_bytes())
|
||||||
|
}
|
||||||
|
/// 如果是MAC地址 则长度为6
|
||||||
|
pub fn set_hardware_size(&mut self, value: u8) {
|
||||||
|
self.buffer.as_mut()[4] = value
|
||||||
|
}
|
||||||
|
/// 如果是IPv4 则长度为4
|
||||||
|
pub fn set_protocol_size(&mut self, value: u8) {
|
||||||
|
self.buffer.as_mut()[5] = value
|
||||||
|
}
|
||||||
|
/// 操作类型,请求和响应 1:ARP请求,2:ARP响应,3:RARP请求,4:RARP响应
|
||||||
|
pub fn set_op_code(&mut self, value: u16) {
|
||||||
|
self.buffer.as_mut()[6..8].copy_from_slice(&value.to_be_bytes())
|
||||||
|
}
|
||||||
|
/// 发送端硬件地址,仅支持以太网
|
||||||
|
pub fn set_sender_hardware_addr(&mut self, buf: &[u8]) {
|
||||||
|
self.buffer.as_mut()[8..14].copy_from_slice(buf)
|
||||||
|
}
|
||||||
|
/// 发送端协议地址,仅支持IPv4
|
||||||
|
pub fn set_sender_protocol_addr(&mut self, buf: &[u8]) {
|
||||||
|
self.buffer.as_mut()[14..18].copy_from_slice(buf)
|
||||||
|
}
|
||||||
|
/// 接收端硬件地址,仅支持以太网
|
||||||
|
pub fn set_target_hardware_addr(&mut self, buf: &[u8]) {
|
||||||
|
self.buffer.as_mut()[18..24].copy_from_slice(buf)
|
||||||
|
}
|
||||||
|
/// 接收端协议地址,仅支持IPv4
|
||||||
|
pub fn set_target_protocol_addr(&mut self, buf: &[u8]) {
|
||||||
|
self.buffer.as_mut()[24..28].copy_from_slice(buf)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<B: AsRef<[u8]>> fmt::Debug for ArpPacket<B> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
f.debug_struct("ArpPacket")
|
||||||
|
.field("hardware_type", &self.hardware_type())
|
||||||
|
.field("protocol_type", &self.protocol_type())
|
||||||
|
.field("hardware_size", &self.hardware_size())
|
||||||
|
.field("protocol_size", &self.protocol_size())
|
||||||
|
.field("op_code", &self.op_code())
|
||||||
|
.field("sender_hardware_addr", &self.sender_hardware_addr())
|
||||||
|
.field("sender_protocol_addr", &self.sender_protocol_addr())
|
||||||
|
.field("target_hardware_addr", &self.target_hardware_addr())
|
||||||
|
.field("target_protocol_addr", &self.target_protocol_addr())
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
pub mod arp;
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
pub mod packet;
|
||||||
|
pub mod protocol;
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
use std::fmt;
|
||||||
|
use crate::error::*;
|
||||||
|
use crate::ethernet::protocol::Protocol;
|
||||||
|
|
||||||
|
/// 以太网帧协议
|
||||||
|
/// https://www.ietf.org/rfc/rfc894.txt
|
||||||
|
/*
|
||||||
|
0 6 12 14 (字节)
|
||||||
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
| 目的地址 | 源地址 | 类型 |
|
||||||
|
*/
|
||||||
|
pub struct EthernetPacket<B> {
|
||||||
|
pub buffer: B,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<B: AsRef<[u8]>> EthernetPacket<B> {
|
||||||
|
pub fn unchecked(buffer: B) -> EthernetPacket<B> {
|
||||||
|
EthernetPacket { buffer }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new(buffer: B) -> Result<EthernetPacket<B>> {
|
||||||
|
let packet = EthernetPacket::unchecked(buffer);
|
||||||
|
//头部固定14位
|
||||||
|
if packet.buffer.as_ref().len() < 14 {
|
||||||
|
Err(Error::SmallBuffer)?
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(packet)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<B: AsRef<[u8]>> EthernetPacket<B> {
|
||||||
|
/// 目的MAC地址
|
||||||
|
pub fn destination(&self) -> &[u8] {
|
||||||
|
&self.buffer.as_ref()[0..6]
|
||||||
|
}
|
||||||
|
/// 源MAC地址
|
||||||
|
pub fn source(&self) -> &[u8] {
|
||||||
|
&self.buffer.as_ref()[6..12]
|
||||||
|
}
|
||||||
|
/// 3层协议
|
||||||
|
pub fn protocol(&self) -> Protocol {
|
||||||
|
u16::from_be_bytes(self.buffer.as_ref()[12..14].try_into().unwrap()).into()
|
||||||
|
}
|
||||||
|
/// 载荷
|
||||||
|
pub fn payload(&self) -> &[u8] {
|
||||||
|
&self.buffer.as_ref()[14..]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<B: AsRef<[u8]> + AsMut<[u8]>> EthernetPacket<B> {
|
||||||
|
pub fn set_destination(&mut self, value: &[u8]) {
|
||||||
|
self.buffer.as_mut()[0..6].copy_from_slice(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_source(&mut self, value: &[u8]) {
|
||||||
|
self.buffer.as_mut()[6..12].copy_from_slice(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_protocol(&mut self, value: Protocol) {
|
||||||
|
let p: u16 = value.into();
|
||||||
|
self.buffer.as_mut()[12..14].copy_from_slice(&p.to_be_bytes())
|
||||||
|
}
|
||||||
|
pub fn payload_mut(&mut self) -> &mut [u8] {
|
||||||
|
&mut self.buffer.as_mut()[14..]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<B: AsRef<[u8]>> fmt::Debug for EthernetPacket<B> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
f.debug_struct("EthernetPacket")
|
||||||
|
.field("destination", &self.destination())
|
||||||
|
.field("source", &self.source())
|
||||||
|
.field("protocol", &self.protocol())
|
||||||
|
.field("payload", &self.payload())
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,141 @@
|
|||||||
|
/// 以太网帧协议
|
||||||
|
#[derive(Eq, PartialEq, Copy, Clone, Debug)]
|
||||||
|
pub enum Protocol {
|
||||||
|
///
|
||||||
|
Ipv4,
|
||||||
|
|
||||||
|
///
|
||||||
|
Arp,
|
||||||
|
|
||||||
|
///
|
||||||
|
WakeOnLan,
|
||||||
|
|
||||||
|
///
|
||||||
|
Trill,
|
||||||
|
|
||||||
|
///
|
||||||
|
DecNet,
|
||||||
|
|
||||||
|
///
|
||||||
|
Rarp,
|
||||||
|
|
||||||
|
///
|
||||||
|
AppleTalk,
|
||||||
|
|
||||||
|
///
|
||||||
|
Aarp,
|
||||||
|
|
||||||
|
///
|
||||||
|
Ipx,
|
||||||
|
|
||||||
|
///
|
||||||
|
Qnx,
|
||||||
|
|
||||||
|
///
|
||||||
|
Ipv6,
|
||||||
|
|
||||||
|
///
|
||||||
|
FlowControl,
|
||||||
|
|
||||||
|
///
|
||||||
|
CobraNet,
|
||||||
|
|
||||||
|
///
|
||||||
|
Mpls,
|
||||||
|
|
||||||
|
///
|
||||||
|
MplsMulticast,
|
||||||
|
|
||||||
|
///
|
||||||
|
PppoeDiscovery,
|
||||||
|
|
||||||
|
///
|
||||||
|
PppoeSession,
|
||||||
|
|
||||||
|
///
|
||||||
|
Vlan,
|
||||||
|
|
||||||
|
///
|
||||||
|
PBridge,
|
||||||
|
|
||||||
|
///
|
||||||
|
Lldp,
|
||||||
|
|
||||||
|
///
|
||||||
|
Ptp,
|
||||||
|
|
||||||
|
///
|
||||||
|
Cfm,
|
||||||
|
|
||||||
|
///
|
||||||
|
QinQ,
|
||||||
|
|
||||||
|
///
|
||||||
|
Unknown(u16),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<u16> for Protocol {
|
||||||
|
fn from(value: u16) -> Protocol {
|
||||||
|
use self::Protocol::*;
|
||||||
|
|
||||||
|
match value {
|
||||||
|
0x0800 => Ipv4,
|
||||||
|
0x0806 => Arp,
|
||||||
|
0x0842 => WakeOnLan,
|
||||||
|
0x22f3 => Trill,
|
||||||
|
0x6003 => DecNet,
|
||||||
|
0x8035 => Rarp,
|
||||||
|
0x809b => AppleTalk,
|
||||||
|
0x80f3 => Aarp,
|
||||||
|
0x8137 => Ipx,
|
||||||
|
0x8204 => Qnx,
|
||||||
|
0x86dd => Ipv6,
|
||||||
|
0x8808 => FlowControl,
|
||||||
|
0x8819 => CobraNet,
|
||||||
|
0x8847 => Mpls,
|
||||||
|
0x8848 => MplsMulticast,
|
||||||
|
0x8863 => PppoeDiscovery,
|
||||||
|
0x8864 => PppoeSession,
|
||||||
|
0x8100 => Vlan,
|
||||||
|
0x88a8 => PBridge,
|
||||||
|
0x88cc => Lldp,
|
||||||
|
0x88f7 => Ptp,
|
||||||
|
0x8902 => Cfm,
|
||||||
|
0x9100 => QinQ,
|
||||||
|
n => Unknown(n),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Into<u16> for Protocol {
|
||||||
|
fn into(self) -> u16 {
|
||||||
|
use self::Protocol::*;
|
||||||
|
|
||||||
|
match self {
|
||||||
|
Ipv4 => 0x0800,
|
||||||
|
Arp => 0x0806,
|
||||||
|
WakeOnLan => 0x0842,
|
||||||
|
Trill => 0x22f3,
|
||||||
|
DecNet => 0x6003,
|
||||||
|
Rarp => 0x8035,
|
||||||
|
AppleTalk => 0x809b,
|
||||||
|
Aarp => 0x80f3,
|
||||||
|
Ipx => 0x8137,
|
||||||
|
Qnx => 0x8204,
|
||||||
|
Ipv6 => 0x86dd,
|
||||||
|
FlowControl => 0x8808,
|
||||||
|
CobraNet => 0x8819,
|
||||||
|
Mpls => 0x8847,
|
||||||
|
MplsMulticast => 0x8848,
|
||||||
|
PppoeDiscovery => 0x8863,
|
||||||
|
PppoeSession => 0x8864,
|
||||||
|
Vlan => 0x8100,
|
||||||
|
PBridge => 0x88a8,
|
||||||
|
Lldp => 0x88cc,
|
||||||
|
Ptp => 0x88f7,
|
||||||
|
Cfm => 0x8902,
|
||||||
|
QinQ => 0x9100,
|
||||||
|
Unknown(n) => n,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -21,7 +21,7 @@ use crate::icmp::{Code, Kind};
|
|||||||
use crate::ip::ipv4::packet::IpV4Packet;
|
use crate::ip::ipv4::packet::IpV4Packet;
|
||||||
|
|
||||||
pub struct IcmpPacket<B> {
|
pub struct IcmpPacket<B> {
|
||||||
buffer: B,
|
pub buffer: B,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<B: AsRef<[u8]>> IcmpPacket<B> {
|
impl<B: AsRef<[u8]>> IcmpPacket<B> {
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::net::Ipv4Addr;
|
use std::net::Ipv4Addr;
|
||||||
|
|
||||||
use byteorder::{BigEndian, ReadBytesExt};
|
|
||||||
|
|
||||||
use crate::cal_checksum;
|
use crate::cal_checksum;
|
||||||
use crate::error::*;
|
use crate::error::*;
|
||||||
@@ -141,16 +140,12 @@ impl<B: AsRef<[u8]>> IpV4Packet<B> {
|
|||||||
|
|
||||||
/// ip报总字节数
|
/// ip报总字节数
|
||||||
pub fn length(&self) -> u16 {
|
pub fn length(&self) -> u16 {
|
||||||
(&self.buffer.as_ref()[2..])
|
u16::from_be_bytes(self.buffer.as_ref()[2..4].try_into().unwrap())
|
||||||
.read_u16::<BigEndian>()
|
|
||||||
.unwrap()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 标识. ip报文在数据链路层可能会被拆分,同一报文的不同分组标识字段相同
|
/// 标识. ip报文在数据链路层可能会被拆分,同一报文的不同分组标识字段相同
|
||||||
pub fn id(&self) -> u16 {
|
pub fn id(&self) -> u16 {
|
||||||
(&self.buffer.as_ref()[4..])
|
u16::from_be_bytes(self.buffer.as_ref()[4..6].try_into().unwrap())
|
||||||
.read_u16::<BigEndian>()
|
|
||||||
.unwrap()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 标志 3位.
|
/// 标志 3位.
|
||||||
@@ -170,10 +165,7 @@ impl<B: AsRef<[u8]>> IpV4Packet<B> {
|
|||||||
/// 以字节为单位,用于指明分段起始点相对于包头起始点的偏移量
|
/// 以字节为单位,用于指明分段起始点相对于包头起始点的偏移量
|
||||||
/// 由于分段到达时可能错序,所以分段的偏移字段可以使接收者按照正确的顺序重组数据包
|
/// 由于分段到达时可能错序,所以分段的偏移字段可以使接收者按照正确的顺序重组数据包
|
||||||
pub fn offset(&self) -> u16 {
|
pub fn offset(&self) -> u16 {
|
||||||
(&self.buffer.as_ref()[6..])
|
u16::from_be_bytes(self.buffer.as_ref()[6..8].try_into().unwrap()) & 0x1fff
|
||||||
.read_u16::<BigEndian>()
|
|
||||||
.unwrap()
|
|
||||||
& 0x1fff
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 生存时间.
|
/// 生存时间.
|
||||||
@@ -189,9 +181,7 @@ impl<B: AsRef<[u8]>> IpV4Packet<B> {
|
|||||||
|
|
||||||
/// 首部校验和
|
/// 首部校验和
|
||||||
pub fn checksum(&self) -> u16 {
|
pub fn checksum(&self) -> u16 {
|
||||||
(&self.buffer.as_ref()[10..])
|
u16::from_be_bytes(self.buffer.as_ref()[10..12].try_into().unwrap())
|
||||||
.read_u16::<BigEndian>()
|
|
||||||
.unwrap()
|
|
||||||
}
|
}
|
||||||
/// 验证校验和
|
/// 验证校验和
|
||||||
///
|
///
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#[derive(Eq, PartialEq, Copy, Clone, Debug)]
|
#[derive(Eq, PartialEq,Ord, PartialOrd, Copy, Clone, Debug)]
|
||||||
pub enum Protocol {
|
pub enum Protocol {
|
||||||
///
|
///
|
||||||
Hopopt,
|
Hopopt,
|
||||||
|
|||||||
@@ -8,7 +8,8 @@ pub mod icmp;
|
|||||||
pub mod ip;
|
pub mod ip;
|
||||||
pub mod tcp;
|
pub mod tcp;
|
||||||
pub mod udp;
|
pub mod udp;
|
||||||
|
pub mod ethernet;
|
||||||
|
pub mod arp;
|
||||||
// pub enum IpUpperLayer<B> {
|
// pub enum IpUpperLayer<B> {
|
||||||
// UDP(UdpPacket<B>),
|
// UDP(UdpPacket<B>),
|
||||||
// Unknown(B),
|
// Unknown(B),
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::net::IpAddr;
|
use std::net::Ipv4Addr;
|
||||||
|
|
||||||
use byteorder::{BigEndian, ReadBytesExt};
|
|
||||||
|
|
||||||
use crate::error::*;
|
use crate::error::*;
|
||||||
use crate::tcp::Flags;
|
use crate::tcp::Flags;
|
||||||
@@ -48,20 +46,20 @@ use crate::tcp::Flags;
|
|||||||
Options+Padding:32位整数倍,最多40个字节
|
Options+Padding:32位整数倍,最多40个字节
|
||||||
*/
|
*/
|
||||||
pub struct TcpPacket<B> {
|
pub struct TcpPacket<B> {
|
||||||
source_ip: IpAddr,
|
source_ip: Ipv4Addr,
|
||||||
destination_ip: IpAddr,
|
destination_ip: Ipv4Addr,
|
||||||
buffer: B,
|
buffer: B,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<B: AsRef<[u8]>> TcpPacket<B> {
|
impl<B: AsRef<[u8]>> TcpPacket<B> {
|
||||||
pub fn unchecked(source_ip: IpAddr, destination_ip: IpAddr, buffer: B) -> TcpPacket<B> {
|
pub fn unchecked(source_ip: Ipv4Addr, destination_ip: Ipv4Addr, buffer: B) -> TcpPacket<B> {
|
||||||
TcpPacket {
|
TcpPacket {
|
||||||
source_ip,
|
source_ip,
|
||||||
destination_ip,
|
destination_ip,
|
||||||
buffer,
|
buffer,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn new(source_ip: IpAddr, destination_ip: IpAddr, buffer: B) -> Result<TcpPacket<B>> {
|
pub fn new(source_ip: Ipv4Addr, destination_ip: Ipv4Addr, buffer: B) -> Result<TcpPacket<B>> {
|
||||||
let packet = TcpPacket::unchecked(source_ip, destination_ip, buffer);
|
let packet = TcpPacket::unchecked(source_ip, destination_ip, buffer);
|
||||||
|
|
||||||
if packet.buffer.as_ref().len() < 20 {
|
if packet.buffer.as_ref().len() < 20 {
|
||||||
@@ -76,31 +74,41 @@ impl<B: AsRef<[u8]>> TcpPacket<B> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<B: AsRef<[u8]> + AsMut<[u8]>> TcpPacket<B> {
|
||||||
|
fn set_checksum(&mut self, value: u16) {
|
||||||
|
self.buffer.as_mut()[16..18].copy_from_slice(&value.to_be_bytes())
|
||||||
|
}
|
||||||
|
pub fn set_source_port(&mut self, value: u16) {
|
||||||
|
self.buffer.as_mut()[0..2].copy_from_slice(&value.to_be_bytes())
|
||||||
|
}
|
||||||
|
pub fn set_destination_port(&mut self, value: u16) {
|
||||||
|
self.buffer.as_mut()[2..4].copy_from_slice(&value.to_be_bytes())
|
||||||
|
}
|
||||||
|
/// 更新校验和
|
||||||
|
pub fn update_checksum(&mut self) {
|
||||||
|
//先将校验和置0
|
||||||
|
self.set_checksum(0);
|
||||||
|
self.set_checksum(self.cal_checksum())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<B: AsRef<[u8]>> TcpPacket<B> {
|
impl<B: AsRef<[u8]>> TcpPacket<B> {
|
||||||
/// 源端口
|
/// 源端口
|
||||||
pub fn source_port(&self) -> u16 {
|
pub fn source_port(&self) -> u16 {
|
||||||
(&self.buffer.as_ref()[0..])
|
u16::from_be_bytes(self.buffer.as_ref()[0..2].try_into().unwrap())
|
||||||
.read_u16::<BigEndian>()
|
|
||||||
.unwrap()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 目标端口
|
/// 目标端口
|
||||||
pub fn destination_port(&self) -> u16 {
|
pub fn destination_port(&self) -> u16 {
|
||||||
(&self.buffer.as_ref()[2..])
|
u16::from_be_bytes(self.buffer.as_ref()[2..4].try_into().unwrap())
|
||||||
.read_u16::<BigEndian>()
|
|
||||||
.unwrap()
|
|
||||||
}
|
}
|
||||||
/// 序列号
|
/// 序列号
|
||||||
pub fn sequence(&self) -> u32 {
|
pub fn sequence(&self) -> u32 {
|
||||||
(&self.buffer.as_ref()[4..])
|
u32::from_be_bytes(self.buffer.as_ref()[4..8].try_into().unwrap())
|
||||||
.read_u32::<BigEndian>()
|
|
||||||
.unwrap()
|
|
||||||
}
|
}
|
||||||
/// 确认号
|
/// 确认号
|
||||||
pub fn acknowledgment(&self) -> u32 {
|
pub fn acknowledgment(&self) -> u32 {
|
||||||
(&self.buffer.as_ref()[8..])
|
u32::from_be_bytes(self.buffer.as_ref()[8..12].try_into().unwrap())
|
||||||
.read_u32::<BigEndian>()
|
|
||||||
.unwrap()
|
|
||||||
}
|
}
|
||||||
/// 数据偏移 4字节为单位
|
/// 数据偏移 4字节为单位
|
||||||
pub fn data_offset(&self) -> u8 {
|
pub fn data_offset(&self) -> u8 {
|
||||||
@@ -110,14 +118,10 @@ impl<B: AsRef<[u8]>> TcpPacket<B> {
|
|||||||
Flags(self.buffer.as_ref()[13])
|
Flags(self.buffer.as_ref()[13])
|
||||||
}
|
}
|
||||||
pub fn window(&self) -> u16 {
|
pub fn window(&self) -> u16 {
|
||||||
(&self.buffer.as_ref()[14..])
|
u16::from_be_bytes(self.buffer.as_ref()[14..16].try_into().unwrap())
|
||||||
.read_u16::<BigEndian>()
|
|
||||||
.unwrap()
|
|
||||||
}
|
}
|
||||||
pub fn checksum(&self) -> u16 {
|
pub fn checksum(&self) -> u16 {
|
||||||
(&self.buffer.as_ref()[16..])
|
u16::from_be_bytes(self.buffer.as_ref()[16..18].try_into().unwrap())
|
||||||
.read_u16::<BigEndian>()
|
|
||||||
.unwrap()
|
|
||||||
}
|
}
|
||||||
/// 验证校验和,ipv4中为0表示不使用校验和,ipv6校验和不能为0
|
/// 验证校验和,ipv4中为0表示不使用校验和,ipv6校验和不能为0
|
||||||
/// TCP/IP协议栈不会自己计算校验和,而是简单地将一个空的校验和字段(零或随机填充)交给网卡硬件。
|
/// TCP/IP协议栈不会自己计算校验和,而是简单地将一个空的校验和字段(零或随机填充)交给网卡硬件。
|
||||||
@@ -126,26 +130,16 @@ impl<B: AsRef<[u8]>> TcpPacket<B> {
|
|||||||
self.checksum() == 0 || self.cal_checksum() == 0
|
self.checksum() == 0 || self.cal_checksum() == 0
|
||||||
}
|
}
|
||||||
fn cal_checksum(&self) -> u16 {
|
fn cal_checksum(&self) -> u16 {
|
||||||
match self.source_ip {
|
crate::ipv4_cal_checksum(
|
||||||
IpAddr::V4(src) => {
|
self.buffer.as_ref(),
|
||||||
if let IpAddr::V4(dest) = self.destination_ip {
|
&self.source_ip,
|
||||||
return crate::ipv4_cal_checksum(
|
&self.destination_ip,
|
||||||
self.buffer.as_ref(),
|
6,
|
||||||
&src,
|
self.buffer.as_ref().len() as u16,
|
||||||
&dest,
|
)
|
||||||
6,
|
|
||||||
self.buffer.as_ref().len() as u16,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
IpAddr::V6(_src) => {}
|
|
||||||
}
|
|
||||||
unimplemented!()
|
|
||||||
}
|
}
|
||||||
pub fn urgent_pointer(&self) -> u16 {
|
pub fn urgent_pointer(&self) -> u16 {
|
||||||
(&self.buffer.as_ref()[18..])
|
u16::from_be_bytes(self.buffer.as_ref()[18..20].try_into().unwrap())
|
||||||
.read_u16::<BigEndian>()
|
|
||||||
.unwrap()
|
|
||||||
}
|
}
|
||||||
pub fn options(&self) -> &[u8] {
|
pub fn options(&self) -> &[u8] {
|
||||||
&self.buffer.as_ref()[20..(self.data_offset() as usize * 4)]
|
&self.buffer.as_ref()[20..(self.data_offset() as usize * 4)]
|
||||||
|
|||||||
@@ -1,9 +1,5 @@
|
|||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::io::Cursor;
|
use std::net::Ipv4Addr;
|
||||||
use std::net::IpAddr;
|
|
||||||
|
|
||||||
use byteorder::WriteBytesExt;
|
|
||||||
use byteorder::{BigEndian, ReadBytesExt};
|
|
||||||
|
|
||||||
use crate::error::*;
|
use crate::error::*;
|
||||||
|
|
||||||
@@ -53,20 +49,20 @@ RFC 768 https://www.ietf.org/rfc/rfc768.txt
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
pub struct UdpPacket<B> {
|
pub struct UdpPacket<B> {
|
||||||
source_ip: IpAddr,
|
source_ip: Ipv4Addr,
|
||||||
destination_ip: IpAddr,
|
destination_ip: Ipv4Addr,
|
||||||
buffer: B,
|
buffer: B,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<B: AsRef<[u8]>> UdpPacket<B> {
|
impl<B: AsRef<[u8]>> UdpPacket<B> {
|
||||||
pub fn unchecked(source_ip: IpAddr, destination_ip: IpAddr, buffer: B) -> UdpPacket<B> {
|
pub fn unchecked(source_ip: Ipv4Addr, destination_ip: Ipv4Addr, buffer: B) -> UdpPacket<B> {
|
||||||
UdpPacket {
|
UdpPacket {
|
||||||
source_ip,
|
source_ip,
|
||||||
destination_ip,
|
destination_ip,
|
||||||
buffer,
|
buffer,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn new(source_ip: IpAddr, destination_ip: IpAddr, buffer: B) -> Result<UdpPacket<B>> {
|
pub fn new(source_ip: Ipv4Addr, destination_ip: Ipv4Addr, buffer: B) -> Result<UdpPacket<B>> {
|
||||||
if buffer.as_ref().len() < 8 {
|
if buffer.as_ref().len() < 8 {
|
||||||
Err(Error::SmallBuffer)?
|
Err(Error::SmallBuffer)?
|
||||||
}
|
}
|
||||||
@@ -78,30 +74,22 @@ impl<B: AsRef<[u8]>> UdpPacket<B> {
|
|||||||
impl<B: AsRef<[u8]>> UdpPacket<B> {
|
impl<B: AsRef<[u8]>> UdpPacket<B> {
|
||||||
/// 源端口
|
/// 源端口
|
||||||
pub fn source_port(&self) -> u16 {
|
pub fn source_port(&self) -> u16 {
|
||||||
(&self.buffer.as_ref()[0..])
|
u16::from_be_bytes(self.buffer.as_ref()[0..2].try_into().unwrap())
|
||||||
.read_u16::<BigEndian>()
|
|
||||||
.unwrap()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 目标端口
|
/// 目标端口
|
||||||
pub fn destination_port(&self) -> u16 {
|
pub fn destination_port(&self) -> u16 {
|
||||||
(&self.buffer.as_ref()[2..])
|
u16::from_be_bytes(self.buffer.as_ref()[2..4].try_into().unwrap())
|
||||||
.read_u16::<BigEndian>()
|
|
||||||
.unwrap()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 总字节数
|
/// 总字节数
|
||||||
pub fn length(&self) -> u16 {
|
pub fn length(&self) -> u16 {
|
||||||
(&self.buffer.as_ref()[4..])
|
u16::from_be_bytes(self.buffer.as_ref()[4..6].try_into().unwrap())
|
||||||
.read_u16::<BigEndian>()
|
|
||||||
.unwrap()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Checksum of the packet.
|
/// Checksum of the packet.
|
||||||
pub fn checksum(&self) -> u16 {
|
pub fn checksum(&self) -> u16 {
|
||||||
(&self.buffer.as_ref()[6..])
|
u16::from_be_bytes(self.buffer.as_ref()[6..8].try_into().unwrap())
|
||||||
.read_u16::<BigEndian>()
|
|
||||||
.unwrap()
|
|
||||||
}
|
}
|
||||||
/// 验证校验和,ipv4中为0表示不使用校验和,ipv6校验和不能为0
|
/// 验证校验和,ipv4中为0表示不使用校验和,ipv6校验和不能为0
|
||||||
pub fn is_valid(&self) -> bool {
|
pub fn is_valid(&self) -> bool {
|
||||||
@@ -111,21 +99,13 @@ impl<B: AsRef<[u8]>> UdpPacket<B> {
|
|||||||
&self.buffer.as_ref()[8..]
|
&self.buffer.as_ref()[8..]
|
||||||
}
|
}
|
||||||
fn cal_checksum(&self) -> u16 {
|
fn cal_checksum(&self) -> u16 {
|
||||||
match self.source_ip {
|
crate::ipv4_cal_checksum(
|
||||||
IpAddr::V4(src) => {
|
self.buffer.as_ref(),
|
||||||
if let IpAddr::V4(dest) = self.destination_ip {
|
&self.source_ip,
|
||||||
return crate::ipv4_cal_checksum(
|
&self.destination_ip,
|
||||||
self.buffer.as_ref(),
|
17,
|
||||||
&src,
|
self.length(),
|
||||||
&dest,
|
)
|
||||||
17,
|
|
||||||
self.length(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
IpAddr::V6(_src) => {}
|
|
||||||
}
|
|
||||||
unimplemented!()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -137,29 +117,21 @@ impl<B: AsRef<[u8]> + AsMut<[u8]>> UdpPacket<B> {
|
|||||||
|
|
||||||
impl<B: AsRef<[u8]> + AsMut<[u8]>> UdpPacket<B> {
|
impl<B: AsRef<[u8]> + AsMut<[u8]>> UdpPacket<B> {
|
||||||
/// 设置源端口
|
/// 设置源端口
|
||||||
pub fn set_source_port(&mut self, value: u16) -> &mut Self {
|
pub fn set_source_port(&mut self, value: u16) {
|
||||||
Cursor::new(&mut self.header_mut()[0..])
|
self.buffer.as_mut()[0..2].copy_from_slice(&value.to_be_bytes())
|
||||||
.write_u16::<BigEndian>(value)
|
|
||||||
.unwrap();
|
|
||||||
self
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 设置目的端口
|
/// 设置目的端口
|
||||||
pub fn set_destination_port(&mut self, value: u16) -> &mut Self {
|
pub fn set_destination_port(&mut self, value: u16) {
|
||||||
Cursor::new(&mut self.header_mut()[2..])
|
self.buffer.as_mut()[2..4].copy_from_slice(&value.to_be_bytes())
|
||||||
.write_u16::<BigEndian>(value)
|
|
||||||
.unwrap();
|
|
||||||
self
|
|
||||||
}
|
}
|
||||||
fn set_checknum(&mut self, value: u16) {
|
fn set_checksum(&mut self, value: u16) {
|
||||||
Cursor::new(&mut self.header_mut()[6..])
|
self.buffer.as_mut()[6..8].copy_from_slice(&value.to_be_bytes())
|
||||||
.write_u16::<BigEndian>(value)
|
|
||||||
.unwrap();
|
|
||||||
}
|
}
|
||||||
pub fn update_checknum(&mut self) {
|
pub fn update_checksum(&mut self) {
|
||||||
//先写0
|
//先写0
|
||||||
self.set_checknum(0);
|
self.set_checksum(0);
|
||||||
self.set_checknum(self.cal_checksum());
|
self.set_checksum(self.cal_checksum());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
// TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
// TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||||
//
|
//
|
||||||
// 0. You just DO WHAT THE FUCK YOU WANT TO.
|
// 0. You just DO WHAT THE FUCK YOU WANT TO.
|
||||||
|
#![cfg(unix)]
|
||||||
mod error;
|
mod error;
|
||||||
pub use crate::error::*;
|
pub use crate::error::*;
|
||||||
|
|
||||||
|
|||||||
@@ -112,6 +112,11 @@ impl AsRawFd for Reader {
|
|||||||
self.0.as_raw_fd()
|
self.0.as_raw_fd()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
impl AsRawFd for Writer {
|
||||||
|
fn as_raw_fd(&self) -> RawFd {
|
||||||
|
self.0.as_raw_fd()
|
||||||
|
}
|
||||||
|
}
|
||||||
//
|
//
|
||||||
// impl AsRawFd for Writer {
|
// impl AsRawFd for Writer {
|
||||||
// fn as_raw_fd(&self) -> RawFd {
|
// fn as_raw_fd(&self) -> RawFd {
|
||||||
|
|||||||
+67
-22
@@ -1,21 +1,27 @@
|
|||||||
use std::io;
|
use std::io;
|
||||||
use std::net::{Ipv4Addr, SocketAddr};
|
use std::net::{Ipv4Addr, SocketAddr};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use crossbeam::atomic::AtomicCell;
|
use crossbeam::atomic::AtomicCell;
|
||||||
use crossbeam_skiplist::SkipMap;
|
use crossbeam_skiplist::SkipMap;
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
|
|
||||||
use p2p_channel::boot::Boot;
|
use p2p_channel::boot::Boot;
|
||||||
use p2p_channel::channel::{Channel, Route, RouteKey};
|
use p2p_channel::channel::{Channel, Route, RouteKey};
|
||||||
use p2p_channel::punch::NatInfo;
|
use p2p_channel::punch::NatInfo;
|
||||||
use crate::handle::{ConnectStatus, CurrentDeviceInfo, heartbeat_handler, PeerDeviceInfo, punch_handler, recv_handler, registration_handler, tun_handler};
|
|
||||||
|
use crate::{tap_device, tun_device};
|
||||||
|
use crate::external_route::ExternalRoute;
|
||||||
|
use crate::handle::{ConnectStatus, CurrentDeviceInfo, CurrentDeviceInfoExt, heartbeat_handler, PeerDeviceInfo, punch_handler, recv_handler, registration_handler, tap_handler, tun_handler};
|
||||||
use crate::nat::NatTest;
|
use crate::nat::NatTest;
|
||||||
use crate::tun_device;
|
use crate::tap_device::TapWriter;
|
||||||
use crate::tun_device::TunReader;
|
use crate::tun_device::TunWriter;
|
||||||
|
|
||||||
pub struct Switch {
|
pub struct Switch {
|
||||||
name: String,
|
name: String,
|
||||||
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
||||||
tun_reader: TunReader,
|
tun_writer: Option<TunWriter>,
|
||||||
|
tap_writer: Option<TapWriter>,
|
||||||
nat_channel: Channel<Ipv4Addr>,
|
nat_channel: Channel<Ipv4Addr>,
|
||||||
/// 0. 机器纪元,每一次上线或者下线都会增1,用于感知网络中机器变化
|
/// 0. 机器纪元,每一次上线或者下线都会增1,用于感知网络中机器变化
|
||||||
/// 服务端和客户端的不一致,则服务端会推送新的设备列表
|
/// 服务端和客户端的不一致,则服务端会推送新的设备列表
|
||||||
@@ -27,7 +33,9 @@ pub struct Switch {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Switch {
|
impl Switch {
|
||||||
pub fn start(config: Config) -> crate::Result<Switch> {
|
pub async fn start(config: Config) -> crate::Result<Switch> {
|
||||||
|
log::info!("config:{:?}",config);
|
||||||
|
|
||||||
let (mut channel, punch, idle) = Boot::new::<Ipv4Addr>(80, 15000, 0)?;
|
let (mut channel, punch, idle) = Boot::new::<Ipv4Addr>(80, 15000, 0)?;
|
||||||
let response = registration_handler::registration(&mut channel, config.server_address, config.token.clone(), config.device_id.clone(), config.name.clone())?;
|
let response = registration_handler::registration(&mut channel, config.server_address, config.token.clone(), config.device_id.clone(), config.name.clone())?;
|
||||||
let register = Arc::new(registration_handler::Register::new(channel.sender()?, config.server_address, config.token.clone(), config.device_id.clone(), config.name.clone()));
|
let register = Arc::new(registration_handler::Register::new(channel.sender()?, config.server_address, config.token.clone(), config.device_id.clone(), config.name.clone()));
|
||||||
@@ -37,14 +45,47 @@ impl Switch {
|
|||||||
let virtual_ip = Ipv4Addr::from(response.virtual_ip);
|
let virtual_ip = Ipv4Addr::from(response.virtual_ip);
|
||||||
let virtual_gateway = Ipv4Addr::from(response.virtual_gateway);
|
let virtual_gateway = Ipv4Addr::from(response.virtual_gateway);
|
||||||
let virtual_netmask = Ipv4Addr::from(response.virtual_netmask);
|
let virtual_netmask = Ipv4Addr::from(response.virtual_netmask);
|
||||||
let current_device = Arc::new(AtomicCell::new(CurrentDeviceInfo::new(virtual_ip, virtual_gateway, virtual_netmask, config.server_address)));
|
|
||||||
let local_ip = crate::nat::local_ip()?;
|
let local_ip = crate::nat::local_ip()?;
|
||||||
let local_port = channel.local_addr()?.port();
|
let local_port = channel.local_addr()?.port();
|
||||||
// NAT检测
|
// NAT检测
|
||||||
let nat_test = NatTest::new(config.nat_test_server.clone(), Ipv4Addr::from(response.public_ip), response.public_port as u16, local_ip, local_port);
|
let nat_test = NatTest::new(config.nat_test_server.clone(), Ipv4Addr::from(response.public_ip), response.public_port as u16, local_ip, local_port);
|
||||||
// tun通道
|
let in_ips = config.in_ips.iter().map(|(dest, mask, _)| { (Ipv4Addr::from(*dest), Ipv4Addr::from(*mask)) }).collect::<Vec<(Ipv4Addr, Ipv4Addr)>>();
|
||||||
let (tun_writer, tun_reader) = tun_device::create_tun(virtual_ip, virtual_netmask, virtual_gateway)?;
|
|
||||||
|
|
||||||
|
let out_ips = config.out_ips.iter().map(|(_, _, ip)| *ip).collect::<Vec<Ipv4Addr>>();
|
||||||
|
let out_external_route = ExternalRoute::new(config.out_ips);
|
||||||
|
let in_external_route = ExternalRoute::new(config.in_ips);
|
||||||
|
let current_device = Arc::new(AtomicCell::new(CurrentDeviceInfo::new(virtual_ip, virtual_gateway, virtual_netmask, config.server_address)));
|
||||||
|
let ip_proxy_map = crate::ip_proxy::init_proxy(channel.sender()?,out_ips,current_device.clone()).await?;
|
||||||
|
let ( current_device_ext,tun_writer, tap_writer) = if config.tap {
|
||||||
|
#[cfg(windows)]
|
||||||
|
{
|
||||||
|
//删除switch的tun网卡避免ip冲突,因为非正常退出会保留网卡
|
||||||
|
tun_device::delete_tun();
|
||||||
|
}
|
||||||
|
let (tap_writer, tap_reader, mac) = tap_device::create_tap(virtual_ip, virtual_netmask, virtual_gateway)?;
|
||||||
|
let current_device_ext = Arc::new(AtomicCell::new(CurrentDeviceInfoExt::new( mac)));
|
||||||
|
//tap数据处理
|
||||||
|
tap_handler::start(channel.sender()?, tap_reader.clone(), tap_writer.clone(), current_device.clone(), in_external_route, ip_proxy_map.clone());
|
||||||
|
(current_device_ext, None, Some(tap_writer))
|
||||||
|
} else {
|
||||||
|
#[cfg(windows)]
|
||||||
|
{
|
||||||
|
//删除switch的tap网卡避免ip冲突,非正常退出会保留网卡
|
||||||
|
tap_device::delete_tap();
|
||||||
|
}
|
||||||
|
// tun通道
|
||||||
|
let (tun_writer, tun_reader) = tun_device::create_tun(virtual_ip, virtual_netmask, virtual_gateway,in_ips)?;
|
||||||
|
let current_device_ext = Arc::new(AtomicCell::new(CurrentDeviceInfoExt::new( [0, 0, 0, 0, 0, 0])));
|
||||||
|
//tun数据接收处理
|
||||||
|
tun_handler::start(channel.sender()?, tun_reader.clone(), tun_writer.clone(), current_device.clone(), in_external_route, ip_proxy_map.clone());
|
||||||
|
(current_device_ext,Some(tun_writer), None)
|
||||||
|
};
|
||||||
|
//外部数据接收处理
|
||||||
|
let channel_recv_handler = recv_handler::RecvHandler::new(channel.try_clone()?, current_device.clone(), current_device_ext,device_list.clone(), register.clone(),
|
||||||
|
nat_test.clone(), tun_writer.clone(), tap_writer.clone(),
|
||||||
|
connect_status.clone(), peer_nat_info_map.clone(), ip_proxy_map, out_external_route);
|
||||||
|
recv_handler::start(channel_recv_handler);
|
||||||
// 定时心跳
|
// 定时心跳
|
||||||
heartbeat_handler::start_heartbeat(channel.sender()?, device_list.clone(), current_device.clone());
|
heartbeat_handler::start_heartbeat(channel.sender()?, device_list.clone(), current_device.clone());
|
||||||
// 空闲检查
|
// 空闲检查
|
||||||
@@ -53,20 +94,12 @@ impl Switch {
|
|||||||
punch_handler::start_cone(punch.try_clone()?, current_device.clone());
|
punch_handler::start_cone(punch.try_clone()?, current_device.clone());
|
||||||
punch_handler::start_symmetric(punch, current_device.clone());
|
punch_handler::start_symmetric(punch, current_device.clone());
|
||||||
punch_handler::start_punch(nat_test.clone(), device_list.clone(), channel.sender()?, current_device.clone());
|
punch_handler::start_punch(nat_test.clone(), device_list.clone(), channel.sender()?, current_device.clone());
|
||||||
//tun数据接收处理
|
log::info!("switch启动成功");
|
||||||
for _ in 0..2 {
|
|
||||||
tun_handler::start(channel.sender()?, tun_reader.clone(), tun_writer.clone(), current_device.clone());
|
|
||||||
}
|
|
||||||
//外部数据接收处理
|
|
||||||
let channel_recv_handler = recv_handler::RecvHandler::new(channel.try_clone()?, current_device.clone(), device_list.clone(), register.clone(),
|
|
||||||
nat_test.clone(), tun_writer.clone(), connect_status.clone(), peer_nat_info_map.clone());
|
|
||||||
for _ in 0..2 {
|
|
||||||
recv_handler::start(channel_recv_handler.try_clone()?);
|
|
||||||
}
|
|
||||||
Ok(Switch {
|
Ok(Switch {
|
||||||
name: config.name,
|
name: config.name,
|
||||||
current_device,
|
current_device,
|
||||||
tun_reader,
|
tun_writer,
|
||||||
|
tap_writer,
|
||||||
nat_channel: channel,
|
nat_channel: channel,
|
||||||
nat_test,
|
nat_test,
|
||||||
device_list,
|
device_list,
|
||||||
@@ -108,7 +141,12 @@ impl Switch {
|
|||||||
self.nat_channel.route_table()
|
self.nat_channel.route_table()
|
||||||
}
|
}
|
||||||
pub fn stop(&self) -> io::Result<()> {
|
pub fn stop(&self) -> io::Result<()> {
|
||||||
self.tun_reader.close();
|
if let Some(tap) = &self.tap_writer {
|
||||||
|
tap.close()?;
|
||||||
|
}
|
||||||
|
if let Some(tun) = &self.tun_writer {
|
||||||
|
tun.close()?;
|
||||||
|
}
|
||||||
self.nat_channel.close()?;
|
self.nat_channel.close()?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -116,25 +154,32 @@ impl Switch {
|
|||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
|
pub tap: bool,
|
||||||
pub token: String,
|
pub token: String,
|
||||||
pub device_id: String,
|
pub device_id: String,
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub server_address: SocketAddr,
|
pub server_address: SocketAddr,
|
||||||
pub nat_test_server: Vec<SocketAddr>,
|
pub nat_test_server: Vec<SocketAddr>,
|
||||||
|
pub in_ips: Vec<(u32, u32, Ipv4Addr)>,
|
||||||
|
pub out_ips: Vec<(u32, u32, Ipv4Addr)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Config {
|
impl Config {
|
||||||
pub fn new(token: String,
|
pub fn new(tap: bool, token: String,
|
||||||
device_id: String,
|
device_id: String,
|
||||||
name: String,
|
name: String,
|
||||||
server_address: SocketAddr,
|
server_address: SocketAddr,
|
||||||
nat_test_server: Vec<SocketAddr>, ) -> Self {
|
nat_test_server: Vec<SocketAddr>,
|
||||||
|
in_ips: Vec<(u32, u32, Ipv4Addr)>, out_ips: Vec<(u32, u32, Ipv4Addr)>, ) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
tap,
|
||||||
token,
|
token,
|
||||||
device_id,
|
device_id,
|
||||||
name,
|
name,
|
||||||
server_address,
|
server_address,
|
||||||
nat_test_server,
|
nat_test_server,
|
||||||
|
in_ips,
|
||||||
|
out_ips,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
use std::net::Ipv4Addr;
|
||||||
|
|
||||||
|
// 目标ip,子网掩码,网关
|
||||||
|
|
||||||
|
pub struct ExternalRoute {
|
||||||
|
route_table: Vec<(u32, u32, Ipv4Addr)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ExternalRoute {
|
||||||
|
pub fn new(route_table: Vec<(u32, u32, Ipv4Addr)>) -> Self {
|
||||||
|
Self {
|
||||||
|
route_table
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn route(&self, ip: &Ipv4Addr) -> Option<Ipv4Addr> {
|
||||||
|
let ip = u32::from_be_bytes(ip.octets());
|
||||||
|
for (dest, mask, gateway) in &self.route_table {
|
||||||
|
if *mask & ip == *mask & *dest {
|
||||||
|
return Some(*gateway);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,48 +1,74 @@
|
|||||||
use std::{io, thread};
|
|
||||||
use std::net::Ipv4Addr;
|
use std::net::Ipv4Addr;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
use std::{io, thread};
|
||||||
|
|
||||||
use chrono::Local;
|
use chrono::Local;
|
||||||
use crossbeam::atomic::AtomicCell;
|
use crossbeam::atomic::AtomicCell;
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use rand::prelude::SliceRandom;
|
use rand::prelude::SliceRandom;
|
||||||
|
|
||||||
use p2p_channel::channel::Route;
|
|
||||||
use p2p_channel::channel::sender::Sender;
|
use p2p_channel::channel::sender::Sender;
|
||||||
|
use p2p_channel::channel::Route;
|
||||||
use p2p_channel::idle::Idle;
|
use p2p_channel::idle::Idle;
|
||||||
|
|
||||||
use crate::handle::{CurrentDeviceInfo, PeerDeviceInfo};
|
use crate::handle::{CurrentDeviceInfo, PeerDeviceInfo};
|
||||||
use crate::protocol::{control_packet, MAX_TTL, NetPacket, Protocol, Version};
|
|
||||||
use crate::protocol::control_packet::PingPacket;
|
use crate::protocol::control_packet::PingPacket;
|
||||||
|
use crate::protocol::{control_packet, NetPacket, Protocol, Version, MAX_TTL};
|
||||||
|
|
||||||
pub fn start_idle(idle: Idle<Ipv4Addr>, sender: Sender<Ipv4Addr>) {
|
pub fn start_idle(idle: Idle<Ipv4Addr>, sender: Sender<Ipv4Addr>) {
|
||||||
thread::spawn(move || {
|
thread::Builder::new()
|
||||||
if let Err(e) = start_idle_(idle, sender) {
|
.name("idle".into())
|
||||||
log::info!("空闲检测线程停止:{:?}",e);
|
.spawn(move || {
|
||||||
}
|
if let Err(e) = start_idle_(idle, sender) {
|
||||||
});
|
log::info!("空闲检测线程停止:{:?}", e);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn start_idle_(idle: Idle<Ipv4Addr>, sender: Sender<Ipv4Addr>) -> io::Result<()> {
|
fn start_idle_(idle: Idle<Ipv4Addr>, sender: Sender<Ipv4Addr>) -> io::Result<()> {
|
||||||
loop {
|
loop {
|
||||||
let (idle_status, peer_ips, route) = idle.next_idle()?;
|
let (idle_status, peer_ips, route) = idle.next_idle()?;
|
||||||
log::warn!("peer_ip:{:?},route:{:?},idle_status:{:?}",peer_ips,route,idle_status);
|
log::warn!(
|
||||||
|
"peer_ip:{:?},route:{:?},idle_status:{:?}",
|
||||||
|
peer_ips,
|
||||||
|
route,
|
||||||
|
idle_status
|
||||||
|
);
|
||||||
for peer_ip in peer_ips {
|
for peer_ip in peer_ips {
|
||||||
sender.remove_route(&peer_ip);
|
sender.remove_route(&peer_ip);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn start_heartbeat(sender: Sender<Ipv4Addr>, device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>, current_device: Arc<AtomicCell<CurrentDeviceInfo>>) {
|
pub fn start_heartbeat(
|
||||||
thread::spawn(move || {
|
sender: Sender<Ipv4Addr>,
|
||||||
if let Err(e) = start_heartbeat_(sender, device_list, current_device) {
|
device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>,
|
||||||
log::info!("空闲检测线程停止:{:?}",e);
|
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
||||||
}
|
) {
|
||||||
});
|
thread::Builder::new()
|
||||||
|
.name("heartbeat".into())
|
||||||
|
.spawn(move || {
|
||||||
|
if let Err(e) = start_heartbeat_(sender, device_list, current_device) {
|
||||||
|
log::info!("空闲检测线程停止:{:?}", e);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn start_heartbeat_(sender: Sender<Ipv4Addr>, device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>, current_device: Arc<AtomicCell<CurrentDeviceInfo>>) -> io::Result<()> {
|
fn set_now_time(packet: &mut NetPacket<[u8; 16]>) -> io::Result<()> {
|
||||||
|
let current_time = Local::now().timestamp_millis() as u16;
|
||||||
|
let mut ping = PingPacket::new(packet.payload_mut())?;
|
||||||
|
ping.set_time(current_time);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn start_heartbeat_(
|
||||||
|
sender: Sender<Ipv4Addr>,
|
||||||
|
device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>,
|
||||||
|
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
||||||
|
) -> io::Result<()> {
|
||||||
let mut net_packet = NetPacket::new([0u8; 16])?;
|
let mut net_packet = NetPacket::new([0u8; 16])?;
|
||||||
net_packet.set_version(Version::V1);
|
net_packet.set_version(Version::V1);
|
||||||
net_packet.set_protocol(Protocol::Control);
|
net_packet.set_protocol(Protocol::Control);
|
||||||
@@ -53,9 +79,7 @@ fn start_heartbeat_(sender: Sender<Ipv4Addr>, device_list: Arc<Mutex<(u16, Vec<P
|
|||||||
let current_device = current_device.load();
|
let current_device = current_device.load();
|
||||||
net_packet.set_source(current_device.virtual_ip());
|
net_packet.set_source(current_device.virtual_ip());
|
||||||
{
|
{
|
||||||
let current_time = Local::now().timestamp_millis() as u16;
|
|
||||||
let mut ping = PingPacket::new(net_packet.payload_mut())?;
|
let mut ping = PingPacket::new(net_packet.payload_mut())?;
|
||||||
ping.set_time(current_time);
|
|
||||||
let epoch = { device_list.lock().0 };
|
let epoch = { device_list.lock().0 };
|
||||||
ping.set_epoch(epoch);
|
ping.set_epoch(epoch);
|
||||||
}
|
}
|
||||||
@@ -63,9 +87,13 @@ fn start_heartbeat_(sender: Sender<Ipv4Addr>, device_list: Arc<Mutex<(u16, Vec<P
|
|||||||
let mut route_list: Option<Vec<(Ipv4Addr, Route)>> = None;
|
let mut route_list: Option<Vec<(Ipv4Addr, Route)>> = None;
|
||||||
let peer_list = device_list.lock().1.clone();
|
let peer_list = device_list.lock().1.clone();
|
||||||
for peer in peer_list {
|
for peer in peer_list {
|
||||||
net_packet.first_set_ttl(MAX_TTL);
|
set_now_time(&mut net_packet)?;
|
||||||
|
net_packet.first_set_ttl(2);
|
||||||
net_packet.set_destination(peer.virtual_ip);
|
net_packet.set_destination(peer.virtual_ip);
|
||||||
if sender.send_to_id(net_packet.buffer(), &peer.virtual_ip).is_err() {
|
if sender
|
||||||
|
.send_to_id(net_packet.buffer(), &peer.virtual_ip)
|
||||||
|
.is_err()
|
||||||
|
{
|
||||||
//没有路由则发送到网关
|
//没有路由则发送到网关
|
||||||
let _ = sender.send_to_addr(net_packet.buffer(), current_device.connect_server);
|
let _ = sender.send_to_addr(net_packet.buffer(), current_device.connect_server);
|
||||||
//再随机发送到其他地址,看有没有客户端符合转发条件
|
//再随机发送到其他地址,看有没有客户端符合转发条件
|
||||||
@@ -75,9 +103,11 @@ fn start_heartbeat_(sender: Sender<Ipv4Addr>, device_list: Arc<Mutex<(u16, Vec<P
|
|||||||
l
|
l
|
||||||
});
|
});
|
||||||
let mut num = 0;
|
let mut num = 0;
|
||||||
|
//只寻找两跳以内能到的目标
|
||||||
net_packet.first_set_ttl(2);
|
net_packet.first_set_ttl(2);
|
||||||
for (peer_ip, route) in route_list.iter() {
|
for (peer_ip, route) in route_list.iter() {
|
||||||
if peer_ip != &peer.virtual_ip && route.metric == 1 {
|
if peer_ip != &peer.virtual_ip && route.metric == 1 {
|
||||||
|
set_now_time(&mut net_packet)?;
|
||||||
let _ = sender.send_to_route(net_packet.buffer(), &route.route_key());
|
let _ = sender.send_to_route(net_packet.buffer(), &route.route_key());
|
||||||
num += 1;
|
num += 1;
|
||||||
}
|
}
|
||||||
@@ -88,15 +118,22 @@ fn start_heartbeat_(sender: Sender<Ipv4Addr>, device_list: Arc<Mutex<(u16, Vec<P
|
|||||||
}
|
}
|
||||||
thread::sleep(Duration::from_millis(1));
|
thread::sleep(Duration::from_millis(1));
|
||||||
}
|
}
|
||||||
|
set_now_time(&mut net_packet)?;
|
||||||
net_packet.set_destination(current_device.virtual_gateway());
|
net_packet.set_destination(current_device.virtual_gateway());
|
||||||
if let Err(e) = sender.send_to_addr(net_packet.buffer(), current_device.connect_server) {
|
if let Err(e) = sender.send_to_addr(net_packet.buffer(), current_device.connect_server)
|
||||||
log::warn!("connect_server:{:?},e:{:?}",current_device.connect_server,e);
|
{
|
||||||
|
log::warn!(
|
||||||
|
"connect_server:{:?},e:{:?}",
|
||||||
|
current_device.connect_server,
|
||||||
|
e
|
||||||
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (peer_ip, route) in sender.route_table().iter() {
|
for (peer_ip, route) in sender.route_table().iter() {
|
||||||
|
set_now_time(&mut net_packet)?;
|
||||||
net_packet.set_destination(*peer_ip);
|
net_packet.set_destination(*peer_ip);
|
||||||
if let Err(e) = sender.send_to_route(net_packet.buffer(), &route.route_key()) {
|
if let Err(e) = sender.send_to_route(net_packet.buffer(), &route.route_key()) {
|
||||||
log::warn!("peer_ip:{:?},route:{:?},e:{:?}",peer_ip,route,e);
|
log::warn!("peer_ip:{:?},route:{:?},e:{:?}", peer_ip, route, e);
|
||||||
}
|
}
|
||||||
thread::sleep(Duration::from_millis(1));
|
thread::sleep(Duration::from_millis(1));
|
||||||
}
|
}
|
||||||
@@ -105,4 +142,4 @@ fn start_heartbeat_(sender: Sender<Ipv4Addr>, device_list: Arc<Mutex<(u16, Vec<P
|
|||||||
count += 1;
|
count += 1;
|
||||||
thread::sleep(Duration::from_millis(5000));
|
thread::sleep(Duration::from_millis(5000));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
use std::net::{Ipv4Addr, SocketAddr};
|
use std::net::{Ipv4Addr, SocketAddr};
|
||||||
|
|
||||||
pub mod heartbeat_handler;
|
pub mod heartbeat_handler;
|
||||||
pub mod punch_handler;
|
|
||||||
pub mod registration_handler;
|
|
||||||
pub mod tun_handler;
|
pub mod tun_handler;
|
||||||
|
pub mod tap_handler;
|
||||||
|
pub mod punch_handler;
|
||||||
pub mod recv_handler;
|
pub mod recv_handler;
|
||||||
|
pub mod registration_handler;
|
||||||
|
|
||||||
/// 是否在一个网段
|
/// 是否在一个网段
|
||||||
fn check_dest(dest: Ipv4Addr, virtual_netmask: Ipv4Addr, virtual_network: Ipv4Addr) -> bool {
|
fn check_dest(dest: Ipv4Addr, virtual_netmask: Ipv4Addr, virtual_network: Ipv4Addr) -> bool {
|
||||||
@@ -59,6 +60,19 @@ pub enum ConnectStatus {
|
|||||||
Connected,
|
Connected,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||||
|
pub struct CurrentDeviceInfoExt {
|
||||||
|
pub mac: [u8; 6],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CurrentDeviceInfoExt {
|
||||||
|
pub fn new(mac: [u8; 6]) -> Self {
|
||||||
|
Self {
|
||||||
|
mac,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||||
pub struct CurrentDeviceInfo {
|
pub struct CurrentDeviceInfo {
|
||||||
virtual_ip: Ipv4Addr,
|
virtual_ip: Ipv4Addr,
|
||||||
@@ -70,6 +84,7 @@ pub struct CurrentDeviceInfo {
|
|||||||
pub broadcast_address: Ipv4Addr,
|
pub broadcast_address: Ipv4Addr,
|
||||||
//链接的服务器地址
|
//链接的服务器地址
|
||||||
pub connect_server: SocketAddr,
|
pub connect_server: SocketAddr,
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CurrentDeviceInfo {
|
impl CurrentDeviceInfo {
|
||||||
@@ -103,7 +118,3 @@ impl CurrentDeviceInfo {
|
|||||||
self.virtual_gateway
|
self.virtual_gateway
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,35 +1,45 @@
|
|||||||
use std::{io, thread};
|
|
||||||
use std::net::{IpAddr, Ipv4Addr};
|
|
||||||
use std::sync::Arc;
|
|
||||||
use std::time::Duration;
|
|
||||||
use crossbeam::atomic::AtomicCell;
|
|
||||||
use parking_lot::Mutex;
|
|
||||||
use protobuf::Message;
|
|
||||||
use rand::prelude::SliceRandom;
|
|
||||||
use p2p_channel::channel::sender::Sender;
|
|
||||||
use p2p_channel::punch::{NatInfo, NatType, Punch};
|
|
||||||
use crate::handle::{CurrentDeviceInfo, PeerDeviceInfo};
|
use crate::handle::{CurrentDeviceInfo, PeerDeviceInfo};
|
||||||
use crate::nat::NatTest;
|
use crate::nat::NatTest;
|
||||||
use crate::proto::message::{PunchInfo, PunchNatType};
|
use crate::proto::message::{PunchInfo, PunchNatType};
|
||||||
use crate::protocol::{control_packet, MAX_TTL, NetPacket, Protocol, turn_packet, Version};
|
use crate::protocol::{control_packet, turn_packet, NetPacket, Protocol, Version, MAX_TTL};
|
||||||
|
use crossbeam::atomic::AtomicCell;
|
||||||
|
use p2p_channel::channel::sender::Sender;
|
||||||
|
use p2p_channel::punch::{NatInfo, NatType, Punch};
|
||||||
|
use parking_lot::Mutex;
|
||||||
|
use protobuf::Message;
|
||||||
|
use rand::prelude::SliceRandom;
|
||||||
|
use std::net::{IpAddr, Ipv4Addr};
|
||||||
|
use std::sync::Arc;
|
||||||
|
use std::time::Duration;
|
||||||
|
use std::{io, thread};
|
||||||
|
|
||||||
pub fn start_cone(punch: Punch<Ipv4Addr>, current_device: Arc<AtomicCell<CurrentDeviceInfo>>) {
|
pub fn start_cone(punch: Punch<Ipv4Addr>, current_device: Arc<AtomicCell<CurrentDeviceInfo>>) {
|
||||||
thread::spawn(move || {
|
thread::Builder::new()
|
||||||
if let Err(e) = start_(true, punch, current_device) {
|
.name("punch-cone".into())
|
||||||
log::warn!("锥形网络打洞处理线程停止 {:?}",e);
|
.spawn(move || {
|
||||||
}
|
if let Err(e) = start_(true, punch, current_device) {
|
||||||
});
|
log::warn!("锥形网络打洞处理线程停止 {:?}", e);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn start_symmetric(punch: Punch<Ipv4Addr>, current_device: Arc<AtomicCell<CurrentDeviceInfo>>) {
|
pub fn start_symmetric(punch: Punch<Ipv4Addr>, current_device: Arc<AtomicCell<CurrentDeviceInfo>>) {
|
||||||
thread::spawn(move || {
|
thread::Builder::new()
|
||||||
if let Err(e) = start_(false, punch, current_device) {
|
.name("punch-symmetric".into())
|
||||||
log::warn!("对称网络打洞处理线程停止 {:?}",e);
|
.spawn(move || {
|
||||||
}
|
if let Err(e) = start_(false, punch, current_device) {
|
||||||
});
|
log::warn!("对称网络打洞处理线程停止 {:?}", e);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn start_(is_cone: bool, mut punch: Punch<Ipv4Addr>, current_device: Arc<AtomicCell<CurrentDeviceInfo>>) -> io::Result<()> {
|
fn start_(
|
||||||
|
is_cone: bool,
|
||||||
|
mut punch: Punch<Ipv4Addr>,
|
||||||
|
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
||||||
|
) -> io::Result<()> {
|
||||||
let mut packet = NetPacket::new([0u8; 12])?;
|
let mut packet = NetPacket::new([0u8; 12])?;
|
||||||
packet.set_version(Version::V1);
|
packet.set_version(Version::V1);
|
||||||
packet.first_set_ttl(1);
|
packet.first_set_ttl(1);
|
||||||
@@ -49,22 +59,35 @@ fn start_(is_cone: bool, mut punch: Punch<Ipv4Addr>, current_device: Arc<AtomicC
|
|||||||
}
|
}
|
||||||
packet.set_source(current_device.load().virtual_ip());
|
packet.set_source(current_device.load().virtual_ip());
|
||||||
packet.set_destination(peer_ip);
|
packet.set_destination(peer_ip);
|
||||||
log::info!("发起打洞,目标:{:?},{:?}",peer_ip,nat_info);
|
log::info!("发起打洞,目标:{:?},{:?}", peer_ip, nat_info);
|
||||||
if let Err(e) = punch.punch(packet.buffer(), peer_ip, nat_info) {
|
if let Err(e) = punch.punch(packet.buffer(), peer_ip, nat_info) {
|
||||||
log::warn!("peer_ip:{:?},e:{:?}",peer_ip,e);
|
log::warn!("peer_ip:{:?},e:{:?}", peer_ip, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn start_punch(nat_test: NatTest, device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>, sender: Sender<Ipv4Addr>, current_device: Arc<AtomicCell<CurrentDeviceInfo>>) {
|
pub fn start_punch(
|
||||||
thread::spawn(move || {
|
nat_test: NatTest,
|
||||||
if let Err(e) = start_punch_(nat_test, device_list, sender, current_device) {
|
device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>,
|
||||||
log::warn!("对称网络打洞处理线程停止 {:?}",e);
|
sender: Sender<Ipv4Addr>,
|
||||||
}
|
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
||||||
});
|
) {
|
||||||
|
thread::Builder::new()
|
||||||
|
.name("punch-send-request".into())
|
||||||
|
.spawn(move || {
|
||||||
|
if let Err(e) = start_punch_(nat_test, device_list, sender, current_device) {
|
||||||
|
log::warn!("对称网络打洞处理线程停止 {:?}", e);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn start_punch_(nat_test: NatTest, device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>, sender: Sender<Ipv4Addr>, current_device: Arc<AtomicCell<CurrentDeviceInfo>>) -> crate::Result<()> {
|
fn start_punch_(
|
||||||
|
nat_test: NatTest,
|
||||||
|
device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>,
|
||||||
|
sender: Sender<Ipv4Addr>,
|
||||||
|
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
||||||
|
) -> crate::Result<()> {
|
||||||
loop {
|
loop {
|
||||||
if sender.is_close() {
|
if sender.is_close() {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
@@ -104,19 +127,23 @@ fn start_punch_(nat_test: NatTest, device_list: Arc<Mutex<(u16, Vec<PeerDeviceIn
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn punch_packet(virtual_ip: Ipv4Addr, nat_info: &NatInfo, dest: Ipv4Addr) -> crate::Result<Vec<u8>> {
|
pub fn punch_packet(
|
||||||
|
virtual_ip: Ipv4Addr,
|
||||||
|
nat_info: &NatInfo,
|
||||||
|
dest: Ipv4Addr,
|
||||||
|
) -> crate::Result<Vec<u8>> {
|
||||||
let mut punch_reply = PunchInfo::new();
|
let mut punch_reply = PunchInfo::new();
|
||||||
punch_reply.reply = false;
|
punch_reply.reply = false;
|
||||||
punch_reply.public_ip_list = nat_info.public_ips.iter().map(|i| {
|
punch_reply.public_ip_list = nat_info
|
||||||
match i {
|
.public_ips
|
||||||
IpAddr::V4(ip) => {
|
.iter()
|
||||||
u32::from_be_bytes(ip.octets())
|
.map(|i| match i {
|
||||||
}
|
IpAddr::V4(ip) => u32::from_be_bytes(ip.octets()),
|
||||||
IpAddr::V6(_) => {
|
IpAddr::V6(_) => {
|
||||||
panic!()
|
panic!()
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
}).collect();
|
.collect();
|
||||||
punch_reply.public_port = nat_info.public_port as u32;
|
punch_reply.public_port = nat_info.public_port as u32;
|
||||||
punch_reply.public_port_range = nat_info.public_port_range as u32;
|
punch_reply.public_port_range = nat_info.public_port_range as u32;
|
||||||
punch_reply.local_ip = match nat_info.local_ip {
|
punch_reply.local_ip = match nat_info.local_ip {
|
||||||
@@ -137,4 +164,4 @@ pub fn punch_packet(virtual_ip: Ipv4Addr, nat_info: &NatInfo, dest: Ipv4Addr) ->
|
|||||||
net_packet.set_destination(dest);
|
net_packet.set_destination(dest);
|
||||||
net_packet.set_payload(&bytes);
|
net_packet.set_payload(&bytes);
|
||||||
Ok(net_packet.into_buffer())
|
Ok(net_packet.into_buffer())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
use std::{io, thread};
|
use std::thread;
|
||||||
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
|
use std::net::{IpAddr, Ipv4Addr, SocketAddr, SocketAddrV4};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use chrono::Local;
|
use chrono::Local;
|
||||||
@@ -10,23 +10,28 @@ use protobuf::Message;
|
|||||||
|
|
||||||
use p2p_channel::channel::{Channel, Route, RouteKey};
|
use p2p_channel::channel::{Channel, Route, RouteKey};
|
||||||
use p2p_channel::punch::NatInfo;
|
use p2p_channel::punch::NatInfo;
|
||||||
|
use packet::ethernet;
|
||||||
use packet::icmp::{icmp, Kind};
|
use packet::icmp::{icmp, Kind};
|
||||||
|
use packet::icmp::icmp::HeaderOther;
|
||||||
use packet::ip::ipv4;
|
use packet::ip::ipv4;
|
||||||
use packet::ip::ipv4::packet::IpV4Packet;
|
use packet::ip::ipv4::packet::IpV4Packet;
|
||||||
|
|
||||||
use crate::error::Error;
|
use crate::error::Error;
|
||||||
use crate::handle::{check_dest, ConnectStatus, CurrentDeviceInfo, PeerDeviceInfo};
|
use crate::external_route::ExternalRoute;
|
||||||
|
use crate::handle::{check_dest, ConnectStatus, CurrentDeviceInfo, CurrentDeviceInfoExt, PeerDeviceInfo};
|
||||||
use crate::handle::registration_handler::Register;
|
use crate::handle::registration_handler::Register;
|
||||||
|
use crate::ip_proxy::IpProxyMap;
|
||||||
use crate::nat;
|
use crate::nat;
|
||||||
use crate::nat::NatTest;
|
use crate::nat::NatTest;
|
||||||
use crate::proto::message::{DeviceList, PunchInfo, PunchNatType, RegistrationResponse};
|
use crate::proto::message::{DeviceList, PunchInfo, PunchNatType, RegistrationResponse};
|
||||||
use crate::protocol::{control_packet, MAX_TTL, NetPacket, Protocol, service_packet, turn_packet, Version};
|
use crate::protocol::{control_packet, MAX_TTL, NetPacket, Protocol, service_packet, turn_packet, Version};
|
||||||
use crate::protocol::control_packet::ControlPacket;
|
use crate::protocol::control_packet::ControlPacket;
|
||||||
use crate::protocol::error_packet::InErrorPacket;
|
use crate::protocol::error_packet::InErrorPacket;
|
||||||
|
use crate::tap_device::TapWriter;
|
||||||
use crate::tun_device::TunWriter;
|
use crate::tun_device::TunWriter;
|
||||||
|
|
||||||
pub fn start(mut handler: RecvHandler) {
|
pub fn start(mut handler: RecvHandler) {
|
||||||
thread::spawn(move || {
|
thread::Builder::new().name("udp-recv-handler".into()).spawn(move || {
|
||||||
let mut buf = [0; 4096];
|
let mut buf = [0; 4096];
|
||||||
loop {
|
loop {
|
||||||
match handler.channel.recv_from(&mut buf, None) {
|
match handler.channel.recv_from(&mut buf, None) {
|
||||||
@@ -48,53 +53,66 @@ pub fn start(mut handler: RecvHandler) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
}).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct RecvHandler {
|
pub struct RecvHandler {
|
||||||
channel: Channel<Ipv4Addr>,
|
channel: Channel<Ipv4Addr>,
|
||||||
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
||||||
|
current_device_ext: Arc<AtomicCell<CurrentDeviceInfoExt>>,
|
||||||
device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>,
|
device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>,
|
||||||
register: Arc<Register>,
|
register: Arc<Register>,
|
||||||
nat_test: NatTest,
|
nat_test: NatTest,
|
||||||
tun_writer: TunWriter,
|
tun_writer: Option<TunWriter>,
|
||||||
|
tap_writer: Option<TapWriter>,
|
||||||
connect_status: Arc<AtomicCell<ConnectStatus>>,
|
connect_status: Arc<AtomicCell<ConnectStatus>>,
|
||||||
peer_nat_info_map: Arc<SkipMap<Ipv4Addr, NatInfo>>,
|
peer_nat_info_map: Arc<SkipMap<Ipv4Addr, NatInfo>>,
|
||||||
|
ip_proxy_map: IpProxyMap,
|
||||||
|
out_external_route: ExternalRoute,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RecvHandler {
|
impl RecvHandler {
|
||||||
pub fn new(channel: Channel<Ipv4Addr>,
|
pub fn new(channel: Channel<Ipv4Addr>,
|
||||||
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
||||||
|
current_device_ext: Arc<AtomicCell<CurrentDeviceInfoExt>>,
|
||||||
device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>,
|
device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>,
|
||||||
register: Arc<Register>,
|
register: Arc<Register>,
|
||||||
nat_test: NatTest,
|
nat_test: NatTest,
|
||||||
tun_writer: TunWriter,
|
tun_writer: Option<TunWriter>,
|
||||||
|
tap_writer: Option<TapWriter>,
|
||||||
connect_status: Arc<AtomicCell<ConnectStatus>>,
|
connect_status: Arc<AtomicCell<ConnectStatus>>,
|
||||||
peer_nat_info_map: Arc<SkipMap<Ipv4Addr, NatInfo>>,
|
peer_nat_info_map: Arc<SkipMap<Ipv4Addr, NatInfo>>,
|
||||||
|
ip_proxy_map: IpProxyMap,
|
||||||
|
out_external_route: ExternalRoute,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
channel,
|
channel,
|
||||||
current_device,
|
current_device,
|
||||||
|
current_device_ext,
|
||||||
device_list,
|
device_list,
|
||||||
register,
|
register,
|
||||||
nat_test,
|
nat_test,
|
||||||
tun_writer,
|
tun_writer,
|
||||||
|
tap_writer,
|
||||||
connect_status,
|
connect_status,
|
||||||
peer_nat_info_map,
|
peer_nat_info_map,
|
||||||
|
ip_proxy_map,
|
||||||
|
out_external_route,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn try_clone(&self) -> io::Result<Self> {
|
// pub fn try_clone(&self) -> io::Result<Self> {
|
||||||
Ok(Self {
|
// Ok(Self {
|
||||||
channel: self.channel.try_clone()?,
|
// channel: self.channel.try_clone()?,
|
||||||
current_device: self.current_device.clone(),
|
// current_device: self.current_device.clone(),
|
||||||
device_list: self.device_list.clone(),
|
// device_list: self.device_list.clone(),
|
||||||
register: self.register.clone(),
|
// register: self.register.clone(),
|
||||||
nat_test: self.nat_test.clone(),
|
// nat_test: self.nat_test.clone(),
|
||||||
tun_writer: self.tun_writer.clone(),
|
// tun_writer: self.tun_writer.clone(),
|
||||||
connect_status: self.connect_status.clone(),
|
// tap_writer: self.tap_writer.clone(),
|
||||||
peer_nat_info_map: self.peer_nat_info_map.clone(),
|
// connect_status: self.connect_status.clone(),
|
||||||
})
|
// peer_nat_info_map: self.peer_nat_info_map.clone(),
|
||||||
}
|
// })
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RecvHandler {
|
impl RecvHandler {
|
||||||
@@ -109,7 +127,8 @@ impl RecvHandler {
|
|||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
let destination = net_packet.destination();
|
let destination = net_packet.destination();
|
||||||
if current_device.virtual_ip() != destination && self.connect_status.load() == ConnectStatus::Connected {
|
if !destination.is_broadcast() && destination != current_device.broadcast_address
|
||||||
|
&& current_device.virtual_ip() != destination && self.connect_status.load() == ConnectStatus::Connected {
|
||||||
if !check_dest(source, current_device.virtual_netmask, current_device.virtual_network) {
|
if !check_dest(source, current_device.virtual_netmask, current_device.virtual_network) {
|
||||||
log::warn!("转发数据,源地址错误:{:?},当前网络:{:?},route_key:{:?}",source,current_device.virtual_network,route_key);
|
log::warn!("转发数据,源地址错误:{:?},当前网络:{:?},route_key:{:?}",source,current_device.virtual_network,route_key);
|
||||||
return Ok(());
|
return Ok(());
|
||||||
@@ -118,15 +137,15 @@ impl RecvHandler {
|
|||||||
log::warn!("转发数据,目的地址错误:{:?},当前网络:{:?},route_key:{:?}",destination,current_device.virtual_network,route_key);
|
log::warn!("转发数据,目的地址错误:{:?},当前网络:{:?},route_key:{:?}",destination,current_device.virtual_network,route_key);
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
net_packet.set_ttl(net_packet.ttl() - 1);
|
||||||
let ttl = net_packet.ttl();
|
let ttl = net_packet.ttl();
|
||||||
if ttl > 1 {
|
if ttl > 0 {
|
||||||
// 转发
|
// 转发
|
||||||
net_packet.set_ttl(ttl - 1);
|
|
||||||
if let Some(route) = self.channel.route(&destination) {
|
if let Some(route) = self.channel.route(&destination) {
|
||||||
if route.metric <= net_packet.ttl() {
|
if route.metric <= net_packet.ttl() {
|
||||||
self.channel.send_to_route(net_packet.buffer(), &route.route_key())?;
|
self.channel.send_to_route(net_packet.buffer(), &route.route_key())?;
|
||||||
}
|
}
|
||||||
} else if (ttl > 2 || destination == current_device.virtual_gateway())
|
} else if (ttl > 1 || destination == current_device.virtual_gateway())
|
||||||
&& source != current_device.virtual_gateway() {
|
&& source != current_device.virtual_gateway() {
|
||||||
//网关默认要转发一次,生存时间不够的发到网关也会被丢弃
|
//网关默认要转发一次,生存时间不够的发到网关也会被丢弃
|
||||||
self.channel.send_to_addr(net_packet.buffer(), current_device.connect_server)?;
|
self.channel.send_to_addr(net_packet.buffer(), current_device.connect_server)?;
|
||||||
@@ -137,7 +156,7 @@ impl RecvHandler {
|
|||||||
match net_packet.protocol() {
|
match net_packet.protocol() {
|
||||||
Protocol::Ipv4Turn => {
|
Protocol::Ipv4Turn => {
|
||||||
let mut ipv4 = IpV4Packet::new(net_packet.payload_mut())?;
|
let mut ipv4 = IpV4Packet::new(net_packet.payload_mut())?;
|
||||||
if ipv4.protocol() == ipv4::protocol::Protocol::Icmp {
|
if ipv4.destination_ip() == destination && ipv4.protocol() == ipv4::protocol::Protocol::Icmp {
|
||||||
let mut icmp_packet = icmp::IcmpPacket::new(ipv4.payload_mut())?;
|
let mut icmp_packet = icmp::IcmpPacket::new(ipv4.payload_mut())?;
|
||||||
if icmp_packet.kind() == Kind::EchoRequest {
|
if icmp_packet.kind() == Kind::EchoRequest {
|
||||||
//开启ping
|
//开启ping
|
||||||
@@ -152,7 +171,69 @@ impl RecvHandler {
|
|||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.tun_writer.write(net_packet.payload())?;
|
if ipv4.destination_ip() != destination {
|
||||||
|
if let Some(gate_way) = self.out_external_route.route(&ipv4.destination_ip()) {
|
||||||
|
match ipv4.protocol() {
|
||||||
|
ipv4::protocol::Protocol::Tcp => {
|
||||||
|
let dest_ip = ipv4.destination_ip();
|
||||||
|
//转发到代理目标地址
|
||||||
|
let mut tcp_packet = packet::tcp::tcp::TcpPacket::new(source, destination, ipv4.payload_mut())?;
|
||||||
|
let source_port = tcp_packet.source_port();
|
||||||
|
let dest_port = tcp_packet.destination_port();
|
||||||
|
tcp_packet.set_destination_port(self.ip_proxy_map.tcp_proxy_port);
|
||||||
|
tcp_packet.update_checksum();
|
||||||
|
ipv4.set_destination_ip(destination);
|
||||||
|
ipv4.update_checksum();
|
||||||
|
self.ip_proxy_map.tcp_proxy_map.insert(SocketAddrV4::new(source, source_port),
|
||||||
|
(SocketAddrV4::new(gate_way, 0), SocketAddrV4::new(dest_ip, dest_port)));
|
||||||
|
}
|
||||||
|
ipv4::protocol::Protocol::Udp => {
|
||||||
|
let dest_ip = ipv4.destination_ip();
|
||||||
|
//转发到代理目标地址
|
||||||
|
let mut udp_packet = packet::udp::udp::UdpPacket::new(source, destination, ipv4.payload_mut())?;
|
||||||
|
let source_port = udp_packet.source_port();
|
||||||
|
let dest_port = udp_packet.destination_port();
|
||||||
|
udp_packet.set_destination_port(self.ip_proxy_map.udp_proxy_port);
|
||||||
|
udp_packet.update_checksum();
|
||||||
|
ipv4.set_destination_ip(destination);
|
||||||
|
ipv4.update_checksum();
|
||||||
|
println!("{:?}",ipv4);
|
||||||
|
self.ip_proxy_map.udp_proxy_map.insert(SocketAddrV4::new(source, source_port),
|
||||||
|
(SocketAddrV4::new(gate_way, 0), SocketAddrV4::new(dest_ip, dest_port)));
|
||||||
|
}
|
||||||
|
ipv4::protocol::Protocol::Icmp => {
|
||||||
|
let dest_ip = ipv4.destination_ip();
|
||||||
|
//转发到代理目标地址
|
||||||
|
let icmp_packet = icmp::IcmpPacket::new(ipv4.payload())?;
|
||||||
|
match icmp_packet.header_other() {
|
||||||
|
HeaderOther::Identifier(id, seq) => {
|
||||||
|
self.ip_proxy_map.icmp_proxy_map.insert((dest_ip, id, seq), source);
|
||||||
|
self.ip_proxy_map.send_icmp(ipv4.payload(), &gate_way, &dest_ip)?;
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some(tun_writer) = &self.tun_writer {
|
||||||
|
tun_writer.write(net_packet.payload())?;
|
||||||
|
} else {
|
||||||
|
if let Some(tap_writer) = &self.tap_writer {
|
||||||
|
let mut ethernet_packet = ethernet::packet::EthernetPacket::unchecked(vec![0; 14 + ipv4.buffer.len()]);
|
||||||
|
let source = source.octets();
|
||||||
|
ethernet_packet.set_source(&[source[0], source[1], source[2], source[3], 123, 234]);
|
||||||
|
ethernet_packet.set_destination(&self.current_device_ext.load().mac);
|
||||||
|
ethernet_packet.set_protocol(ethernet::protocol::Protocol::Ipv4);
|
||||||
|
ethernet_packet.payload_mut().copy_from_slice(ipv4.buffer);
|
||||||
|
tap_writer.write(ðernet_packet.buffer)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Protocol::Service => {
|
Protocol::Service => {
|
||||||
self.service(current_device, source, net_packet, route_key)?;
|
self.service(current_device, source, net_packet, route_key)?;
|
||||||
@@ -194,7 +275,13 @@ impl RecvHandler {
|
|||||||
let virtual_ip = Ipv4Addr::from(response.virtual_ip);
|
let virtual_ip = Ipv4Addr::from(response.virtual_ip);
|
||||||
let virtual_gateway = Ipv4Addr::from(response.virtual_gateway);
|
let virtual_gateway = Ipv4Addr::from(response.virtual_gateway);
|
||||||
let virtual_netmask = Ipv4Addr::from(response.virtual_netmask);
|
let virtual_netmask = Ipv4Addr::from(response.virtual_netmask);
|
||||||
self.tun_writer.change_ip(virtual_ip, virtual_netmask, virtual_gateway, old_netmask, old_gateway)?;
|
if let Some(tun_writer) = &self.tun_writer {
|
||||||
|
tun_writer.change_ip(virtual_ip, virtual_netmask, virtual_gateway, old_netmask, old_gateway)?;
|
||||||
|
} else {
|
||||||
|
if let Some(tap_writer) = &self.tap_writer {
|
||||||
|
tap_writer.change_ip(virtual_ip, virtual_netmask, virtual_gateway, old_netmask, old_gateway)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
let new_current_device = CurrentDeviceInfo::new(virtual_ip, virtual_gateway,
|
let new_current_device = CurrentDeviceInfo::new(virtual_ip, virtual_gateway,
|
||||||
virtual_netmask, current_device.connect_server);
|
virtual_netmask, current_device.connect_server);
|
||||||
if let Err(e) = self.current_device.compare_exchange(current_device, new_current_device) {
|
if let Err(e) = self.current_device.compare_exchange(current_device, new_current_device) {
|
||||||
@@ -254,11 +341,20 @@ impl RecvHandler {
|
|||||||
fn control(&self, current_device: CurrentDeviceInfo, source: Ipv4Addr, mut net_packet: NetPacket<&mut [u8]>, route_key: &RouteKey) -> crate::Result<()> {
|
fn control(&self, current_device: CurrentDeviceInfo, source: Ipv4Addr, mut net_packet: NetPacket<&mut [u8]>, route_key: &RouteKey) -> crate::Result<()> {
|
||||||
match ControlPacket::new(net_packet.transport_protocol(), net_packet.payload())? {
|
match ControlPacket::new(net_packet.transport_protocol(), net_packet.payload())? {
|
||||||
ControlPacket::PingPacket(_) => {
|
ControlPacket::PingPacket(_) => {
|
||||||
|
let metric = net_packet.source_ttl() - net_packet.ttl() + 1;
|
||||||
net_packet.set_transport_protocol(control_packet::Protocol::Pong.into());
|
net_packet.set_transport_protocol(control_packet::Protocol::Pong.into());
|
||||||
net_packet.set_source(current_device.virtual_ip());
|
net_packet.set_source(current_device.virtual_ip());
|
||||||
net_packet.set_destination(source);
|
net_packet.set_destination(source);
|
||||||
net_packet.first_set_ttl(MAX_TTL);
|
net_packet.first_set_ttl(MAX_TTL);
|
||||||
self.channel.send_to_route(net_packet.buffer(), route_key)?;
|
self.channel.send_to_route(net_packet.buffer(), route_key)?;
|
||||||
|
if metric == 1 {
|
||||||
|
if let Some(current_route) = self.channel.route(&source) {
|
||||||
|
if current_route.metric > 1 {
|
||||||
|
let route = Route::from(*route_key, 1, -1);
|
||||||
|
self.channel.add_route(source, route);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ControlPacket::PongPacket(pong_packet) => {
|
ControlPacket::PongPacket(pong_packet) => {
|
||||||
let current_time = Local::now().timestamp_millis() as u16;
|
let current_time = Local::now().timestamp_millis() as u16;
|
||||||
@@ -330,18 +426,19 @@ impl RecvHandler {
|
|||||||
let nat_info = self.nat_test.nat_info();
|
let nat_info = self.nat_test.nat_info();
|
||||||
punch_reply.public_ip_list = nat_info.public_ips.iter().map(|i| {
|
punch_reply.public_ip_list = nat_info.public_ips.iter().map(|i| {
|
||||||
match i {
|
match i {
|
||||||
IpAddr::V4(ip) => {
|
IpAddr::V4(ip) => u32::from_be_bytes(ip.octets()),
|
||||||
u32::from_be_bytes(ip.octets())
|
IpAddr::V6(_) => 0
|
||||||
}
|
|
||||||
IpAddr::V6(_) => {
|
|
||||||
panic!()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}).collect();
|
}).collect();
|
||||||
punch_reply.public_port = nat_info.public_port as u32;
|
punch_reply.public_port = nat_info.public_port as u32;
|
||||||
punch_reply.public_port_range = nat_info.public_port_range as u32;
|
punch_reply.public_port_range = nat_info.public_port_range as u32;
|
||||||
punch_reply.nat_type =
|
punch_reply.nat_type =
|
||||||
protobuf::EnumOrUnknown::new(PunchNatType::from(nat_info.nat_type));
|
protobuf::EnumOrUnknown::new(PunchNatType::from(nat_info.nat_type));
|
||||||
|
punch_reply.local_ip = match nat_info.local_ip {
|
||||||
|
IpAddr::V4(ip) => u32::from_be_bytes(ip.octets()),
|
||||||
|
IpAddr::V6(_) => 0
|
||||||
|
};
|
||||||
|
punch_reply.local_port = nat_info.local_port as u32;
|
||||||
let bytes = punch_reply.write_to_bytes()?;
|
let bytes = punch_reply.write_to_bytes()?;
|
||||||
let mut net_packet =
|
let mut net_packet =
|
||||||
NetPacket::new(vec![0u8; 12 + bytes.len()])?;
|
NetPacket::new(vec![0u8; 12 + bytes.len()])?;
|
||||||
|
|||||||
@@ -4,9 +4,9 @@ use std::sync::atomic::{AtomicI64, Ordering};
|
|||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
use chrono::Local;
|
use chrono::Local;
|
||||||
use protobuf::Message;
|
|
||||||
use p2p_channel::channel::Channel;
|
|
||||||
use p2p_channel::channel::sender::Sender;
|
use p2p_channel::channel::sender::Sender;
|
||||||
|
use p2p_channel::channel::Channel;
|
||||||
|
use protobuf::Message;
|
||||||
|
|
||||||
use crate::error::*;
|
use crate::error::*;
|
||||||
use crate::proto::message::{RegistrationRequest, RegistrationResponse};
|
use crate::proto::message::{RegistrationRequest, RegistrationResponse};
|
||||||
@@ -25,45 +25,64 @@ pub fn registration(
|
|||||||
registration_request_packet(token.clone(), device_id.clone(), name.clone(), false)?;
|
registration_request_packet(token.clone(), device_id.clone(), name.clone(), false)?;
|
||||||
let buf = request_packet.buffer();
|
let buf = request_packet.buffer();
|
||||||
let mut recv_buf = [0u8; 10240];
|
let mut recv_buf = [0u8; 10240];
|
||||||
channel.send_to_addr(buf, server_address)?;
|
let mut count = 0;
|
||||||
let (len, route) = channel.recv_from(&mut recv_buf, Some(Duration::from_millis(300)))?;
|
let len = loop {
|
||||||
if server_address != route.addr {
|
match channel.send_to_addr(buf, server_address) {
|
||||||
return Err(Error::Warn(format!("数据来源错误:{:?}", route.addr)));
|
Ok(_) => {
|
||||||
}
|
match channel.recv_from(&mut recv_buf, Some(Duration::from_millis(300))) {
|
||||||
let net_packet = NetPacket::new(&recv_buf[..len])?;
|
Ok((len, route)) => {
|
||||||
return match net_packet.protocol() {
|
if server_address == route.addr {
|
||||||
Protocol::Service => {
|
let net_packet = NetPacket::new(&recv_buf[..len])?;
|
||||||
match service_packet::Protocol::from(net_packet.transport_protocol()) {
|
match net_packet.protocol() {
|
||||||
service_packet::Protocol::RegistrationResponse => {
|
Protocol::Service => {
|
||||||
let response =
|
match service_packet::Protocol::from(net_packet.transport_protocol()) {
|
||||||
RegistrationResponse::parse_from_bytes(net_packet.payload())?;
|
service_packet::Protocol::RegistrationResponse => {
|
||||||
Ok(response)
|
let response = RegistrationResponse::parse_from_bytes(net_packet.payload())?;
|
||||||
}
|
return Ok(response);
|
||||||
_ => {
|
}
|
||||||
Err(Error::Warn(format!("数据错误:{:?}", net_packet)))
|
_ => println!("响应数据错误"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Protocol::Error => {
|
||||||
|
match InErrorPacket::new(net_packet.transport_protocol(), net_packet.payload()) {
|
||||||
|
Ok(e) => match e {
|
||||||
|
InErrorPacket::TokenError => return Err(Error::Stop("token错误".to_string())),
|
||||||
|
InErrorPacket::Disconnect => {
|
||||||
|
println!("断开连接");
|
||||||
|
}
|
||||||
|
InErrorPacket::AddressExhausted => {
|
||||||
|
println!("地址用尽");
|
||||||
|
log::warn!("地址用尽");
|
||||||
|
}
|
||||||
|
InErrorPacket::OtherError(e) => match e.message() {
|
||||||
|
Ok(str) => {
|
||||||
|
println!("其他异常:{:?}", str);
|
||||||
|
log::warn!("其他异常{:?}",str);
|
||||||
|
}
|
||||||
|
Err(e) => println!("其他异常:{:?}", e),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Err(e) => println!("数据解析异常:{:?}", e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => println!("响应数据错误"),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
println!("接收服务器数据失败:{:?}", e);
|
||||||
|
log::warn!("接收服务器数据失败:{:?}",e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
Err(e) => {
|
||||||
Protocol::Error => {
|
println!("发送数据到服务器失败:{:?}", e);
|
||||||
match InErrorPacket::new(
|
log::warn!("发送数据到服务器失败:{:?}",e);
|
||||||
net_packet.transport_protocol(),
|
|
||||||
net_packet.payload(),
|
|
||||||
) {
|
|
||||||
Ok(e) => match e {
|
|
||||||
InErrorPacket::TokenError => Err(Error::Stop("token错误".to_string())),
|
|
||||||
InErrorPacket::Disconnect => Err(Error::Warn("断开连接".to_string())),
|
|
||||||
InErrorPacket::AddressExhausted => Err(Error::Stop("地址用尽".to_string())),
|
|
||||||
InErrorPacket::OtherError(e) => match e.message() {
|
|
||||||
Ok(str) => Err(Error::Warn(str)),
|
|
||||||
Err(e) => Err(Error::Warn(format!("{:?}", e))),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Err(e) => Err(Error::Warn(format!("{:?}", e))),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
count += 1;
|
||||||
Err(Error::Warn(format!("数据错误:{:?}", net_packet)))
|
println!("重试中(retrying)...");
|
||||||
}
|
std::thread::sleep(Duration::from_secs(count % 10 + 1));
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -99,11 +118,13 @@ pub struct Register {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Register {
|
impl Register {
|
||||||
pub fn new(sender: Sender<Ipv4Addr>,
|
pub fn new(
|
||||||
server_address: SocketAddr,
|
sender: Sender<Ipv4Addr>,
|
||||||
token: String,
|
server_address: SocketAddr,
|
||||||
device_id: String,
|
token: String,
|
||||||
name: String, ) -> Self {
|
device_id: String,
|
||||||
|
name: String,
|
||||||
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
sender,
|
sender,
|
||||||
server_address,
|
server_address,
|
||||||
@@ -117,7 +138,8 @@ impl Register {
|
|||||||
let last = self.time.load(Ordering::Relaxed);
|
let last = self.time.load(Ordering::Relaxed);
|
||||||
let new = Local::now().timestamp_millis();
|
let new = Local::now().timestamp_millis();
|
||||||
if new - last < 1000
|
if new - last < 1000
|
||||||
|| self.time
|
|| self
|
||||||
|
.time
|
||||||
.compare_exchange(last, new, Ordering::Relaxed, Ordering::Relaxed)
|
.compare_exchange(last, new, Ordering::Relaxed, Ordering::Relaxed)
|
||||||
.is_err()
|
.is_err()
|
||||||
{
|
{
|
||||||
@@ -125,10 +147,13 @@ impl Register {
|
|||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
log::info!("重新连接");
|
log::info!("重新连接");
|
||||||
let request_packet =
|
let request_packet = registration_request_packet(
|
||||||
registration_request_packet(self.token.clone(),
|
self.token.clone(),
|
||||||
self.device_id.clone(),
|
self.device_id.clone(),
|
||||||
self.name.clone(), false).unwrap();
|
self.name.clone(),
|
||||||
|
false,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
let buf = request_packet.buffer();
|
let buf = request_packet.buffer();
|
||||||
self.sender.send_to_addr(buf, self.server_address)?;
|
self.sender.send_to_addr(buf, self.server_address)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
@@ -0,0 +1,163 @@
|
|||||||
|
use std::net::{Ipv4Addr, SocketAddrV4};
|
||||||
|
use std::sync::Arc;
|
||||||
|
use std::{io, thread};
|
||||||
|
use crossbeam::atomic::AtomicCell;
|
||||||
|
use p2p_channel::channel::sender::Sender;
|
||||||
|
use packet::arp::arp::ArpPacket;
|
||||||
|
use packet::ethernet;
|
||||||
|
use packet::ethernet::packet::EthernetPacket;
|
||||||
|
use packet::icmp::icmp::IcmpPacket;
|
||||||
|
use packet::icmp::Kind;
|
||||||
|
use packet::ip::ipv4;
|
||||||
|
use packet::ip::ipv4::packet::IpV4Packet;
|
||||||
|
use crate::external_route::ExternalRoute;
|
||||||
|
use crate::handle::{check_dest, CurrentDeviceInfo};
|
||||||
|
use crate::ip_proxy::IpProxyMap;
|
||||||
|
use crate::protocol::{MAX_TTL, NetPacket, Protocol, Version};
|
||||||
|
use crate::tap_device::{TapReader, TapWriter};
|
||||||
|
|
||||||
|
pub fn start(sender: Sender<Ipv4Addr>,
|
||||||
|
tap_reader: TapReader,
|
||||||
|
tap_writer: TapWriter,
|
||||||
|
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
||||||
|
ip_route: ExternalRoute,
|
||||||
|
ip_proxy_map: IpProxyMap) {
|
||||||
|
thread::Builder::new().name("tap-handler".into()).spawn(move || {
|
||||||
|
if let Err(e) = start_(sender, tap_reader, tap_writer, current_device,ip_route,ip_proxy_map) {
|
||||||
|
log::warn!("{:?}",e);
|
||||||
|
}
|
||||||
|
}).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn start_(sender: Sender<Ipv4Addr>,
|
||||||
|
tap_reader: TapReader,
|
||||||
|
tap_writer: TapWriter,
|
||||||
|
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
||||||
|
ip_route: ExternalRoute,
|
||||||
|
ip_proxy_map: IpProxyMap) -> io::Result<()> {
|
||||||
|
let mut net_packet = NetPacket::new(vec![0u8; 4 + 8 + 1500]).unwrap();
|
||||||
|
net_packet.set_version(Version::V1);
|
||||||
|
net_packet.set_protocol(Protocol::Ipv4Turn);
|
||||||
|
net_packet.set_transport_protocol(ipv4::protocol::Protocol::Ipv4.into());
|
||||||
|
net_packet.set_ttl(MAX_TTL);
|
||||||
|
let mut buf = [0; 2048];
|
||||||
|
loop {
|
||||||
|
let len = tap_reader.read(&mut buf)?;
|
||||||
|
if len == 0 {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let mut ethernet_packet = EthernetPacket::unchecked(&mut buf[..len]);
|
||||||
|
if let Err(e) = handle(&mut net_packet, ¤t_device, &tap_writer, &mut ethernet_packet, &sender,&ip_route,&ip_proxy_map) {
|
||||||
|
log::error!("tap handle{:?}",e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle(net_packet: &mut NetPacket<Vec<u8>>, current_device: &AtomicCell<CurrentDeviceInfo>, tap_writer: &TapWriter, ethernet_packet: &mut EthernetPacket<&mut [u8]>, sender: &Sender<Ipv4Addr>, ip_route: &ExternalRoute, proxy_map: &IpProxyMap) -> crate::Result<()> {
|
||||||
|
let current_device = current_device.load();
|
||||||
|
match ethernet_packet.protocol() {
|
||||||
|
ethernet::protocol::Protocol::Arp => {
|
||||||
|
let mut out_ethernet_packet = EthernetPacket::unchecked(ethernet_packet.buffer.to_vec());
|
||||||
|
let arp_packet = ArpPacket::unchecked(ethernet_packet.payload());
|
||||||
|
let mut out_arp_packet = ArpPacket::unchecked(out_ethernet_packet.payload_mut());
|
||||||
|
let sender_h = arp_packet.sender_hardware_addr();
|
||||||
|
let sender_p = arp_packet.sender_protocol_addr();
|
||||||
|
let target_p = arp_packet.target_protocol_addr();
|
||||||
|
if target_p == &[0, 0, 0, 0] || sender_p == &[0, 0, 0, 0] || target_p == sender_p {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
//回复一个虚假的MAC地址
|
||||||
|
out_arp_packet.set_sender_hardware_addr(&[target_p[0], target_p[1], target_p[2], target_p[3], 123, 234]);
|
||||||
|
out_arp_packet.set_sender_protocol_addr(target_p);
|
||||||
|
out_arp_packet.set_target_hardware_addr(sender_h);
|
||||||
|
out_arp_packet.set_target_protocol_addr(sender_p);
|
||||||
|
out_arp_packet.set_op_code(2);
|
||||||
|
out_ethernet_packet.set_source(&[target_p[0], target_p[1], target_p[2], target_p[3], 123, 234]);
|
||||||
|
out_ethernet_packet.set_destination(sender_h);
|
||||||
|
|
||||||
|
tap_writer.write(&out_ethernet_packet.buffer)?;
|
||||||
|
}
|
||||||
|
ethernet::protocol::Protocol::Ipv4 => {
|
||||||
|
// println!("in ethernet_packet {:?}", ethernet_packet);
|
||||||
|
let mut ipv4_packet = IpV4Packet::unchecked(ethernet_packet.payload_mut());
|
||||||
|
let src_ip = ipv4_packet.source_ip();
|
||||||
|
let mut dest_ip = ipv4_packet.destination_ip();
|
||||||
|
if src_ip != current_device.virtual_ip() {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
if !check_dest(dest_ip, current_device.virtual_netmask, current_device.virtual_network) && !dest_ip.is_broadcast() {
|
||||||
|
if let Some(r_dest_ip) = ip_route.route(&dest_ip) {
|
||||||
|
//路由的目标不能是自己
|
||||||
|
if r_dest_ip == src_ip {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
dest_ip = r_dest_ip;
|
||||||
|
} else {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
match ipv4_packet.protocol() {
|
||||||
|
ipv4::protocol::Protocol::Tcp => {
|
||||||
|
let dest_addr = {
|
||||||
|
let tcp_packet = packet::tcp::tcp::TcpPacket::new(src_ip, dest_ip, ipv4_packet.payload())?;
|
||||||
|
SocketAddrV4::new(dest_ip, tcp_packet.destination_port())
|
||||||
|
};
|
||||||
|
if let Some(entry) = proxy_map.tcp_proxy_map.get(&dest_addr) {
|
||||||
|
let source_addr = entry.value().1;
|
||||||
|
let source_ip = *source_addr.ip();
|
||||||
|
let mut tcp_packet = packet::tcp::tcp::TcpPacket::new(source_ip, dest_ip, ipv4_packet.payload_mut())?;
|
||||||
|
tcp_packet.set_source_port(source_addr.port());
|
||||||
|
tcp_packet.update_checksum();
|
||||||
|
ipv4_packet.set_source_ip(source_ip);
|
||||||
|
ipv4_packet.update_checksum();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ipv4::protocol::Protocol::Udp => {
|
||||||
|
let dest_addr = {
|
||||||
|
let udp_packet = packet::udp::udp::UdpPacket::new(src_ip, dest_ip, ipv4_packet.payload())?;
|
||||||
|
SocketAddrV4::new(dest_ip, udp_packet.destination_port())
|
||||||
|
};
|
||||||
|
if let Some(entry) = proxy_map.udp_proxy_map.get(&dest_addr) {
|
||||||
|
let source_addr = entry.value().1;
|
||||||
|
let source_ip = *source_addr.ip();
|
||||||
|
let mut udp_packet = packet::udp::udp::UdpPacket::new(src_ip, dest_ip, ipv4_packet.payload_mut())?;
|
||||||
|
udp_packet.set_source_port(source_addr.port());
|
||||||
|
udp_packet.update_checksum();
|
||||||
|
ipv4_packet.set_source_ip(source_ip);
|
||||||
|
ipv4_packet.update_checksum();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if src_ip == dest_ip {
|
||||||
|
if ipv4_packet.protocol() == ipv4::protocol::Protocol::Icmp {
|
||||||
|
let mut icmp = IcmpPacket::unchecked(ipv4_packet.payload_mut());
|
||||||
|
if icmp.kind() == Kind::EchoRequest {
|
||||||
|
icmp.set_kind(Kind::EchoReply);
|
||||||
|
icmp.update_checksum();
|
||||||
|
let src = ipv4_packet.source_ip();
|
||||||
|
ipv4_packet.set_source_ip(ipv4_packet.destination_ip());
|
||||||
|
ipv4_packet.set_destination_ip(src);
|
||||||
|
ipv4_packet.update_checksum();
|
||||||
|
tap_writer.write(ethernet_packet.buffer)?;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
net_packet.set_source(src_ip);
|
||||||
|
net_packet.set_destination(dest_ip);
|
||||||
|
let data_len = ipv4_packet.buffer.len();
|
||||||
|
net_packet.set_payload(ipv4_packet.buffer);
|
||||||
|
//优先发到直连到地址
|
||||||
|
if sender.send_to_id(&net_packet.buffer()[..(12 + data_len)], &dest_ip).is_err() {
|
||||||
|
sender.send_to_addr(&net_packet.buffer()[..(12 + data_len)], current_device.connect_server)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
// log::warn!("不支持的二层协议:{:?}",p)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
@@ -1,21 +1,22 @@
|
|||||||
use std::{io, thread};
|
use std::{io, thread};
|
||||||
/// 接收tun数据,并且转发到udp上
|
use std::net::{Ipv4Addr, SocketAddrV4};
|
||||||
use std::net::Ipv4Addr;
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use crossbeam::atomic::AtomicCell;
|
use crossbeam::atomic::AtomicCell;
|
||||||
|
|
||||||
use p2p_channel::channel::sender::Sender;
|
use p2p_channel::channel::sender::Sender;
|
||||||
use packet::icmp::icmp::IcmpPacket;
|
use packet::icmp:: Kind;
|
||||||
use packet::icmp::Kind;
|
use packet::icmp::icmp:: IcmpPacket;
|
||||||
use packet::ip::ipv4;
|
use packet::ip::ipv4;
|
||||||
use packet::ip::ipv4::packet::IpV4Packet;
|
use packet::ip::ipv4::packet::IpV4Packet;
|
||||||
|
|
||||||
use crate::error::*;
|
use crate::error::*;
|
||||||
|
use crate::external_route::ExternalRoute;
|
||||||
use crate::handle::{check_dest, CurrentDeviceInfo};
|
use crate::handle::{check_dest, CurrentDeviceInfo};
|
||||||
|
use crate::ip_proxy::IpProxyMap;
|
||||||
use crate::protocol::{MAX_TTL, NetPacket, Protocol, Version};
|
use crate::protocol::{MAX_TTL, NetPacket, Protocol, Version};
|
||||||
use crate::tun_device::{TunReader, TunWriter};
|
use crate::tun_device::{TunReader, TunWriter};
|
||||||
|
|
||||||
|
|
||||||
fn icmp(tun_writer: &TunWriter, mut ipv4_packet: IpV4Packet<&mut [u8]>) -> Result<()> {
|
fn icmp(tun_writer: &TunWriter, mut ipv4_packet: IpV4Packet<&mut [u8]>) -> Result<()> {
|
||||||
if ipv4_packet.protocol() == ipv4::protocol::Protocol::Icmp {
|
if ipv4_packet.protocol() == ipv4::protocol::Protocol::Icmp {
|
||||||
let mut icmp = IcmpPacket::new(ipv4_packet.payload_mut())?;
|
let mut icmp = IcmpPacket::new(ipv4_packet.payload_mut())?;
|
||||||
@@ -32,10 +33,11 @@ fn icmp(tun_writer: &TunWriter, mut ipv4_packet: IpV4Packet<&mut [u8]>) -> Resul
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 接收tun数据,并且转发到udp上
|
||||||
#[inline]
|
#[inline]
|
||||||
fn handle(sender: &Sender<Ipv4Addr>, data: &mut [u8], tun_writer: &TunWriter, current_device: CurrentDeviceInfo, net_packet: &mut NetPacket<Vec<u8>>) -> Result<()> {
|
fn handle(sender: &Sender<Ipv4Addr>, data: &mut [u8], tun_writer: &TunWriter, current_device: CurrentDeviceInfo, net_packet: &mut NetPacket<[u8; 1512]>, ip_route: &ExternalRoute, proxy_map: &IpProxyMap) -> Result<()> {
|
||||||
let data_len = data.len();
|
let data_len = data.len();
|
||||||
let ipv4_packet = match IpV4Packet::new(data) {
|
let mut ipv4_packet = match IpV4Packet::new(data) {
|
||||||
Ok(ipv4_packet) => ipv4_packet,
|
Ok(ipv4_packet) => ipv4_packet,
|
||||||
Err(packet::error::Error::Unimplemented) => {
|
Err(packet::error::Error::Unimplemented) => {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
@@ -43,18 +45,65 @@ fn handle(sender: &Sender<Ipv4Addr>, data: &mut [u8], tun_writer: &TunWriter, cu
|
|||||||
Err(e) => Err(e)?,
|
Err(e) => Err(e)?,
|
||||||
};
|
};
|
||||||
let src_ip = ipv4_packet.source_ip();
|
let src_ip = ipv4_packet.source_ip();
|
||||||
let dest_ip = ipv4_packet.destination_ip();
|
let mut dest_ip = ipv4_packet.destination_ip();
|
||||||
// if dest_ip == cur_info.broadcast_address {
|
// if dest_ip == cur_info.broadcast_address {
|
||||||
// // 启动服务后会收到对137端口的广播
|
// // 启动服务后会收到对137端口的广播
|
||||||
// // 137端口是在局域网中提供计算机的名字或IP地址查询服务
|
// // 137端口是在局域网中提供计算机的名字或IP地址查询服务
|
||||||
// return Ok(());
|
// return Ok(());
|
||||||
// }
|
// }
|
||||||
if src_ip != current_device.virtual_ip() || !check_dest(dest_ip, current_device.virtual_netmask, current_device.virtual_network) {
|
if src_ip != current_device.virtual_ip() {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
if src_ip == dest_ip {
|
if src_ip == dest_ip {
|
||||||
return icmp(&tun_writer, ipv4_packet);
|
return icmp(&tun_writer, ipv4_packet);
|
||||||
}
|
}
|
||||||
|
if !check_dest(dest_ip, current_device.virtual_netmask, current_device.virtual_network) && !dest_ip.is_broadcast() {
|
||||||
|
// println!("非目标 {:?}",ipv4_packet);
|
||||||
|
if let Some(r_dest_ip) = ip_route.route(&dest_ip) {
|
||||||
|
//路由的目标不能是自己
|
||||||
|
if r_dest_ip == src_ip {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
dest_ip = r_dest_ip;
|
||||||
|
} else {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
match ipv4_packet.protocol() {
|
||||||
|
ipv4::protocol::Protocol::Tcp => {
|
||||||
|
let dest_addr = {
|
||||||
|
let tcp_packet = packet::tcp::tcp::TcpPacket::new(src_ip, dest_ip, ipv4_packet.payload())?;
|
||||||
|
SocketAddrV4::new(dest_ip, tcp_packet.destination_port())
|
||||||
|
};
|
||||||
|
if let Some(entry) = proxy_map.tcp_proxy_map.get(&dest_addr) {
|
||||||
|
let source_addr = entry.value().1;
|
||||||
|
let source_ip = *source_addr.ip();
|
||||||
|
let mut tcp_packet = packet::tcp::tcp::TcpPacket::new(source_ip, dest_ip, ipv4_packet.payload_mut())?;
|
||||||
|
tcp_packet.set_source_port(source_addr.port());
|
||||||
|
tcp_packet.update_checksum();
|
||||||
|
ipv4_packet.set_source_ip(source_ip);
|
||||||
|
ipv4_packet.update_checksum();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ipv4::protocol::Protocol::Udp => {
|
||||||
|
let dest_addr = {
|
||||||
|
let udp_packet = packet::udp::udp::UdpPacket::new(src_ip, dest_ip, ipv4_packet.payload())?;
|
||||||
|
SocketAddrV4::new(dest_ip, udp_packet.destination_port())
|
||||||
|
};
|
||||||
|
if let Some(entry) = proxy_map.udp_proxy_map.get(&dest_addr) {
|
||||||
|
let source_addr = entry.value().1;
|
||||||
|
let source_ip = *source_addr.ip();
|
||||||
|
let mut udp_packet = packet::udp::udp::UdpPacket::new(source_ip, dest_ip, ipv4_packet.payload_mut())?;
|
||||||
|
udp_packet.set_source_port(source_addr.port());
|
||||||
|
udp_packet.update_checksum();
|
||||||
|
ipv4_packet.set_source_ip(source_ip);
|
||||||
|
ipv4_packet.update_checksum();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
net_packet.set_source(src_ip);
|
net_packet.set_source(src_ip);
|
||||||
net_packet.set_destination(dest_ip);
|
net_packet.set_destination(dest_ip);
|
||||||
net_packet.set_payload(ipv4_packet.buffer);
|
net_packet.set_payload(ipv4_packet.buffer);
|
||||||
@@ -68,27 +117,31 @@ fn handle(sender: &Sender<Ipv4Addr>, data: &mut [u8], tun_writer: &TunWriter, cu
|
|||||||
pub fn start(sender: Sender<Ipv4Addr>,
|
pub fn start(sender: Sender<Ipv4Addr>,
|
||||||
tun_reader: TunReader,
|
tun_reader: TunReader,
|
||||||
tun_writer: TunWriter,
|
tun_writer: TunWriter,
|
||||||
current_device: Arc<AtomicCell<CurrentDeviceInfo>>, ) {
|
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
||||||
thread::spawn(move || {
|
ip_route: ExternalRoute,
|
||||||
if let Err(e) = start_(sender, tun_reader, tun_writer, current_device) {
|
ip_proxy_map: IpProxyMap) {
|
||||||
|
thread::Builder::new().name("tun-handler".into()).spawn(move || {
|
||||||
|
if let Err(e) = start_(sender, tun_reader, tun_writer, current_device, ip_route, ip_proxy_map) {
|
||||||
log::warn!("{:?}",e);
|
log::warn!("{:?}",e);
|
||||||
}
|
}
|
||||||
});
|
}).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
fn start_(sender: Sender<Ipv4Addr>,
|
fn start_(sender: Sender<Ipv4Addr>,
|
||||||
tun_reader: TunReader,
|
tun_reader: TunReader,
|
||||||
tun_writer: TunWriter,
|
tun_writer: TunWriter,
|
||||||
current_device: Arc<AtomicCell<CurrentDeviceInfo>>, ) -> io::Result<()> {
|
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
||||||
let mut net_packet = NetPacket::new(vec![0u8; 4 + 8 + 1500])?;
|
ip_route: ExternalRoute,
|
||||||
|
ip_proxy_map: IpProxyMap) -> io::Result<()> {
|
||||||
|
let mut net_packet = NetPacket::new([0u8; 4 + 8 + 1500])?;
|
||||||
net_packet.set_version(Version::V1);
|
net_packet.set_version(Version::V1);
|
||||||
net_packet.set_protocol(Protocol::Ipv4Turn);
|
net_packet.set_protocol(Protocol::Ipv4Turn);
|
||||||
net_packet.set_transport_protocol(ipv4::protocol::Protocol::Ipv4.into());
|
net_packet.set_transport_protocol(ipv4::protocol::Protocol::Ipv4.into());
|
||||||
net_packet.set_ttl(MAX_TTL);
|
net_packet.set_ttl(MAX_TTL);
|
||||||
loop {
|
loop {
|
||||||
let mut data = tun_reader.next()?;
|
let mut data = tun_reader.next()?;
|
||||||
match handle(&sender, data.bytes_mut(), &tun_writer, current_device.load(), &mut net_packet) {
|
match handle(&sender, data.bytes_mut(), &tun_writer, current_device.load(), &mut net_packet, &ip_route, &ip_proxy_map) {
|
||||||
Ok(_) => {}
|
Ok(_) => {}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
log::warn!("{:?}", e)
|
log::warn!("{:?}", e)
|
||||||
@@ -97,20 +150,22 @@ fn start_(sender: Sender<Ipv4Addr>,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(target_os = "linux",target_os = "macos"))]
|
#[cfg(any(target_os = "linux", target_os = "macos"))]
|
||||||
fn start_(sender: Sender<Ipv4Addr>,
|
fn start_(sender: Sender<Ipv4Addr>,
|
||||||
tun_reader: TunReader,
|
tun_reader: TunReader,
|
||||||
tun_writer: TunWriter,
|
tun_writer: TunWriter,
|
||||||
current_device: Arc<AtomicCell<CurrentDeviceInfo>>, ) -> io::Result<()> {
|
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
||||||
let mut net_packet = NetPacket::new(vec![0u8; 4 + 8 + 1500])?;
|
ip_route: ExternalRoute,
|
||||||
|
ip_proxy_map: IpProxyMap) -> io::Result<()> {
|
||||||
|
let mut net_packet = NetPacket::new([0u8; 4 + 8 + 1500])?;
|
||||||
net_packet.set_version(Version::V1);
|
net_packet.set_version(Version::V1);
|
||||||
net_packet.set_protocol(Protocol::Ipv4Turn);
|
net_packet.set_protocol(Protocol::Ipv4Turn);
|
||||||
net_packet.set_transport_protocol(ipv4::protocol::Protocol::Ipv4.into());
|
net_packet.set_transport_protocol(ipv4::protocol::Protocol::Ipv4.into());
|
||||||
net_packet.set_ttl(MAX_TTL);
|
net_packet.set_ttl(MAX_TTL);
|
||||||
let mut buf = [0; 4096];
|
let mut buf = [0; 4096];
|
||||||
loop {
|
loop {
|
||||||
let data = tun_reader.read(&mut buf)?;
|
let len = tun_reader.read(&mut buf)?;
|
||||||
match handle(&sender, data, &tun_writer, current_device.load(), &mut net_packet) {
|
match handle(&sender, &mut buf[..len], &tun_writer, current_device.load(), &mut net_packet, &ip_route, &ip_proxy_map) {
|
||||||
Ok(_) => {}
|
Ok(_) => {}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
log::warn!("{:?}", e)
|
log::warn!("{:?}", e)
|
||||||
|
|||||||
@@ -0,0 +1,131 @@
|
|||||||
|
use std::io;
|
||||||
|
use std::mem::MaybeUninit;
|
||||||
|
use std::net::{IpAddr, Ipv4Addr, SocketAddrV4};
|
||||||
|
use std::sync::Arc;
|
||||||
|
use crossbeam::atomic::AtomicCell;
|
||||||
|
|
||||||
|
use crossbeam_skiplist::SkipMap;
|
||||||
|
use socket2::{Domain, SockAddr, Socket, Type};
|
||||||
|
use p2p_channel::channel::sender::Sender;
|
||||||
|
|
||||||
|
use packet::icmp::icmp;
|
||||||
|
use packet::icmp::icmp::HeaderOther;
|
||||||
|
use packet::ip::ipv4;
|
||||||
|
use crate::handle::CurrentDeviceInfo;
|
||||||
|
use crate::protocol::{MAX_TTL, NetPacket, Protocol, Version};
|
||||||
|
|
||||||
|
pub struct IcmpProxy {
|
||||||
|
icmp_socket: Arc<Socket>,
|
||||||
|
// 对端-> 真实来源
|
||||||
|
icmp_proxy_map: Arc<SkipMap<(Ipv4Addr, u16, u16), Ipv4Addr>>,
|
||||||
|
sender: Sender<Ipv4Addr>,
|
||||||
|
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IcmpProxy {
|
||||||
|
pub fn new(addr: SocketAddrV4, icmp_proxy_map: Arc<SkipMap<(Ipv4Addr, u16, u16), Ipv4Addr>>, sender: Sender<Ipv4Addr>, current_device: Arc<AtomicCell<CurrentDeviceInfo>>) -> io::Result<IcmpProxy> {
|
||||||
|
let icmp_socket = Arc::new(Socket::new(Domain::IPV4, Type::RAW, Some(socket2::Protocol::ICMPV4))?);
|
||||||
|
icmp_socket.bind(&SockAddr::from(addr))?;
|
||||||
|
// // 设置 SIO_RCVALL 参数
|
||||||
|
// #[cfg(windows)]
|
||||||
|
// {
|
||||||
|
// use std::os::windows::io::AsRawSocket;
|
||||||
|
// let raw_fd = icmp_socket.as_raw_socket();
|
||||||
|
// let mut rcvall: winapi::shared::minwindef::DWORD = 1;
|
||||||
|
// let mut bytes_returned: winapi::shared::minwindef::DWORD = 0;
|
||||||
|
// let result = unsafe {
|
||||||
|
// winapi::um::winsock2::WSAIoctl(
|
||||||
|
// raw_fd as _,
|
||||||
|
// winapi::shared::mstcpip::SIO_RCVALL,
|
||||||
|
// &mut rcvall as *mut winapi::shared::minwindef::DWORD as *mut std::ffi::c_void,
|
||||||
|
// std::mem::size_of::<winapi::shared::minwindef::DWORD>() as winapi::shared::minwindef::DWORD,
|
||||||
|
// std::ptr::null_mut(),
|
||||||
|
// 0,
|
||||||
|
// &mut bytes_returned as winapi::shared::minwindef::LPDWORD,
|
||||||
|
// std::ptr::null_mut(),
|
||||||
|
// None,
|
||||||
|
// )
|
||||||
|
// };
|
||||||
|
// if result != 0 {
|
||||||
|
// return Err(io::Error::from_raw_os_error(unsafe { winapi::um::winsock2::WSAGetLastError() }));
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
Ok(IcmpProxy {
|
||||||
|
icmp_socket,
|
||||||
|
icmp_proxy_map,
|
||||||
|
sender,
|
||||||
|
current_device,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
pub fn icmp_socket(&self) ->Arc<Socket>{
|
||||||
|
self.icmp_socket.clone()
|
||||||
|
}
|
||||||
|
pub fn start(self) {
|
||||||
|
let mut buf = [0 as u8; 1500];
|
||||||
|
let data: &mut [MaybeUninit<u8>] =
|
||||||
|
unsafe { std::mem::transmute(&mut buf[..]) };
|
||||||
|
let mut net_packet = NetPacket::new([0u8; 4 + 8 + 1500]).unwrap();
|
||||||
|
net_packet.set_version(Version::V1);
|
||||||
|
net_packet.set_protocol(Protocol::Ipv4Turn);
|
||||||
|
net_packet.set_transport_protocol(ipv4::protocol::Protocol::Ipv4.into());
|
||||||
|
net_packet.set_ttl(MAX_TTL);
|
||||||
|
loop {
|
||||||
|
match self.recv(data) {
|
||||||
|
Ok((len, peer_ip)) => {
|
||||||
|
match peer_ip {
|
||||||
|
IpAddr::V4(peer_ip) => {
|
||||||
|
match ipv4::packet::IpV4Packet::new(&mut buf[..len]) {
|
||||||
|
Ok(mut ipv4_packet) => {
|
||||||
|
match icmp::IcmpPacket::new(ipv4_packet.payload()) {
|
||||||
|
Ok(icmp_packet) => {
|
||||||
|
match icmp_packet.header_other() {
|
||||||
|
HeaderOther::Identifier(id, seq) => {
|
||||||
|
if let Some(entry) = self.icmp_proxy_map.get(&(peer_ip, id, seq)) {
|
||||||
|
//将数据发送到真实的来源
|
||||||
|
let dest_ip = *entry.value();
|
||||||
|
ipv4_packet.set_destination_ip(dest_ip);
|
||||||
|
ipv4_packet.update_checksum();
|
||||||
|
let virtual_ip = self.current_device.load().virtual_ip();
|
||||||
|
net_packet.set_source(virtual_ip);
|
||||||
|
net_packet.set_destination(dest_ip);
|
||||||
|
let data_len = ipv4_packet.buffer.len();
|
||||||
|
net_packet.set_payload(ipv4_packet.buffer);
|
||||||
|
let _ = self.sender.send_to_id(&net_packet.buffer()[..(12 + data_len)], &dest_ip);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(_) => {}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
Err(_) => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
IpAddr::V6(_) => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
log::warn!("icmp代理异常:{:?}",e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn recv(&self, buf: &mut [MaybeUninit<u8>]) -> io::Result<(usize, IpAddr)> {
|
||||||
|
let (size, addr) = self.icmp_socket.recv_from(buf)?;
|
||||||
|
let addr = match addr.as_socket() {
|
||||||
|
None => {
|
||||||
|
IpAddr::V4(Ipv4Addr::UNSPECIFIED)
|
||||||
|
}
|
||||||
|
Some(add) => {
|
||||||
|
add.ip()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Ok((size, addr))
|
||||||
|
}
|
||||||
|
// fn send_to(&self, buf: &[u8], addr: SocketAddrV4) -> io::Result<usize> {
|
||||||
|
// self.icmp_socket.send_to(buf, &SockAddr::from(addr))
|
||||||
|
// }
|
||||||
|
}
|
||||||
@@ -0,0 +1,90 @@
|
|||||||
|
use std::{io, thread};
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::net::{Ipv4Addr, SocketAddrV4};
|
||||||
|
use std::sync::Arc;
|
||||||
|
use crossbeam::atomic::AtomicCell;
|
||||||
|
use crossbeam_skiplist::SkipMap;
|
||||||
|
use socket2::{SockAddr, Socket};
|
||||||
|
use tokio::net::{TcpListener, UdpSocket};
|
||||||
|
use p2p_channel::channel::sender::Sender;
|
||||||
|
use crate::handle::CurrentDeviceInfo;
|
||||||
|
use crate::ip_proxy::icmp_proxy::IcmpProxy;
|
||||||
|
use crate::ip_proxy::tcp_proxy::TcpProxy;
|
||||||
|
use crate::ip_proxy::udp_proxy::UdpProxy;
|
||||||
|
|
||||||
|
pub mod icmp_proxy;
|
||||||
|
pub mod tcp_proxy;
|
||||||
|
pub mod udp_proxy;
|
||||||
|
|
||||||
|
#[derive(Eq, PartialEq, Ord, PartialOrd, Copy, Clone, Debug)]
|
||||||
|
pub enum Protocol {
|
||||||
|
Icmp,
|
||||||
|
Tcp,
|
||||||
|
Udp,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct IpProxyMap {
|
||||||
|
pub(crate) tcp_proxy_port: u16,
|
||||||
|
pub(crate) udp_proxy_port: u16,
|
||||||
|
//真实源地址 -> (绑定地址,目的地址)
|
||||||
|
pub(crate) tcp_proxy_map: Arc<SkipMap<SocketAddrV4, (SocketAddrV4, SocketAddrV4)>>,
|
||||||
|
pub(crate) udp_proxy_map: Arc<SkipMap<SocketAddrV4, (SocketAddrV4, SocketAddrV4)>>,
|
||||||
|
// icmp用Identifier来区分,没有Identifier的一律不转发
|
||||||
|
pub(crate) icmp_proxy_map: Arc<SkipMap<(Ipv4Addr, u16, u16), Ipv4Addr>>,
|
||||||
|
icmp_sockets: HashMap<Ipv4Addr, Arc<Socket>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IpProxyMap {
|
||||||
|
pub fn send_icmp(&self, buf: &[u8], src: &Ipv4Addr, dest: &Ipv4Addr) -> io::Result<usize> {
|
||||||
|
if let Some(socket) = self.icmp_sockets.get(src) {
|
||||||
|
socket.send_to(buf, &SockAddr::from(SocketAddrV4::new(*dest, 0)))
|
||||||
|
} else {
|
||||||
|
Err(io::Error::new(io::ErrorKind::Other, format!("not found src:{},dest:{}", src, dest)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn init_proxy(sender: Sender<Ipv4Addr>, bind_ips: Vec<Ipv4Addr>, current_device: Arc<AtomicCell<CurrentDeviceInfo>>) -> io::Result<IpProxyMap> {
|
||||||
|
let mut icmp_sockets = HashMap::new();
|
||||||
|
let tcp_proxy_map: Arc<SkipMap<SocketAddrV4, (SocketAddrV4, SocketAddrV4)>> = Arc::new(SkipMap::new());
|
||||||
|
let udp_proxy_map: Arc<SkipMap<SocketAddrV4, (SocketAddrV4, SocketAddrV4)>> = Arc::new(SkipMap::new());
|
||||||
|
let icmp_proxy_map: Arc<SkipMap<(Ipv4Addr, u16, u16), Ipv4Addr>> = Arc::new(SkipMap::new());
|
||||||
|
let tcp_listener = TcpListener::bind("0.0.0.0:0").await?;
|
||||||
|
let udp_socket = UdpSocket::bind("0.0.0.0:0").await?;
|
||||||
|
let tcp_proxy_port = tcp_listener.local_addr()?.port();
|
||||||
|
let udp_proxy_port = udp_socket.local_addr()?.port();
|
||||||
|
|
||||||
|
{
|
||||||
|
let tcp_proxy_map = tcp_proxy_map.clone();
|
||||||
|
tokio::spawn(async {
|
||||||
|
let tcp_proxy = TcpProxy::new(tcp_listener, tcp_proxy_map);
|
||||||
|
tcp_proxy.start().await
|
||||||
|
});
|
||||||
|
}
|
||||||
|
{
|
||||||
|
let udp_proxy_map = udp_proxy_map.clone();
|
||||||
|
tokio::spawn(async {
|
||||||
|
let udp_proxy = UdpProxy::new(udp_socket, udp_proxy_map);
|
||||||
|
udp_proxy.start().await
|
||||||
|
});
|
||||||
|
}
|
||||||
|
for ip in bind_ips {
|
||||||
|
let addr = SocketAddrV4::new(ip, 0);
|
||||||
|
let icmp_proxy_map = icmp_proxy_map.clone();
|
||||||
|
let icmp_proxy = IcmpProxy::new(addr, icmp_proxy_map, sender.try_clone()?, current_device.clone())?;
|
||||||
|
icmp_sockets.insert(ip, icmp_proxy.icmp_socket());
|
||||||
|
thread::spawn(move || {
|
||||||
|
icmp_proxy.start();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(IpProxyMap {
|
||||||
|
tcp_proxy_port,
|
||||||
|
udp_proxy_port,
|
||||||
|
tcp_proxy_map,
|
||||||
|
udp_proxy_map,
|
||||||
|
icmp_proxy_map,
|
||||||
|
icmp_sockets,
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
use std::io;
|
||||||
|
use std::net::{SocketAddr, SocketAddrV4};
|
||||||
|
use std::sync::Arc;
|
||||||
|
use crossbeam_skiplist::SkipMap;
|
||||||
|
use tokio::net::{TcpListener, TcpStream};
|
||||||
|
|
||||||
|
pub struct TcpProxy {
|
||||||
|
tcp_listener: TcpListener,
|
||||||
|
// todo 怎么过期
|
||||||
|
map: Arc<SkipMap<SocketAddrV4, (SocketAddrV4, SocketAddrV4)>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TcpProxy {
|
||||||
|
pub fn new(tcp_listener: TcpListener, map: Arc<SkipMap<SocketAddrV4, (SocketAddrV4, SocketAddrV4)>>) -> Self {
|
||||||
|
Self {
|
||||||
|
tcp_listener,
|
||||||
|
map,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub async fn start(self) {
|
||||||
|
let tcp_listener = self.tcp_listener;
|
||||||
|
let map = self.map;
|
||||||
|
loop {
|
||||||
|
match tcp_listener.accept().await {
|
||||||
|
Ok((tcp_stream, sender_addr)) => {
|
||||||
|
match sender_addr {
|
||||||
|
SocketAddr::V4(sender_addr) => {
|
||||||
|
if let Some(entry) = map.get(&sender_addr) {
|
||||||
|
let (src_addr, dest_addr) = *entry.value();
|
||||||
|
let peer_tcp_stream = match TcpStream::connect(dest_addr).await {
|
||||||
|
Ok(peer_tcp_stream) => {peer_tcp_stream}
|
||||||
|
Err(e) => {
|
||||||
|
log::warn!("tcp代理异常:{:?},来源:{},目标:{}",e,src_addr,dest_addr);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
tokio::spawn(async move {
|
||||||
|
match proxy(tcp_stream, peer_tcp_stream).await {
|
||||||
|
Ok(_) => {}
|
||||||
|
Err(e) => {
|
||||||
|
log::warn!("tcp代理异常:{:?},来源:{},目标:{}",e,src_addr,dest_addr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SocketAddr::V6(_) => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
log::warn!("tcp代理监听:{:?}",e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn proxy(mut client: TcpStream, mut server: TcpStream) -> io::Result<()> {
|
||||||
|
let (mut client_reader, mut client_writer) = client.split();
|
||||||
|
let (mut server_reader, mut server_writer) = server.split();
|
||||||
|
|
||||||
|
let client_to_server = tokio::io::copy(&mut client_reader, &mut server_writer);
|
||||||
|
let server_to_client = tokio::io::copy(&mut server_reader, &mut client_writer);
|
||||||
|
|
||||||
|
tokio::try_join!(client_to_server, server_to_client)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
@@ -0,0 +1,96 @@
|
|||||||
|
use std::io;
|
||||||
|
use std::net::{SocketAddr, SocketAddrV4};
|
||||||
|
use std::sync::Arc;
|
||||||
|
use std::time::Duration;
|
||||||
|
use crossbeam_skiplist::SkipMap;
|
||||||
|
use tokio::net::UdpSocket;
|
||||||
|
|
||||||
|
/// 一个udp代理,作用是利用系统协议栈,将udp数据报解析出来再转发到目的地址
|
||||||
|
pub struct UdpProxy {
|
||||||
|
udp_socket: Arc<UdpSocket>,
|
||||||
|
// todo 过期处理
|
||||||
|
map: Arc<SkipMap<SocketAddrV4, (SocketAddrV4, SocketAddrV4)>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UdpProxy {
|
||||||
|
pub fn new(udp_socket: UdpSocket, map: Arc<SkipMap<SocketAddrV4, (SocketAddrV4, SocketAddrV4)>>) -> Self {
|
||||||
|
let udp_socket = Arc::new(udp_socket);
|
||||||
|
Self {
|
||||||
|
udp_socket,
|
||||||
|
map,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub async fn start(self) {
|
||||||
|
let map = self.map;
|
||||||
|
let udp_socket = self.udp_socket;
|
||||||
|
let mut buf = [0u8; 65536];
|
||||||
|
let inner_map: Arc<SkipMap<SocketAddrV4, Arc<UdpSocket>>> = Arc::new(SkipMap::new());
|
||||||
|
|
||||||
|
loop {
|
||||||
|
match udp_socket.recv_from(&mut buf).await {
|
||||||
|
Ok((len, sender_addr)) => {
|
||||||
|
match sender_addr {
|
||||||
|
SocketAddr::V4(sender_addr) => {
|
||||||
|
match start0(&buf[..len], sender_addr, &inner_map, &map, &udp_socket).await {
|
||||||
|
Ok(_) => {}
|
||||||
|
Err(e) => {
|
||||||
|
log::warn!("udp代理异常:{:?},来源:{}",e,sender_addr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SocketAddr::V6(_) => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
log::warn!("udp代理异常:{:?}",e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn start0(buf: &[u8], sender_addr: SocketAddrV4, inner_map: &Arc<SkipMap<SocketAddrV4, Arc<UdpSocket>>>, map: &Arc<SkipMap<SocketAddrV4, (SocketAddrV4, SocketAddrV4)>>, udp_socket: &Arc<UdpSocket>) -> io::Result<()> {
|
||||||
|
if let Some(entry) = inner_map.get(&sender_addr) {
|
||||||
|
entry.value().send(buf).await?;
|
||||||
|
} else if let Some(entry) = map.get(&sender_addr) {
|
||||||
|
let (src_addr, dest_addr) = *entry.value();
|
||||||
|
let peer_udp_socket = UdpSocket::bind("0.0.0.0:0").await?;
|
||||||
|
peer_udp_socket.connect(dest_addr).await?;
|
||||||
|
peer_udp_socket.send(buf).await?;
|
||||||
|
let peer_udp_socket = Arc::new(peer_udp_socket);
|
||||||
|
let inner_map = inner_map.clone();
|
||||||
|
inner_map.insert(sender_addr, peer_udp_socket.clone());
|
||||||
|
let udp_socket = udp_socket.clone();
|
||||||
|
tokio::spawn(async move {
|
||||||
|
let mut buf = [0u8; 65536];
|
||||||
|
loop {
|
||||||
|
match tokio::time::timeout(Duration::from_secs(300), peer_udp_socket.recv(&mut buf)).await {
|
||||||
|
Ok(rs) => {
|
||||||
|
match rs {
|
||||||
|
Ok(len) => {
|
||||||
|
match udp_socket.send_to(&buf[..len], sender_addr).await {
|
||||||
|
Ok(_) => {}
|
||||||
|
Err(e) => {
|
||||||
|
log::warn!("udp代理异常:{:?},来源:{},目标:{}",e,src_addr,dest_addr);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
log::warn!("udp代理异常:{:?},来源:{},目标:{}",e,src_addr,dest_addr);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(_) => {
|
||||||
|
//超时关闭
|
||||||
|
log::warn!("udp代理超时关闭,来源:{},目标:{}",src_addr,dest_addr);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
inner_map.remove(&sender_addr);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
+3
-1
@@ -1,6 +1,5 @@
|
|||||||
use crate::error::Error;
|
use crate::error::Error;
|
||||||
|
|
||||||
|
|
||||||
pub use p2p_channel::channel::{Route, RouteKey};
|
pub use p2p_channel::channel::{Route, RouteKey};
|
||||||
|
|
||||||
pub type Result<T> = std::result::Result<T, Error>;
|
pub type Result<T> = std::result::Result<T, Error>;
|
||||||
@@ -11,4 +10,7 @@ pub mod nat;
|
|||||||
pub mod proto;
|
pub mod proto;
|
||||||
pub mod protocol;
|
pub mod protocol;
|
||||||
pub mod tun_device;
|
pub mod tun_device;
|
||||||
|
pub mod tap_device;
|
||||||
|
pub mod ip_proxy;
|
||||||
|
pub mod external_route;
|
||||||
pub mod core;
|
pub mod core;
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
|
use p2p_channel::punch::NatType;
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use std::net::{IpAddr, Ipv4Addr, SocketAddr, UdpSocket};
|
use std::net::{IpAddr, Ipv4Addr, SocketAddr, UdpSocket};
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use std::{io, thread};
|
use std::{io, thread};
|
||||||
use p2p_channel::punch::NatType;
|
|
||||||
|
|
||||||
|
|
||||||
// #[derive(Debug, Copy, Clone, PartialEq)]
|
// #[derive(Debug, Copy, Clone, PartialEq)]
|
||||||
// pub enum NatType {
|
// pub enum NatType {
|
||||||
|
|||||||
+52
-18
@@ -1,9 +1,9 @@
|
|||||||
|
use crate::proto::message::PunchNatType;
|
||||||
|
use p2p_channel::punch::{NatInfo, NatType};
|
||||||
|
use parking_lot::Mutex;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
|
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use parking_lot::Mutex;
|
|
||||||
use p2p_channel::punch::{NatInfo, NatType};
|
|
||||||
use crate::proto::message::PunchNatType;
|
|
||||||
|
|
||||||
pub mod check;
|
pub mod check;
|
||||||
|
|
||||||
@@ -26,7 +26,7 @@ impl From<NatType> for PunchNatType {
|
|||||||
fn from(value: NatType) -> Self {
|
fn from(value: NatType) -> Self {
|
||||||
match value {
|
match value {
|
||||||
NatType::Symmetric => PunchNatType::Symmetric,
|
NatType::Symmetric => PunchNatType::Symmetric,
|
||||||
NatType::Cone => PunchNatType::Cone
|
NatType::Cone => PunchNatType::Cone,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -35,14 +35,26 @@ impl Into<NatType> for PunchNatType {
|
|||||||
fn into(self) -> NatType {
|
fn into(self) -> NatType {
|
||||||
match self {
|
match self {
|
||||||
PunchNatType::Symmetric => NatType::Symmetric,
|
PunchNatType::Symmetric => NatType::Symmetric,
|
||||||
PunchNatType::Cone => NatType::Cone
|
PunchNatType::Cone => NatType::Cone,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NatTest {
|
impl NatTest {
|
||||||
pub fn new(nat_test_server: Vec<SocketAddr>, public_ip: Ipv4Addr, public_port: u16, local_ip: IpAddr, local_port: u16) -> NatTest {
|
pub fn new(
|
||||||
let info = NatTest::re_test_(&nat_test_server, public_ip, public_port, local_ip, local_port);
|
nat_test_server: Vec<SocketAddr>,
|
||||||
|
public_ip: Ipv4Addr,
|
||||||
|
public_port: u16,
|
||||||
|
local_ip: IpAddr,
|
||||||
|
local_port: u16,
|
||||||
|
) -> NatTest {
|
||||||
|
let info = NatTest::re_test_(
|
||||||
|
&nat_test_server,
|
||||||
|
public_ip,
|
||||||
|
public_port,
|
||||||
|
local_ip,
|
||||||
|
local_port,
|
||||||
|
);
|
||||||
NatTest {
|
NatTest {
|
||||||
nat_test_server: Arc::new(nat_test_server),
|
nat_test_server: Arc::new(nat_test_server),
|
||||||
info: Arc::new(Mutex::new(info)),
|
info: Arc::new(Mutex::new(info)),
|
||||||
@@ -51,12 +63,30 @@ impl NatTest {
|
|||||||
pub fn nat_info(&self) -> NatInfo {
|
pub fn nat_info(&self) -> NatInfo {
|
||||||
self.info.lock().clone()
|
self.info.lock().clone()
|
||||||
}
|
}
|
||||||
pub fn re_test(&self, public_ip: Ipv4Addr, public_port: u16, local_ip: IpAddr, local_port: u16) -> NatInfo {
|
pub fn re_test(
|
||||||
let info = NatTest::re_test_(&self.nat_test_server, public_ip, public_port, local_ip, local_port);
|
&self,
|
||||||
|
public_ip: Ipv4Addr,
|
||||||
|
public_port: u16,
|
||||||
|
local_ip: IpAddr,
|
||||||
|
local_port: u16,
|
||||||
|
) -> NatInfo {
|
||||||
|
let info = NatTest::re_test_(
|
||||||
|
&self.nat_test_server,
|
||||||
|
public_ip,
|
||||||
|
public_port,
|
||||||
|
local_ip,
|
||||||
|
local_port,
|
||||||
|
);
|
||||||
*self.info.lock() = info.clone();
|
*self.info.lock() = info.clone();
|
||||||
info
|
info
|
||||||
}
|
}
|
||||||
fn re_test_(nat_test_server: &Vec<SocketAddr>, public_ip: Ipv4Addr, public_port: u16, local_ip: IpAddr, local_port: u16) -> NatInfo {
|
fn re_test_(
|
||||||
|
nat_test_server: &Vec<SocketAddr>,
|
||||||
|
public_ip: Ipv4Addr,
|
||||||
|
public_port: u16,
|
||||||
|
local_ip: IpAddr,
|
||||||
|
local_port: u16,
|
||||||
|
) -> NatInfo {
|
||||||
return match check::public_ip_list(nat_test_server) {
|
return match check::public_ip_list(nat_test_server) {
|
||||||
Ok((nat_type, ips, port_range)) => {
|
Ok((nat_type, ips, port_range)) => {
|
||||||
let mut public_ips = Vec::new();
|
let mut public_ips = Vec::new();
|
||||||
@@ -66,22 +96,26 @@ impl NatTest {
|
|||||||
public_ips.push(IpAddr::from(ip));
|
public_ips.push(IpAddr::from(ip));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
NatInfo::new(public_ips,
|
NatInfo::new(
|
||||||
public_port,
|
public_ips,
|
||||||
port_range,
|
public_port,
|
||||||
local_ip, local_port,
|
port_range,
|
||||||
nat_type, )
|
local_ip,
|
||||||
|
local_port,
|
||||||
|
nat_type,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
log::warn!("{:?}",e);
|
log::warn!("{:?}", e);
|
||||||
NatInfo::new(
|
NatInfo::new(
|
||||||
vec![IpAddr::from(public_ip)],
|
vec![IpAddr::from(public_ip)],
|
||||||
public_port,
|
public_port,
|
||||||
0,
|
0,
|
||||||
local_ip, local_port,
|
local_ip,
|
||||||
|
local_port,
|
||||||
NatType::Cone,
|
NatType::Cone,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
use std::{fmt, io};
|
use std::{fmt, io};
|
||||||
|
|
||||||
|
|
||||||
#[derive(Eq, PartialEq, Copy, Clone, Debug)]
|
#[derive(Eq, PartialEq, Copy, Clone, Debug)]
|
||||||
pub enum Protocol {
|
pub enum Protocol {
|
||||||
/// ping请求
|
/// ping请求
|
||||||
@@ -107,4 +106,4 @@ impl<B: AsRef<[u8]>> fmt::Debug for PingPacket<B> {
|
|||||||
.field("epoch", &self.epoch())
|
.field("epoch", &self.epoch())
|
||||||
.finish()
|
.finish()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+17
-14
@@ -1,19 +1,19 @@
|
|||||||
use std::{fmt, io};
|
|
||||||
use std::net::Ipv4Addr;
|
use std::net::Ipv4Addr;
|
||||||
|
use std::{fmt, io};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
0 15 31
|
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
|
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
|
||||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
| 版本(8) | 协议(8) | 上层协议(8) | 初始ttl(4) | 生存时间(4) |
|
| 版本(8) | 协议(8) | 上层协议(8) | 初始ttl(4) | 生存时间(4) |
|
||||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
| 源ip地址(32) |
|
| 源ip地址(32) |
|
||||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
| 目的ip地址(32) |
|
| 目的ip地址(32) |
|
||||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
| 数据体 |
|
| 数据体 |
|
||||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
*/
|
*/
|
||||||
|
|
||||||
pub mod control_packet;
|
pub mod control_packet;
|
||||||
pub mod error_packet;
|
pub mod error_packet;
|
||||||
@@ -98,7 +98,10 @@ impl<B: AsRef<[u8]>> NetPacket<B> {
|
|||||||
let len = buffer.as_ref().len();
|
let len = buffer.as_ref().len();
|
||||||
// 不能大于udp最大载荷长度
|
// 不能大于udp最大载荷长度
|
||||||
if len < 12 || len > 65535 - 20 - 8 {
|
if len < 12 || len > 65535 - 20 - 8 {
|
||||||
return Err(io::Error::new(io::ErrorKind::InvalidData, "length overflow"));
|
return Err(io::Error::new(
|
||||||
|
io::ErrorKind::InvalidData,
|
||||||
|
"length overflow",
|
||||||
|
));
|
||||||
}
|
}
|
||||||
Ok(NetPacket { buffer })
|
Ok(NetPacket { buffer })
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
|
|
||||||
|
|
||||||
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
|
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
|
||||||
pub enum Protocol {
|
pub enum Protocol {
|
||||||
Punch,
|
Punch,
|
||||||
|
|||||||
@@ -0,0 +1,58 @@
|
|||||||
|
use crate::tun_device::{TunReader, TunWriter};
|
||||||
|
|
||||||
|
pub type TapReader = TunReader;
|
||||||
|
pub type TapWriter = TunWriter;
|
||||||
|
|
||||||
|
use std::net::Ipv4Addr;
|
||||||
|
use std::sync::Arc;
|
||||||
|
use tun::Device;
|
||||||
|
use parking_lot::Mutex;
|
||||||
|
use std::io;
|
||||||
|
|
||||||
|
pub fn create_tap(
|
||||||
|
address: Ipv4Addr,
|
||||||
|
netmask: Ipv4Addr,
|
||||||
|
gateway: Ipv4Addr,
|
||||||
|
) -> io::Result<(TunWriter, TunReader, [u8; 6])> {
|
||||||
|
println!("========TAP网卡配置========");
|
||||||
|
let mut config = tun::Configuration::default();
|
||||||
|
|
||||||
|
config
|
||||||
|
.destination(gateway)
|
||||||
|
.address(address)
|
||||||
|
.netmask(netmask)
|
||||||
|
.mtu(1420)
|
||||||
|
.layer(tun::Layer::L2)
|
||||||
|
// .queues(2) 用多个队列有兼容性问题
|
||||||
|
.up();
|
||||||
|
|
||||||
|
let dev = tun::create(&config).unwrap();
|
||||||
|
let name = dev.name();
|
||||||
|
println!("name:{:?}", name);
|
||||||
|
let packet_information = dev.has_packet_information();
|
||||||
|
let queue = dev.queue(0).unwrap();
|
||||||
|
let reader = queue.reader();
|
||||||
|
let writer = queue.writer();
|
||||||
|
let get_mac_cmd = format!("cat /sys/class/net/{}/address", name);
|
||||||
|
let mac_out = std::process::Command::new("sh")
|
||||||
|
.arg("-c")
|
||||||
|
.arg(get_mac_cmd)
|
||||||
|
.output()
|
||||||
|
.expect("sh exec error!");
|
||||||
|
if !mac_out.status.success() {
|
||||||
|
return Err(io::Error::new(io::ErrorKind::Other, format!("获取mac地址错误: {:?}", mac_out)));
|
||||||
|
}
|
||||||
|
let mac_str = String::from_utf8(mac_out.stdout).unwrap();
|
||||||
|
let mut mac = [0; 6];
|
||||||
|
let mut split = mac_str.split(":");
|
||||||
|
for i in 0..6 {
|
||||||
|
mac[i] = u8::from_str_radix(&split.next().unwrap()[..2], 16).unwrap();
|
||||||
|
}
|
||||||
|
println!("mac:{:?}", mac);
|
||||||
|
println!("========TAP网卡配置========");
|
||||||
|
Ok((
|
||||||
|
TunWriter(writer, packet_information, Arc::new(Mutex::new(dev))),
|
||||||
|
TunReader(reader, packet_information),
|
||||||
|
mac
|
||||||
|
))
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
use crate::tun_device::{TunReader, TunWriter};
|
||||||
|
|
||||||
|
pub type TapReader = TunReader;
|
||||||
|
pub type TapWriter = TunWriter;
|
||||||
|
use std::net::Ipv4Addr;
|
||||||
|
|
||||||
|
pub fn create_tap(
|
||||||
|
address: Ipv4Addr,
|
||||||
|
netmask: Ipv4Addr,
|
||||||
|
gateway: Ipv4Addr,
|
||||||
|
) -> crate::error::Result<(TapWriter, TapReader, [u8; 6])> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
#[cfg(target_os = "windows")]
|
||||||
|
mod windows;
|
||||||
|
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||||
|
mod linux;
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
mod mac;
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
pub use mac::{TapWriter, TapReader};
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
pub use mac::create_tap;
|
||||||
|
|
||||||
|
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||||
|
pub use linux::{TapWriter, TapReader};
|
||||||
|
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||||
|
pub use linux::create_tap;
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
|
pub use windows::create_tap;
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
|
pub use windows::delete_tap;
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
|
pub use windows::{TapReader, TapWriter};
|
||||||
@@ -0,0 +1,101 @@
|
|||||||
|
use std::io;
|
||||||
|
use std::net::Ipv4Addr;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use parking_lot::Mutex;
|
||||||
|
|
||||||
|
use win_tun_tap::{IFace, TapDevice};
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct TapWriter(Arc<TapDevice>, Arc<Mutex<()>>);
|
||||||
|
|
||||||
|
impl TapWriter {
|
||||||
|
pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
|
||||||
|
self.0.write(buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn change_ip(
|
||||||
|
&self,
|
||||||
|
address: Ipv4Addr,
|
||||||
|
netmask: Ipv4Addr,
|
||||||
|
gateway: Ipv4Addr,
|
||||||
|
old_netmask: Ipv4Addr,
|
||||||
|
old_gateway: Ipv4Addr,
|
||||||
|
) -> io::Result<()> {
|
||||||
|
if let Err(e) =
|
||||||
|
self.0.delete_route(dest(old_gateway, old_gateway), old_netmask, old_gateway)
|
||||||
|
{
|
||||||
|
log::warn!("{:?}", e);
|
||||||
|
}
|
||||||
|
self.0.set_ip(address, netmask)?;
|
||||||
|
self.0.add_route(dest(gateway, netmask), netmask, gateway)
|
||||||
|
}
|
||||||
|
pub fn close(&self) -> io::Result<()> {
|
||||||
|
self.0.shutdown()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn dest(ip: Ipv4Addr, mask: Ipv4Addr) -> Ipv4Addr {
|
||||||
|
let ip = ip.octets();
|
||||||
|
let mask = mask.octets();
|
||||||
|
Ipv4Addr::from([
|
||||||
|
ip[0] & mask[0],
|
||||||
|
ip[1] & mask[1],
|
||||||
|
ip[2] & mask[2],
|
||||||
|
ip[3] & mask[3],
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct TapReader(Arc<TapDevice>);
|
||||||
|
|
||||||
|
impl TapReader {
|
||||||
|
pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
|
||||||
|
self.0.read(buf)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const TAP_INTERFACE_NAME: &str = "Switch-Tap-V1";
|
||||||
|
|
||||||
|
pub fn create_tap(
|
||||||
|
address: Ipv4Addr,
|
||||||
|
netmask: Ipv4Addr,
|
||||||
|
gateway: Ipv4Addr,
|
||||||
|
) -> io::Result<(TapWriter, TapReader, [u8; 6])> {
|
||||||
|
println!("========TAP网卡配置========");
|
||||||
|
let tap_device = match TapDevice::open(TAP_INTERFACE_NAME) {
|
||||||
|
Ok(tap_device) => tap_device,
|
||||||
|
Err(e) => {
|
||||||
|
log::warn!("{:?}", e);
|
||||||
|
let tap_device = TapDevice::create()?;
|
||||||
|
tap_device.set_name(TAP_INTERFACE_NAME)?;
|
||||||
|
tap_device
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let mac = tap_device.get_mac()?;
|
||||||
|
println!("name:{:?}", tap_device.get_name()?);
|
||||||
|
println!("version:{:x?}", tap_device.get_version()?);
|
||||||
|
println!("mac:{:x?}", mac);
|
||||||
|
tap_device.set_ip(address, netmask)?;
|
||||||
|
tap_device.set_metric(1)?;
|
||||||
|
tap_device.set_mtu(1420)?;
|
||||||
|
tap_device.set_status(true)?;
|
||||||
|
tap_device.add_route(address, netmask, gateway)?;
|
||||||
|
let tap = Arc::new(tap_device);
|
||||||
|
println!("========TAP网卡配置========");
|
||||||
|
Ok((
|
||||||
|
TapWriter(tap.clone(), Arc::default()),
|
||||||
|
TapReader(tap),
|
||||||
|
mac
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn delete_tap() {
|
||||||
|
let tap_device = match TapDevice::open(TAP_INTERFACE_NAME) {
|
||||||
|
Ok(tap_device) => tap_device,
|
||||||
|
Err(_) => {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let _ = tap_device.delete();
|
||||||
|
}
|
||||||
@@ -1,14 +1,18 @@
|
|||||||
|
use std::io;
|
||||||
use crate::tun_device::{TunReader, TunWriter};
|
use crate::tun_device::{TunReader, TunWriter};
|
||||||
use std::net::Ipv4Addr;
|
use std::net::Ipv4Addr;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use tun::Device;
|
use tun::Device;
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
|
use std::process::Command;
|
||||||
|
|
||||||
pub fn create_tun(
|
pub fn create_tun(
|
||||||
address: Ipv4Addr,
|
address: Ipv4Addr,
|
||||||
netmask: Ipv4Addr,
|
netmask: Ipv4Addr,
|
||||||
gateway: Ipv4Addr,
|
gateway: Ipv4Addr,
|
||||||
|
in_ips: Vec<(Ipv4Addr, Ipv4Addr)>,
|
||||||
) -> crate::error::Result<(TunWriter, TunReader)> {
|
) -> crate::error::Result<(TunWriter, TunReader)> {
|
||||||
|
println!("========TUN网卡配置========");
|
||||||
let mut config = tun::Configuration::default();
|
let mut config = tun::Configuration::default();
|
||||||
|
|
||||||
config
|
config
|
||||||
@@ -18,18 +22,36 @@ pub fn create_tun(
|
|||||||
.mtu(1420)
|
.mtu(1420)
|
||||||
// .queues(2) 用多个队列有兼容性问题
|
// .queues(2) 用多个队列有兼容性问题
|
||||||
.up();
|
.up();
|
||||||
//
|
|
||||||
// config.platform(|config| {
|
|
||||||
// config.packet_information(true);
|
|
||||||
// });
|
|
||||||
|
|
||||||
let dev = tun::create(&config).unwrap();
|
let dev = tun::create(&config).unwrap();
|
||||||
let packet_information = dev.has_packet_information();
|
let packet_information = dev.has_packet_information();
|
||||||
let queue = dev.queue(0).unwrap();
|
let queue = dev.queue(0).unwrap();
|
||||||
let reader = queue.reader();
|
let reader = queue.reader();
|
||||||
let writer = queue.writer();
|
let writer = queue.writer();
|
||||||
|
let name = dev.name();
|
||||||
|
println!("name:{:?}", name);
|
||||||
|
for (address, netmask) in in_ips {
|
||||||
|
add_route(name, address, netmask)?;
|
||||||
|
}
|
||||||
|
println!("========TUN网卡配置========");
|
||||||
Ok((
|
Ok((
|
||||||
TunWriter(writer, packet_information, Arc::new(Mutex::new(dev))),
|
TunWriter(writer, packet_information, Arc::new(Mutex::new(dev))),
|
||||||
TunReader(reader, packet_information),
|
TunReader(reader, packet_information),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn add_route(name: &str, address: Ipv4Addr, netmask: Ipv4Addr) -> io::Result<()> {
|
||||||
|
let route_add_str: String = format!(
|
||||||
|
"ip route add {:?}/{:?} dev {}",
|
||||||
|
address, netmask, name
|
||||||
|
);
|
||||||
|
let route_add_out = Command::new("sh")
|
||||||
|
.arg("-c")
|
||||||
|
.arg(route_add_str)
|
||||||
|
.output()
|
||||||
|
.expect("sh exec error!");
|
||||||
|
if !route_add_out.status.success() {
|
||||||
|
return Err(io::Error::new(io::ErrorKind::Other, format!("添加路由失败: {:?}", route_add_out)));
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|||||||
@@ -11,7 +11,9 @@ pub fn create_tun(
|
|||||||
address: Ipv4Addr,
|
address: Ipv4Addr,
|
||||||
netmask: Ipv4Addr,
|
netmask: Ipv4Addr,
|
||||||
gateway: Ipv4Addr,
|
gateway: Ipv4Addr,
|
||||||
|
in_ips: Vec<(Ipv4Addr, Ipv4Addr)>,
|
||||||
) -> crate::error::Result<(TunWriter, TunReader)> {
|
) -> crate::error::Result<(TunWriter, TunReader)> {
|
||||||
|
println!("========TUN网卡配置========");
|
||||||
let mut config = tun::Configuration::default();
|
let mut config = tun::Configuration::default();
|
||||||
|
|
||||||
config
|
config
|
||||||
@@ -22,35 +24,42 @@ pub fn create_tun(
|
|||||||
.up();
|
.up();
|
||||||
|
|
||||||
let dev = tun::create(&config).unwrap();
|
let dev = tun::create(&config).unwrap();
|
||||||
config_ip(dev.name(), address, netmask, gateway)?;
|
let name = dev.name();
|
||||||
// println!("{:?}", if_config_out);
|
config_ip(name, address, netmask, gateway)?;
|
||||||
// let cmd_str: String = " ifconfig|grep flags=8051|awk -F ':' '{print $1}'|tail -1".to_string();
|
add_route(name, address, netmask)?;
|
||||||
//
|
for (address, netmask) in in_ips {
|
||||||
// let cmd_str_out = Command::new("sh")
|
add_route(name, address, netmask)?;
|
||||||
// .arg("-c")
|
}
|
||||||
// .arg(cmd_str)
|
|
||||||
// .output()
|
|
||||||
// .expect("sh exec error!");
|
|
||||||
// if !cmd_str_out.status.success(){
|
|
||||||
// return Err(Error::Stop(format!("设置路由失败:{:?}", cmd_str_out)));
|
|
||||||
// }
|
|
||||||
// println!("{:?}", cmd_str_out);
|
|
||||||
let packet_information = dev.has_packet_information();
|
let packet_information = dev.has_packet_information();
|
||||||
let queue = dev.queue(0).unwrap();
|
let queue = dev.queue(0).unwrap();
|
||||||
let reader = queue.reader();
|
let reader = queue.reader();
|
||||||
let writer = queue.writer();
|
let writer = queue.writer();
|
||||||
|
println!("name:{:?}", name);
|
||||||
|
println!("========TUN网卡配置========");
|
||||||
Ok((
|
Ok((
|
||||||
TunWriter(writer, packet_information, Arc::new(Mutex::new(dev))),
|
TunWriter(writer, packet_information, Arc::new(Mutex::new(dev))),
|
||||||
TunReader(reader, packet_information),
|
TunReader(reader, packet_information),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn add_route(name: &str, address: Ipv4Addr, netmask: Ipv4Addr) -> io::Result<()> {
|
||||||
|
let route_add_str: String = format!(
|
||||||
|
"sudo route -n add -net {:?}/{:?} -interface {}",
|
||||||
|
address, netmask, name
|
||||||
|
);
|
||||||
|
let route_add_out = Command::new("sh")
|
||||||
|
.arg("-c")
|
||||||
|
.arg(route_add_str)
|
||||||
|
.output()
|
||||||
|
.expect("sh exec error!");
|
||||||
|
if !route_add_out.status.success() {
|
||||||
|
return Err(io::Error::new(io::ErrorKind::Other, format!("添加路由失败: {:?}", route_add_out)));
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn config_ip(name: &str, address: Ipv4Addr, netmask: Ipv4Addr, gateway: Ipv4Addr) -> io::Result<()> {
|
pub(crate) fn config_ip(name: &str, address: Ipv4Addr, netmask: Ipv4Addr, gateway: Ipv4Addr) -> io::Result<()> {
|
||||||
let up_eth_str: String = format!("ifconfig {} {:?} {:?} up ", name, address, gateway);
|
let up_eth_str: String = format!("ifconfig {} {:?} {:?} up ", name, address, gateway);
|
||||||
let route_add_str: String = format!(
|
|
||||||
"sudo route -n add -net {:?} -netmask {:?} {:?}",
|
|
||||||
address, netmask, gateway
|
|
||||||
);
|
|
||||||
let up_eth_out = Command::new("sh")
|
let up_eth_out = Command::new("sh")
|
||||||
.arg("-c")
|
.arg("-c")
|
||||||
.arg(up_eth_str)
|
.arg(up_eth_str)
|
||||||
@@ -59,13 +68,5 @@ pub(crate) fn config_ip(name: &str, address: Ipv4Addr, netmask: Ipv4Addr, gatewa
|
|||||||
if !up_eth_out.status.success() {
|
if !up_eth_out.status.success() {
|
||||||
return Err(io::Error::new(io::ErrorKind::Other, format!("设置网络地址失败: {:?}", up_eth_out)));
|
return Err(io::Error::new(io::ErrorKind::Other, format!("设置网络地址失败: {:?}", up_eth_out)));
|
||||||
}
|
}
|
||||||
let if_config_out = Command::new("sh")
|
|
||||||
.arg("-c")
|
|
||||||
.arg(route_add_str)
|
|
||||||
.output()
|
|
||||||
.expect("sh exec error!");
|
|
||||||
if !if_config_out.status.success() {
|
|
||||||
return Err(io::Error::new(io::ErrorKind::Other, format!("添加路由失败: {:?}", if_config_out)));
|
|
||||||
}
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ pub use unix::{TunReader, TunWriter};
|
|||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
pub use windows::create_tun;
|
pub use windows::create_tun;
|
||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
|
pub use windows::delete_tun;
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
pub use windows::{TunReader, TunWriter};
|
pub use windows::{TunReader, TunWriter};
|
||||||
|
|
||||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||||
|
|||||||
@@ -15,21 +15,8 @@ use parking_lot::Mutex;
|
|||||||
pub struct TunReader(pub(crate) Reader, pub(crate) bool);
|
pub struct TunReader(pub(crate) Reader, pub(crate) bool);
|
||||||
|
|
||||||
impl TunReader {
|
impl TunReader {
|
||||||
pub fn read<'a>(&'a self, buf: &'a mut [u8]) -> io::Result<&mut [u8]> {
|
pub fn read(&self, buf: & mut [u8]) -> io::Result<usize> {
|
||||||
let len = self.0.read(buf)?;
|
self.0.read(buf)
|
||||||
if self.1 {
|
|
||||||
Ok(&mut buf[4..len])
|
|
||||||
} else {
|
|
||||||
Ok(&mut buf[..len])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub fn close(&self) {
|
|
||||||
unsafe {
|
|
||||||
let raw = self.0.as_raw_fd();
|
|
||||||
if raw >= 0 {
|
|
||||||
libc::close(raw);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -52,6 +39,15 @@ impl TunWriter {
|
|||||||
self.0.write_all(packet)
|
self.0.write_all(packet)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
pub fn close(&self) -> io::Result<()>{
|
||||||
|
unsafe {
|
||||||
|
let raw = self.0.as_raw_fd();
|
||||||
|
if raw >= 0 {
|
||||||
|
libc::close(raw);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
pub fn change_ip(&self, address: Ipv4Addr, netmask: Ipv4Addr,
|
pub fn change_ip(&self, address: Ipv4Addr, netmask: Ipv4Addr,
|
||||||
gateway: Ipv4Addr, _old_netmask: Ipv4Addr, _old_gateway: Ipv4Addr) -> io::Result<()> {
|
gateway: Ipv4Addr, _old_netmask: Ipv4Addr, _old_gateway: Ipv4Addr) -> io::Result<()> {
|
||||||
let mut config = tun::Configuration::default();
|
let mut config = tun::Configuration::default();
|
||||||
|
|||||||
+108
-132
@@ -1,52 +1,66 @@
|
|||||||
use std::io;
|
use std::{io, thread};
|
||||||
use std::net::Ipv4Addr;
|
use std::net::Ipv4Addr;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
use libloading::Library;
|
use libloading::Library;
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use wintun::{Adapter, Packet, Session};
|
|
||||||
|
use win_tun_tap::{IFace, TunDevice};
|
||||||
|
use win_tun_tap::packet::TunPacket;
|
||||||
|
|
||||||
|
pub const TUN_INTERFACE_NAME: &str = "Switch-V1";
|
||||||
|
pub const TUN_POOL_NAME: &str = "Switch-V1";
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct TunWriter(Arc<Session>, Arc<Mutex<u32>>);
|
pub struct TunWriter(Arc<TunDevice>, Arc<Mutex<()>>);
|
||||||
|
|
||||||
impl TunWriter {
|
impl TunWriter {
|
||||||
pub fn write(&self, buf: &[u8]) -> io::Result<()> {
|
pub fn write(&self, buf: &[u8]) -> io::Result<()> {
|
||||||
match self.0.allocate_send_packet(buf.len() as u16) {
|
let mut packet = self.0.allocate_send_packet(buf.len() as u16)?;
|
||||||
Ok(mut packet) => {
|
packet.bytes_mut().copy_from_slice(buf);
|
||||||
packet.bytes_mut().copy_from_slice(buf);
|
self.0.send_packet(packet);
|
||||||
self.0.send_packet(packet);
|
return Ok(());
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
Err(_) => {}
|
|
||||||
}
|
|
||||||
return Err(io::Error::new(io::ErrorKind::Other, "send err"));
|
|
||||||
}
|
}
|
||||||
pub fn change_ip(&self, address: Ipv4Addr, netmask: Ipv4Addr,
|
pub fn change_ip(
|
||||||
gateway: Ipv4Addr, old_netmask: Ipv4Addr, old_gateway: Ipv4Addr) -> io::Result<()> {
|
&self,
|
||||||
let index = self.1.lock();
|
address: Ipv4Addr,
|
||||||
if let Err(e) = delete_route(*index, old_netmask, old_gateway) {
|
netmask: Ipv4Addr,
|
||||||
log::warn!("{:?}",e);
|
gateway: Ipv4Addr,
|
||||||
|
old_netmask: Ipv4Addr,
|
||||||
|
old_gateway: Ipv4Addr,
|
||||||
|
) -> io::Result<()> {
|
||||||
|
if let Err(e) =
|
||||||
|
self.0.delete_route(dest(old_gateway, old_gateway), old_netmask, old_gateway)
|
||||||
|
{
|
||||||
|
log::warn!("{:?}", e);
|
||||||
}
|
}
|
||||||
config_ip(*index, address, netmask, gateway)
|
self.0.set_ip(address, netmask)?;
|
||||||
|
self.0.add_route(dest(gateway, netmask), netmask, gateway)
|
||||||
|
}
|
||||||
|
pub fn close(&self) -> io::Result<()> {
|
||||||
|
self.0.shutdown()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn dest(ip: Ipv4Addr, mask: Ipv4Addr) -> Ipv4Addr {
|
||||||
|
let ip = ip.octets();
|
||||||
|
let mask = mask.octets();
|
||||||
|
Ipv4Addr::from([
|
||||||
|
ip[0] & mask[0],
|
||||||
|
ip[1] & mask[1],
|
||||||
|
ip[2] & mask[2],
|
||||||
|
ip[3] & mask[3],
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct TunReader(pub(crate) Arc<Session>);
|
pub struct TunReader(Arc<TunDevice>);
|
||||||
|
|
||||||
|
|
||||||
impl TunReader {
|
impl TunReader {
|
||||||
pub fn next(&self) -> io::Result<Packet> {
|
pub fn next(&self) -> io::Result<TunPacket> {
|
||||||
match self.0.receive_blocking() {
|
self.0.receive_blocking()
|
||||||
Ok(packet) => {
|
|
||||||
return Ok(packet);
|
|
||||||
}
|
|
||||||
Err(_) => {}
|
|
||||||
}
|
|
||||||
return Err(io::Error::new(io::ErrorKind::Other, "read err"));
|
|
||||||
}
|
|
||||||
pub fn close(&self) {
|
|
||||||
self.0.shutdown()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -54,118 +68,80 @@ pub fn create_tun(
|
|||||||
address: Ipv4Addr,
|
address: Ipv4Addr,
|
||||||
netmask: Ipv4Addr,
|
netmask: Ipv4Addr,
|
||||||
gateway: Ipv4Addr,
|
gateway: Ipv4Addr,
|
||||||
|
in_ips:Vec<(Ipv4Addr,Ipv4Addr)>
|
||||||
) -> io::Result<(TunWriter, TunReader)> {
|
) -> io::Result<(TunWriter, TunReader)> {
|
||||||
let win_tun = unsafe {
|
unsafe {
|
||||||
|
println!("========TUN网卡配置========");
|
||||||
match Library::new("wintun.dll") {
|
match Library::new("wintun.dll") {
|
||||||
Ok(library) => match wintun::load_from_library(library) {
|
Ok(lib) => match TunDevice::delete_for_name(lib, TUN_INTERFACE_NAME) {
|
||||||
Ok(win_tun) => win_tun,
|
Ok(_) => {
|
||||||
Err(e) => {
|
thread::sleep(Duration::from_millis(5));
|
||||||
return Err(io::Error::new(io::ErrorKind::Other, format!("{:?}", e)));
|
|
||||||
}
|
}
|
||||||
|
Err(_) => {}
|
||||||
},
|
},
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
log::error!("wintun.dll not found");
|
log::error!("wintun.dll not found");
|
||||||
return Err(io::Error::new(io::ErrorKind::Other, format!("wintun.dll not found {:?}", e)));
|
return Err(io::Error::new(
|
||||||
|
io::ErrorKind::Other,
|
||||||
|
format!("wintun.dll not found {:?}", e),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
let tun_device = match TunDevice::create(
|
||||||
let adapter = match Adapter::open(&win_tun, "Switch-V1") {
|
Library::new("wintun.dll").unwrap(),
|
||||||
Ok(a) => a,
|
TUN_POOL_NAME,
|
||||||
Err(_) => match Adapter::create(&win_tun, "Switch-V1", "Switch-V1", None) {
|
TUN_INTERFACE_NAME,
|
||||||
Ok(adapter) => adapter,
|
) {
|
||||||
|
Ok(tun_device) => tun_device,
|
||||||
Err(e) => return Err(io::Error::new(io::ErrorKind::Other, format!("{:?}", e))),
|
Err(_) => {
|
||||||
},
|
thread::sleep(Duration::from_millis(200));
|
||||||
};
|
match TunDevice::create(
|
||||||
let index = adapter.get_adapter_index().unwrap();
|
Library::new("wintun.dll").unwrap(),
|
||||||
config_ip(index, address, netmask, gateway)?;
|
TUN_POOL_NAME,
|
||||||
let session = Arc::new(adapter.start_session(wintun::MAX_RING_CAPACITY).unwrap());
|
TUN_INTERFACE_NAME,
|
||||||
let reader_session = session.clone();
|
) {
|
||||||
Ok((TunWriter(session.clone(), Arc::new(Mutex::new(index))), TunReader(reader_session)))
|
Ok(tun_device) => tun_device,
|
||||||
|
Err(e) => {
|
||||||
|
return Err(io::Error::new(
|
||||||
|
io::ErrorKind::Other,
|
||||||
|
format!("{:?}", e),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
println!("name:{:?}", tun_device.get_name()?);
|
||||||
|
println!("version:{:?}", tun_device.version()?);
|
||||||
|
tun_device.set_ip(address, netmask)?;
|
||||||
|
tun_device.set_metric(1)?;
|
||||||
|
tun_device.set_mtu(1420)?;
|
||||||
|
for (address, netmask) in in_ips {
|
||||||
|
tun_device.add_route(address, netmask, gateway)?;
|
||||||
|
}
|
||||||
|
tun_device.add_route(address, netmask, gateway)?;
|
||||||
|
let device = Arc::new(tun_device);
|
||||||
|
println!("========TUN网卡配置========");
|
||||||
|
Ok((
|
||||||
|
TunWriter(device.clone(), Arc::default()),
|
||||||
|
TunReader(device),
|
||||||
|
))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn config_ip(index: u32, address: Ipv4Addr, netmask: Ipv4Addr, gateway: Ipv4Addr) -> io::Result<()> {
|
pub fn delete_tun() {
|
||||||
let set_mtu = format!(
|
unsafe {
|
||||||
"netsh interface ipv4 set subinterface {} mtu=1420 store=persistent",
|
match Library::new("wintun.dll") {
|
||||||
index
|
Ok(lib) => match TunDevice::delete_for_name(lib, TUN_INTERFACE_NAME) {
|
||||||
);
|
Ok(_) => {
|
||||||
let set_metric = format!("netsh interface ip set interface {} metric=1", index);
|
}
|
||||||
let set_address = format!(
|
Err(_) => {}
|
||||||
"netsh interface ip set address {} static {:?} {:?} ", // gateway={:?}
|
},
|
||||||
index, address, netmask,
|
Err(_) => {}
|
||||||
);
|
}
|
||||||
// 执行网卡初始化命令
|
|
||||||
let out = std::process::Command::new("cmd")
|
|
||||||
.arg("/C")
|
|
||||||
.arg(set_mtu)
|
|
||||||
.output()
|
|
||||||
.unwrap();
|
|
||||||
if !out.status.success() {
|
|
||||||
return Err(io::Error::new(io::ErrorKind::Other, format!("设置mtu失败: {:?}", out)));
|
|
||||||
}
|
}
|
||||||
let out = std::process::Command::new("cmd")
|
|
||||||
.arg("/C")
|
|
||||||
.arg(set_metric)
|
|
||||||
.output()
|
|
||||||
.unwrap();
|
|
||||||
if !out.status.success() {
|
|
||||||
return Err(io::Error::new(io::ErrorKind::Other, format!("设置接口跃点失败: {:?}", out)));
|
|
||||||
}
|
|
||||||
let out = std::process::Command::new("cmd")
|
|
||||||
.arg("/C")
|
|
||||||
.arg(set_address)
|
|
||||||
.output()
|
|
||||||
.unwrap();
|
|
||||||
if !out.status.success() {
|
|
||||||
return Err(io::Error::new(io::ErrorKind::Other, format!("设置网络地址失败: {:?}", out)));
|
|
||||||
}
|
|
||||||
let dest = {
|
|
||||||
let ip = address.octets();
|
|
||||||
let mask = netmask.octets();
|
|
||||||
Ipv4Addr::from([
|
|
||||||
ip[0] & mask[0],
|
|
||||||
ip[1] & mask[1],
|
|
||||||
ip[2] & mask[2],
|
|
||||||
ip[3] & mask[3],
|
|
||||||
])
|
|
||||||
};
|
|
||||||
let set_route = format!(
|
|
||||||
"route add {:?} mask {:?} {:?} if {}",
|
|
||||||
dest, netmask, gateway, index
|
|
||||||
);
|
|
||||||
// 执行添加路由命令
|
|
||||||
let out = std::process::Command::new("cmd")
|
|
||||||
.arg("/C")
|
|
||||||
.arg(set_route)
|
|
||||||
.output()
|
|
||||||
.unwrap();
|
|
||||||
if !out.status.success() {
|
|
||||||
return Err(io::Error::new(io::ErrorKind::Other, format!("添加路由失败: {:?}", out)));
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn delete_route(index: u32, netmask: Ipv4Addr, gateway: Ipv4Addr) -> io::Result<()> {
|
|
||||||
let mask = netmask.octets();
|
|
||||||
let ip = gateway.octets();
|
|
||||||
let dest = Ipv4Addr::from([
|
|
||||||
ip[0] & mask[0],
|
|
||||||
ip[1] & mask[1],
|
|
||||||
ip[2] & mask[2],
|
|
||||||
ip[3] & mask[3],
|
|
||||||
]);
|
|
||||||
let delete_route = format!(
|
|
||||||
"route delete {:?} mask {:?} {:?} if {}",
|
|
||||||
dest, netmask, gateway, index
|
|
||||||
);
|
|
||||||
// 删除路由
|
|
||||||
let out = std::process::Command::new("cmd")
|
|
||||||
.arg("/C")
|
|
||||||
.arg(delete_route)
|
|
||||||
.output()
|
|
||||||
.unwrap();
|
|
||||||
if !out.status.success() {
|
|
||||||
return Err(io::Error::new(io::ErrorKind::Other, format!("删除路由失败: {:?}", out)));
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -0,0 +1,33 @@
|
|||||||
|
[package]
|
||||||
|
name = "win-tun-tap"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
log = "0.4.17"
|
||||||
|
winreg = "0.7"
|
||||||
|
scopeguard = "1.1"
|
||||||
|
libloading = "0.7"
|
||||||
|
widestring = "0.4"
|
||||||
|
once_cell = "1.8"
|
||||||
|
itertools = "0.10.1"
|
||||||
|
|
||||||
|
[dependencies.winapi]
|
||||||
|
version = "0.3"
|
||||||
|
features = [
|
||||||
|
"errhandlingapi",
|
||||||
|
"combaseapi",
|
||||||
|
"ioapiset",
|
||||||
|
"winioctl",
|
||||||
|
"setupapi",
|
||||||
|
"synchapi",
|
||||||
|
"netioapi",
|
||||||
|
"fileapi",
|
||||||
|
"winbase",
|
||||||
|
"winerror",
|
||||||
|
"ipexport",
|
||||||
|
"iphlpapi",
|
||||||
|
"handleapi"
|
||||||
|
]
|
||||||
@@ -0,0 +1,534 @@
|
|||||||
|
// Many things will be used in the future
|
||||||
|
#![allow(unused)]
|
||||||
|
|
||||||
|
//! Module holding safe wrappers over winapi functions
|
||||||
|
|
||||||
|
use winapi::shared::basetsd::*;
|
||||||
|
use winapi::shared::guiddef::GUID;
|
||||||
|
use winapi::shared::ifdef::*;
|
||||||
|
use winapi::shared::minwindef::*;
|
||||||
|
use winapi::shared::netioapi::*;
|
||||||
|
use winapi::shared::winerror::*;
|
||||||
|
|
||||||
|
use winapi::um::combaseapi::*;
|
||||||
|
use winapi::um::errhandlingapi::*;
|
||||||
|
use winapi::um::fileapi::*;
|
||||||
|
use winapi::um::handleapi::*;
|
||||||
|
use winapi::um::ioapiset::*;
|
||||||
|
use winapi::um::setupapi::*;
|
||||||
|
use winapi::um::synchapi::*;
|
||||||
|
use winapi::um::winioctl::*;
|
||||||
|
use winapi::um::winnt::*;
|
||||||
|
use winapi::um::winreg::*;
|
||||||
|
|
||||||
|
use std::{io, mem, ptr};
|
||||||
|
use std::error::Error;
|
||||||
|
use winapi::um::minwinbase::OVERLAPPED_u;
|
||||||
|
|
||||||
|
#[allow(non_camel_case_types)]
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
/// Custom type to handle variable size SP_DRVINFO_DETAIL_DATA_W
|
||||||
|
pub struct SP_DRVINFO_DETAIL_DATA_W2 {
|
||||||
|
pub cbSize: DWORD,
|
||||||
|
pub InfDate: FILETIME,
|
||||||
|
pub CompatIDsOffset: DWORD,
|
||||||
|
pub CompatIDsLength: DWORD,
|
||||||
|
pub Reserved: ULONG_PTR,
|
||||||
|
pub SectionName: [WCHAR; 256],
|
||||||
|
pub InfFileName: [WCHAR; 260],
|
||||||
|
pub DrvDescription: [WCHAR; 256],
|
||||||
|
pub HardwareID: [WCHAR; 512],
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn string_from_guid(guid: &GUID) -> io::Result<Vec<WCHAR>> {
|
||||||
|
// GUID_STRING_CHARACTERS + 1
|
||||||
|
let mut string = vec![0; 39];
|
||||||
|
|
||||||
|
match unsafe {
|
||||||
|
StringFromGUID2(guid, string.as_mut_ptr(), string.len() as _)
|
||||||
|
} {
|
||||||
|
0 => Err(io::Error::new(io::ErrorKind::Other, "Insufficent buffer")),
|
||||||
|
_ => Ok(string),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn alias_to_luid(alias: &[WCHAR]) -> io::Result<NET_LUID> {
|
||||||
|
let mut luid = unsafe { mem::zeroed() };
|
||||||
|
|
||||||
|
match unsafe { ConvertInterfaceAliasToLuid(alias.as_ptr(), &mut luid) } {
|
||||||
|
0 => Ok(luid),
|
||||||
|
err => Err(io::Error::from_raw_os_error(err as _)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn luid_to_index(luid: &NET_LUID) -> io::Result<NET_IFINDEX> {
|
||||||
|
let mut index = 0;
|
||||||
|
|
||||||
|
match unsafe { ConvertInterfaceLuidToIndex(luid, &mut index) } {
|
||||||
|
0 => Ok(index),
|
||||||
|
err => Err(io::Error::from_raw_os_error(err as _)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn luid_to_guid(luid: &NET_LUID) -> io::Result<GUID> {
|
||||||
|
let mut guid = unsafe { mem::zeroed() };
|
||||||
|
|
||||||
|
match unsafe { ConvertInterfaceLuidToGuid(luid, &mut guid) } {
|
||||||
|
0 => Ok(guid),
|
||||||
|
err => Err(io::Error::from_raw_os_error(err as _)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn luid_to_alias(luid: &NET_LUID) -> io::Result<Vec<WCHAR>> {
|
||||||
|
// IF_MAX_STRING_SIZE + 1
|
||||||
|
let mut alias = vec![0; 257];
|
||||||
|
|
||||||
|
match unsafe {
|
||||||
|
ConvertInterfaceLuidToAlias(luid, alias.as_mut_ptr(), alias.len())
|
||||||
|
} {
|
||||||
|
0 => {
|
||||||
|
Ok(alias)
|
||||||
|
}
|
||||||
|
err => Err(io::Error::from_raw_os_error(err as _)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn close_handle(handle: HANDLE) -> io::Result<()> {
|
||||||
|
match unsafe { CloseHandle(handle) } {
|
||||||
|
0 => Err(io::Error::last_os_error()),
|
||||||
|
_ => Ok(()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn create_file(
|
||||||
|
file_name: &[WCHAR],
|
||||||
|
desired_access: DWORD,
|
||||||
|
share_mode: DWORD,
|
||||||
|
creation_disposition: DWORD,
|
||||||
|
flags_and_attributes: DWORD,
|
||||||
|
) -> io::Result<HANDLE> {
|
||||||
|
match unsafe {
|
||||||
|
CreateFileW(
|
||||||
|
file_name.as_ptr(),
|
||||||
|
desired_access,
|
||||||
|
share_mode,
|
||||||
|
ptr::null_mut(),
|
||||||
|
creation_disposition,
|
||||||
|
flags_and_attributes,
|
||||||
|
ptr::null_mut(),
|
||||||
|
)
|
||||||
|
} {
|
||||||
|
INVALID_HANDLE_VALUE => Err(io::Error::last_os_error()),
|
||||||
|
handle => Ok(handle),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn read_file(handle: HANDLE, buffer: &mut [u8]) -> io::Result<DWORD> {
|
||||||
|
let mut ret = 0;
|
||||||
|
//https://www.cnblogs.com/linyilong3/archive/2012/05/03/2480451.html
|
||||||
|
unsafe {
|
||||||
|
let mut ip_overlapped = winapi::um::minwinbase::OVERLAPPED {
|
||||||
|
Internal: 0,
|
||||||
|
InternalHigh: 0,
|
||||||
|
u: Default::default(),
|
||||||
|
hEvent: ptr::null_mut(),
|
||||||
|
};
|
||||||
|
if 0 == ReadFile(
|
||||||
|
handle,
|
||||||
|
buffer.as_mut_ptr() as _,
|
||||||
|
buffer.len() as _,
|
||||||
|
&mut ret,
|
||||||
|
&mut ip_overlapped, ) {
|
||||||
|
let e = io::Error::last_os_error();
|
||||||
|
if e.raw_os_error().unwrap_or(0) == 997 {
|
||||||
|
if 0 == GetOverlappedResult(handle, &mut ip_overlapped, &mut ret, 1) {
|
||||||
|
return Err(e);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return Err(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(ret)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn write_file(handle: HANDLE, buffer: &[u8]) -> io::Result<DWORD> {
|
||||||
|
let mut ret = 0;
|
||||||
|
let mut ip_overlapped = winapi::um::minwinbase::OVERLAPPED {
|
||||||
|
Internal: 0,
|
||||||
|
InternalHigh: 0,
|
||||||
|
u: Default::default(),
|
||||||
|
hEvent: ptr::null_mut(),
|
||||||
|
};
|
||||||
|
unsafe {
|
||||||
|
if 0 == WriteFile(
|
||||||
|
handle,
|
||||||
|
buffer.as_ptr() as _,
|
||||||
|
buffer.len() as _,
|
||||||
|
&mut ret,
|
||||||
|
&mut ip_overlapped,
|
||||||
|
) {
|
||||||
|
let e = io::Error::last_os_error();
|
||||||
|
if e.raw_os_error().unwrap_or(0) == 997 {
|
||||||
|
if 0 == GetOverlappedResult(handle, &mut ip_overlapped, &mut ret, 1) {
|
||||||
|
return Err(e);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return Err(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(ret)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn create_device_info_list(guid: &GUID) -> io::Result<HDEVINFO> {
|
||||||
|
match unsafe { SetupDiCreateDeviceInfoList(guid, ptr::null_mut()) } {
|
||||||
|
INVALID_HANDLE_VALUE => Err(io::Error::last_os_error()),
|
||||||
|
devinfo => Ok(devinfo),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_class_devs(guid: &GUID, flags: DWORD) -> io::Result<HDEVINFO> {
|
||||||
|
match unsafe {
|
||||||
|
SetupDiGetClassDevsW(guid, ptr::null(), ptr::null_mut(), flags)
|
||||||
|
} {
|
||||||
|
INVALID_HANDLE_VALUE => Err(io::Error::last_os_error()),
|
||||||
|
devinfo => Ok(devinfo),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn destroy_device_info_list(devinfo: HDEVINFO) -> io::Result<()> {
|
||||||
|
match unsafe { SetupDiDestroyDeviceInfoList(devinfo) } {
|
||||||
|
0 => Err(io::Error::last_os_error()),
|
||||||
|
_ => Ok(()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn class_name_from_guid(guid: &GUID) -> io::Result<Vec<WCHAR>> {
|
||||||
|
let mut class_name = vec![0; 32];
|
||||||
|
|
||||||
|
match unsafe {
|
||||||
|
SetupDiClassNameFromGuidW(
|
||||||
|
guid,
|
||||||
|
class_name.as_mut_ptr(),
|
||||||
|
class_name.len() as _,
|
||||||
|
ptr::null_mut(),
|
||||||
|
)
|
||||||
|
} {
|
||||||
|
0 => Err(io::Error::last_os_error()),
|
||||||
|
_ => Ok(class_name),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn create_device_info(
|
||||||
|
devinfo: HDEVINFO,
|
||||||
|
device_name: &[WCHAR],
|
||||||
|
guid: &GUID,
|
||||||
|
device_description: &[WCHAR],
|
||||||
|
creation_flags: DWORD,
|
||||||
|
) -> io::Result<SP_DEVINFO_DATA> {
|
||||||
|
let mut devinfo_data: SP_DEVINFO_DATA = unsafe { mem::zeroed() };
|
||||||
|
devinfo_data.cbSize = mem::size_of_val(&devinfo_data) as _;
|
||||||
|
|
||||||
|
match unsafe {
|
||||||
|
SetupDiCreateDeviceInfoW(
|
||||||
|
devinfo,
|
||||||
|
device_name.as_ptr(),
|
||||||
|
guid,
|
||||||
|
device_description.as_ptr(),
|
||||||
|
ptr::null_mut(),
|
||||||
|
creation_flags,
|
||||||
|
&mut devinfo_data,
|
||||||
|
)
|
||||||
|
} {
|
||||||
|
0 => Err(io::Error::last_os_error()),
|
||||||
|
_ => Ok(devinfo_data),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_selected_device(
|
||||||
|
devinfo: HDEVINFO,
|
||||||
|
devinfo_data: &SP_DEVINFO_DATA,
|
||||||
|
) -> io::Result<()> {
|
||||||
|
match unsafe {
|
||||||
|
SetupDiSetSelectedDevice(devinfo, devinfo_data as *const _ as _)
|
||||||
|
} {
|
||||||
|
0 => Err(io::Error::last_os_error()),
|
||||||
|
_ => Ok(()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_device_registry_property(
|
||||||
|
devinfo: HDEVINFO,
|
||||||
|
devinfo_data: &SP_DEVINFO_DATA,
|
||||||
|
property: DWORD,
|
||||||
|
value: &[WCHAR],
|
||||||
|
) -> io::Result<()> {
|
||||||
|
match unsafe {
|
||||||
|
SetupDiSetDeviceRegistryPropertyW(
|
||||||
|
devinfo,
|
||||||
|
devinfo_data as *const _ as _,
|
||||||
|
property,
|
||||||
|
value.as_ptr() as _,
|
||||||
|
(value.len() * 2) as _,
|
||||||
|
)
|
||||||
|
} {
|
||||||
|
0 => Err(io::Error::last_os_error()),
|
||||||
|
_ => Ok(()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_device_registry_property(
|
||||||
|
devinfo: HDEVINFO,
|
||||||
|
devinfo_data: &SP_DEVINFO_DATA,
|
||||||
|
property: DWORD,
|
||||||
|
) -> io::Result<Vec<WCHAR>> {
|
||||||
|
let mut value = vec![0; 32];
|
||||||
|
|
||||||
|
match unsafe {
|
||||||
|
SetupDiGetDeviceRegistryPropertyW(
|
||||||
|
devinfo,
|
||||||
|
devinfo_data as *const _ as _,
|
||||||
|
property,
|
||||||
|
ptr::null_mut(),
|
||||||
|
value.as_mut_ptr() as _,
|
||||||
|
(value.len() * 2) as _,
|
||||||
|
ptr::null_mut(),
|
||||||
|
)
|
||||||
|
} {
|
||||||
|
0 => Err(io::Error::last_os_error()),
|
||||||
|
_ => Ok(value),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn build_driver_info_list(
|
||||||
|
devinfo: HDEVINFO,
|
||||||
|
devinfo_data: &SP_DEVINFO_DATA,
|
||||||
|
driver_type: DWORD,
|
||||||
|
) -> io::Result<()> {
|
||||||
|
match unsafe {
|
||||||
|
SetupDiBuildDriverInfoList(
|
||||||
|
devinfo,
|
||||||
|
devinfo_data as *const _ as _,
|
||||||
|
driver_type,
|
||||||
|
)
|
||||||
|
} {
|
||||||
|
0 => Err(io::Error::last_os_error()),
|
||||||
|
_ => Ok(()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn destroy_driver_info_list(
|
||||||
|
devinfo: HDEVINFO,
|
||||||
|
devinfo_data: &SP_DEVINFO_DATA,
|
||||||
|
driver_type: DWORD,
|
||||||
|
) -> io::Result<()> {
|
||||||
|
match unsafe {
|
||||||
|
SetupDiDestroyDriverInfoList(
|
||||||
|
devinfo,
|
||||||
|
devinfo_data as *const _ as _,
|
||||||
|
driver_type,
|
||||||
|
)
|
||||||
|
} {
|
||||||
|
0 => Err(io::Error::last_os_error()),
|
||||||
|
_ => Ok(()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_driver_info_detail(
|
||||||
|
devinfo: HDEVINFO,
|
||||||
|
devinfo_data: &SP_DEVINFO_DATA,
|
||||||
|
drvinfo_data: &SP_DRVINFO_DATA_W,
|
||||||
|
) -> io::Result<SP_DRVINFO_DETAIL_DATA_W2> {
|
||||||
|
let mut drvinfo_detail: SP_DRVINFO_DETAIL_DATA_W2 =
|
||||||
|
unsafe { mem::zeroed() };
|
||||||
|
drvinfo_detail.cbSize = mem::size_of::<SP_DRVINFO_DETAIL_DATA_W>() as _;
|
||||||
|
|
||||||
|
match unsafe {
|
||||||
|
SetupDiGetDriverInfoDetailW(
|
||||||
|
devinfo,
|
||||||
|
devinfo_data as *const _ as _,
|
||||||
|
drvinfo_data as *const _ as _,
|
||||||
|
&mut drvinfo_detail as *mut _ as _,
|
||||||
|
mem::size_of_val(&drvinfo_detail) as _,
|
||||||
|
ptr::null_mut(),
|
||||||
|
)
|
||||||
|
} {
|
||||||
|
0 => Err(io::Error::last_os_error()),
|
||||||
|
_ => Ok(drvinfo_detail),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_selected_driver(
|
||||||
|
devinfo: HDEVINFO,
|
||||||
|
devinfo_data: &SP_DEVINFO_DATA,
|
||||||
|
drvinfo_data: &SP_DRVINFO_DATA_W,
|
||||||
|
) -> io::Result<()> {
|
||||||
|
match unsafe {
|
||||||
|
SetupDiSetSelectedDriverW(
|
||||||
|
devinfo,
|
||||||
|
devinfo_data as *const _ as _,
|
||||||
|
drvinfo_data as *const _ as _,
|
||||||
|
)
|
||||||
|
} {
|
||||||
|
0 => Err(io::Error::last_os_error()),
|
||||||
|
_ => Ok(()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_class_install_params(
|
||||||
|
devinfo: HDEVINFO,
|
||||||
|
devinfo_data: &SP_DEVINFO_DATA,
|
||||||
|
params: &impl Copy,
|
||||||
|
) -> io::Result<()> {
|
||||||
|
match unsafe {
|
||||||
|
SetupDiSetClassInstallParamsW(
|
||||||
|
devinfo,
|
||||||
|
devinfo_data as *const _ as _,
|
||||||
|
params as *const _ as _,
|
||||||
|
mem::size_of_val(params) as _,
|
||||||
|
)
|
||||||
|
} {
|
||||||
|
0 => Err(io::Error::last_os_error()),
|
||||||
|
_ => Ok(()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn call_class_installer(
|
||||||
|
devinfo: HDEVINFO,
|
||||||
|
devinfo_data: &SP_DEVINFO_DATA,
|
||||||
|
install_function: DI_FUNCTION,
|
||||||
|
) -> io::Result<()> {
|
||||||
|
match unsafe {
|
||||||
|
SetupDiCallClassInstaller(
|
||||||
|
install_function,
|
||||||
|
devinfo,
|
||||||
|
devinfo_data as *const _ as _,
|
||||||
|
)
|
||||||
|
} {
|
||||||
|
0 => Err(io::Error::last_os_error()),
|
||||||
|
_ => Ok(()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn open_dev_reg_key(
|
||||||
|
devinfo: HDEVINFO,
|
||||||
|
devinfo_data: &SP_DEVINFO_DATA,
|
||||||
|
scope: DWORD,
|
||||||
|
hw_profile: DWORD,
|
||||||
|
key_type: DWORD,
|
||||||
|
sam_desired: REGSAM,
|
||||||
|
) -> io::Result<HKEY> {
|
||||||
|
const INVALID_KEY_VALUE: HKEY = INVALID_HANDLE_VALUE as _;
|
||||||
|
|
||||||
|
match unsafe {
|
||||||
|
SetupDiOpenDevRegKey(
|
||||||
|
devinfo,
|
||||||
|
devinfo_data as *const _ as _,
|
||||||
|
scope,
|
||||||
|
hw_profile,
|
||||||
|
key_type,
|
||||||
|
sam_desired,
|
||||||
|
)
|
||||||
|
} {
|
||||||
|
INVALID_KEY_VALUE => Err(io::Error::last_os_error()),
|
||||||
|
key => Ok(key),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn notify_change_key_value(
|
||||||
|
key: HKEY,
|
||||||
|
watch_subtree: BOOL,
|
||||||
|
notify_filter: DWORD,
|
||||||
|
milliseconds: DWORD,
|
||||||
|
) -> io::Result<()> {
|
||||||
|
let event = match unsafe {
|
||||||
|
CreateEventW(ptr::null_mut(), FALSE, FALSE, ptr::null())
|
||||||
|
} {
|
||||||
|
INVALID_HANDLE_VALUE => Err(io::Error::last_os_error()),
|
||||||
|
event => Ok(event),
|
||||||
|
}?;
|
||||||
|
|
||||||
|
match unsafe {
|
||||||
|
RegNotifyChangeKeyValue(key, watch_subtree, notify_filter, event, TRUE)
|
||||||
|
} {
|
||||||
|
0 => Ok(()),
|
||||||
|
err => Err(io::Error::from_raw_os_error(err)),
|
||||||
|
}?;
|
||||||
|
|
||||||
|
match unsafe { WaitForSingleObject(event, milliseconds) } {
|
||||||
|
0 => Ok(()),
|
||||||
|
0x102 => Err(io::Error::new(
|
||||||
|
io::ErrorKind::TimedOut,
|
||||||
|
"Registry timed out",
|
||||||
|
)),
|
||||||
|
_ => Err(io::Error::last_os_error()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn enum_driver_info(
|
||||||
|
devinfo: HDEVINFO,
|
||||||
|
devinfo_data: &SP_DEVINFO_DATA,
|
||||||
|
driver_type: DWORD,
|
||||||
|
member_index: DWORD,
|
||||||
|
) -> Option<io::Result<SP_DRVINFO_DATA_W>> {
|
||||||
|
let mut drvinfo_data: SP_DRVINFO_DATA_W = unsafe { mem::zeroed() };
|
||||||
|
drvinfo_data.cbSize = mem::size_of_val(&drvinfo_data) as _;
|
||||||
|
|
||||||
|
match unsafe {
|
||||||
|
SetupDiEnumDriverInfoW(
|
||||||
|
devinfo,
|
||||||
|
devinfo_data as *const _ as _,
|
||||||
|
driver_type,
|
||||||
|
member_index,
|
||||||
|
&mut drvinfo_data,
|
||||||
|
)
|
||||||
|
} {
|
||||||
|
0 if unsafe { GetLastError() == ERROR_NO_MORE_ITEMS } => None,
|
||||||
|
0 => Some(Err(io::Error::last_os_error())),
|
||||||
|
_ => Some(Ok(drvinfo_data)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn enum_device_info(
|
||||||
|
devinfo: HDEVINFO,
|
||||||
|
member_index: DWORD,
|
||||||
|
) -> Option<io::Result<SP_DEVINFO_DATA>> {
|
||||||
|
let mut devinfo_data: SP_DEVINFO_DATA = unsafe { mem::zeroed() };
|
||||||
|
devinfo_data.cbSize = mem::size_of_val(&devinfo_data) as _;
|
||||||
|
|
||||||
|
match unsafe {
|
||||||
|
SetupDiEnumDeviceInfo(devinfo, member_index, &mut devinfo_data)
|
||||||
|
} {
|
||||||
|
0 if unsafe { GetLastError() == ERROR_NO_MORE_ITEMS } => None,
|
||||||
|
0 => Some(Err(io::Error::last_os_error())),
|
||||||
|
_ => Some(Ok(devinfo_data)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn device_io_control(
|
||||||
|
handle: HANDLE,
|
||||||
|
io_control_code: DWORD,
|
||||||
|
in_buffer: &impl Copy,
|
||||||
|
out_buffer: &mut impl Copy,
|
||||||
|
) -> io::Result<()> {
|
||||||
|
let mut junk = 0;
|
||||||
|
|
||||||
|
match unsafe {
|
||||||
|
DeviceIoControl(
|
||||||
|
handle,
|
||||||
|
io_control_code,
|
||||||
|
in_buffer as *const _ as _,
|
||||||
|
mem::size_of_val(in_buffer) as _,
|
||||||
|
out_buffer as *mut _ as _,
|
||||||
|
mem::size_of_val(out_buffer) as _,
|
||||||
|
&mut junk,
|
||||||
|
ptr::null_mut(),
|
||||||
|
)
|
||||||
|
} {
|
||||||
|
0 => Err(io::Error::last_os_error()),
|
||||||
|
_ => Ok(()),
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
#![cfg(windows)]
|
||||||
|
|
||||||
|
mod tap;
|
||||||
|
mod tun;
|
||||||
|
mod ffi;
|
||||||
|
mod netsh;
|
||||||
|
mod route;
|
||||||
|
|
||||||
|
use std::{io, net};
|
||||||
|
pub use tap::TapDevice;
|
||||||
|
pub use tun::*;
|
||||||
|
|
||||||
|
/// Encode a string as a utf16 buffer
|
||||||
|
fn encode_utf16(string: &str) -> Vec<u16> {
|
||||||
|
use std::iter::once;
|
||||||
|
string.encode_utf16().chain(once(0)).collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Decode a string from a utf16 buffer
|
||||||
|
fn decode_utf16(string: &[u16]) -> String {
|
||||||
|
let end = string.iter().position(|b| *b == 0).unwrap_or(string.len());
|
||||||
|
String::from_utf16_lossy(&string[..end])
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait IFace {
|
||||||
|
fn shutdown(&self)->io::Result<()>;
|
||||||
|
/// 获取接口索引
|
||||||
|
fn get_index(&self) -> io::Result<u32>;
|
||||||
|
/// 获取名称
|
||||||
|
fn get_name(&self) -> io::Result<String>;
|
||||||
|
/// 设置名称
|
||||||
|
fn set_name(&self, new_name: &str) -> io::Result<()>;
|
||||||
|
/// 设置ip
|
||||||
|
fn set_ip<IP>(&self, address: IP, mask: IP) -> io::Result<()>
|
||||||
|
where IP: Into<net::Ipv4Addr>;
|
||||||
|
/// 设置路由
|
||||||
|
fn add_route<IP>(&self, dest: IP,
|
||||||
|
netmask: IP,
|
||||||
|
gateway: IP, ) -> io::Result<()>
|
||||||
|
where IP: Into<net::Ipv4Addr>;
|
||||||
|
/// 删除路由
|
||||||
|
fn delete_route<IP>(&self, dest: IP,
|
||||||
|
netmask: IP,
|
||||||
|
gateway: IP, ) -> io::Result<()>
|
||||||
|
where IP: Into<net::Ipv4Addr>;
|
||||||
|
/// 设置最大传输单元
|
||||||
|
fn set_mtu(&self, mtu: u16) -> io::Result<()>;
|
||||||
|
/// 设置跃点
|
||||||
|
fn set_metric(&self, metric: u16) -> io::Result<()>;
|
||||||
|
}
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
use std::io;
|
||||||
|
use std::net::Ipv4Addr;
|
||||||
|
|
||||||
|
/// 设置网卡名称
|
||||||
|
pub fn set_interface_name(old_name: &str, new_name: &str) -> io::Result<()> {
|
||||||
|
let cmd = format!(" netsh interface set interface name={:?} newname={:?}", old_name, new_name);
|
||||||
|
let out = std::process::Command::new("cmd")
|
||||||
|
.arg("/C")
|
||||||
|
.arg(&cmd)
|
||||||
|
.output()?;
|
||||||
|
if !out.status.success() {
|
||||||
|
log::warn!("修改网卡名称失败:cmd={:?},out={:?}",cmd,out);
|
||||||
|
return Err(io::Error::new(io::ErrorKind::Other, "修改网卡名称失败"));
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
/// 设置网卡ip
|
||||||
|
pub fn set_interface_ip(index: u32, address: &Ipv4Addr, netmask: &Ipv4Addr) -> io::Result<()> {
|
||||||
|
let set_address = format!(
|
||||||
|
"netsh interface ip set address {} static {:?} {:?} ",
|
||||||
|
index, address, netmask,
|
||||||
|
);
|
||||||
|
let out = std::process::Command::new("cmd")
|
||||||
|
.arg("/C")
|
||||||
|
.arg(&set_address)
|
||||||
|
.output()?;
|
||||||
|
if !out.status.success() {
|
||||||
|
log::error!("cmd={:?},out={:?}",set_address,out);
|
||||||
|
return Err(io::Error::new(io::ErrorKind::Other, format!("设置网络地址失败: {:?}", out)));
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_interface_mtu(index: u32, mtu: u16) -> io::Result<()> {
|
||||||
|
let set_mtu = format!(
|
||||||
|
"netsh interface ipv4 set subinterface {} mtu={} store=persistent",
|
||||||
|
index, mtu
|
||||||
|
);
|
||||||
|
let out = std::process::Command::new("cmd")
|
||||||
|
.arg("/C")
|
||||||
|
.arg(&set_mtu)
|
||||||
|
.output()?;
|
||||||
|
if !out.status.success() {
|
||||||
|
log::error!("cmd={:?},out={:?}",set_mtu,out);
|
||||||
|
return Err(io::Error::new(io::ErrorKind::Other, format!("设置mtu失败: {:?}", out)));
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
pub fn set_interface_metric(index: u32, metric: u16) -> io::Result<()> {
|
||||||
|
let set_metric = format!("netsh interface ip set interface {} metric={}", index,metric);
|
||||||
|
let out = std::process::Command::new("cmd")
|
||||||
|
.arg("/C")
|
||||||
|
.arg(&set_metric)
|
||||||
|
.output()?;
|
||||||
|
if !out.status.success() {
|
||||||
|
log::error!("cmd={:?},out={:?}",set_metric,out);
|
||||||
|
return Err(io::Error::new(io::ErrorKind::Other, format!("设置metric失败: {:?}", out)));
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
use std::io;
|
||||||
|
use std::net::Ipv4Addr;
|
||||||
|
|
||||||
|
/// 添加路由
|
||||||
|
pub fn add_route(index: u32, dest: Ipv4Addr,
|
||||||
|
netmask: Ipv4Addr,
|
||||||
|
gateway: Ipv4Addr, ) -> io::Result<()> {
|
||||||
|
let set_route = format!(
|
||||||
|
"route add {:?} mask {:?} {:?} if {}",
|
||||||
|
dest, netmask, gateway, index
|
||||||
|
);
|
||||||
|
// 执行添加路由命令
|
||||||
|
let out = std::process::Command::new("cmd")
|
||||||
|
.arg("/C")
|
||||||
|
.arg(&set_route)
|
||||||
|
.output()
|
||||||
|
.unwrap();
|
||||||
|
if !out.status.success() {
|
||||||
|
log::error!("cmd={:?},out={:?}",set_route,out);
|
||||||
|
return Err(io::Error::new(io::ErrorKind::Other, format!("添加路由失败: {:?}", out)));
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 删除路由
|
||||||
|
pub fn delete_route(index: u32, dest: Ipv4Addr,netmask: Ipv4Addr, gateway: Ipv4Addr) -> io::Result<()> {
|
||||||
|
if index == 0 {
|
||||||
|
return Err(io::Error::new(io::ErrorKind::Other, format!("网络接口索引错误: {:?}", index)));
|
||||||
|
}
|
||||||
|
let delete_route = format!(
|
||||||
|
"route delete {:?} mask {:?} {:?} if {}",
|
||||||
|
dest, netmask, gateway, index
|
||||||
|
);
|
||||||
|
// 删除路由
|
||||||
|
let out = std::process::Command::new("cmd")
|
||||||
|
.arg("/C")
|
||||||
|
.arg(delete_route)
|
||||||
|
.output()
|
||||||
|
.unwrap();
|
||||||
|
if !out.status.success() {
|
||||||
|
return Err(io::Error::new(io::ErrorKind::Other, format!("删除路由失败: {:?}", out)));
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
@@ -0,0 +1,328 @@
|
|||||||
|
use winapi::shared::ifdef::NET_LUID;
|
||||||
|
use winapi::shared::minwindef::*;
|
||||||
|
|
||||||
|
use winapi::um::fileapi::*;
|
||||||
|
use winapi::um::setupapi::*;
|
||||||
|
use winapi::um::winnt::*;
|
||||||
|
|
||||||
|
use scopeguard::{guard, ScopeGuard};
|
||||||
|
use winreg::RegKey;
|
||||||
|
|
||||||
|
use std::io;
|
||||||
|
use winapi::um::winbase::FILE_FLAG_OVERLAPPED;
|
||||||
|
|
||||||
|
use crate::{decode_utf16, encode_utf16, ffi};
|
||||||
|
|
||||||
|
/// tap-windows hardware ID
|
||||||
|
const HARDWARE_ID: &str = "tap0901";
|
||||||
|
|
||||||
|
winapi::DEFINE_GUID! {
|
||||||
|
GUID_NETWORK_ADAPTER,
|
||||||
|
0x4d36e972, 0xe325, 0x11ce,
|
||||||
|
0xbf, 0xc1, 0x08, 0x00, 0x2b, 0xe1, 0x03, 0x18
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a new interface and returns its NET_LUID
|
||||||
|
pub fn create_interface() -> io::Result<NET_LUID> {
|
||||||
|
let devinfo = ffi::create_device_info_list(&GUID_NETWORK_ADAPTER)?;
|
||||||
|
|
||||||
|
let _guard = guard((), |_| {
|
||||||
|
let _ = ffi::destroy_device_info_list(devinfo);
|
||||||
|
});
|
||||||
|
|
||||||
|
let class_name = ffi::class_name_from_guid(&GUID_NETWORK_ADAPTER)?;
|
||||||
|
|
||||||
|
let devinfo_data = ffi::create_device_info(
|
||||||
|
devinfo,
|
||||||
|
&class_name,
|
||||||
|
&GUID_NETWORK_ADAPTER,
|
||||||
|
&encode_utf16(""),
|
||||||
|
DICD_GENERATE_ID,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
ffi::set_selected_device(devinfo, &devinfo_data)?;
|
||||||
|
ffi::set_device_registry_property(
|
||||||
|
devinfo,
|
||||||
|
&devinfo_data,
|
||||||
|
SPDRP_HARDWAREID,
|
||||||
|
&encode_utf16(HARDWARE_ID),
|
||||||
|
)?;
|
||||||
|
|
||||||
|
ffi::build_driver_info_list(devinfo, &devinfo_data, SPDIT_COMPATDRIVER)?;
|
||||||
|
|
||||||
|
let _guard = guard((), |_| {
|
||||||
|
let _ = ffi::destroy_driver_info_list(
|
||||||
|
devinfo,
|
||||||
|
&devinfo_data,
|
||||||
|
SPDIT_COMPATDRIVER,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
let mut driver_version = 0;
|
||||||
|
let mut member_index = 0;
|
||||||
|
|
||||||
|
while let Some(drvinfo_data) = ffi::enum_driver_info(
|
||||||
|
devinfo,
|
||||||
|
&devinfo_data,
|
||||||
|
SPDIT_COMPATDRIVER,
|
||||||
|
member_index,
|
||||||
|
) {
|
||||||
|
member_index += 1;
|
||||||
|
|
||||||
|
let drvinfo_data = match drvinfo_data {
|
||||||
|
Ok(drvinfo_data) => drvinfo_data,
|
||||||
|
_ => continue,
|
||||||
|
};
|
||||||
|
|
||||||
|
if drvinfo_data.DriverVersion <= driver_version {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let drvinfo_detail = match ffi::get_driver_info_detail(
|
||||||
|
devinfo,
|
||||||
|
&devinfo_data,
|
||||||
|
&drvinfo_data,
|
||||||
|
) {
|
||||||
|
Ok(drvinfo_detail) => drvinfo_detail,
|
||||||
|
_ => continue,
|
||||||
|
};
|
||||||
|
|
||||||
|
let is_compatible = drvinfo_detail
|
||||||
|
.HardwareID
|
||||||
|
.split(|b| *b == 0)
|
||||||
|
.map(|id| decode_utf16(id))
|
||||||
|
.any(|id| id.eq_ignore_ascii_case(HARDWARE_ID));
|
||||||
|
|
||||||
|
if !is_compatible {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
match ffi::set_selected_driver(devinfo, &devinfo_data, &drvinfo_data) {
|
||||||
|
Ok(_) => (),
|
||||||
|
_ => continue,
|
||||||
|
}
|
||||||
|
|
||||||
|
driver_version = drvinfo_data.DriverVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
if driver_version == 0 {
|
||||||
|
return Err(io::Error::new(io::ErrorKind::NotFound, "No driver found"));
|
||||||
|
}
|
||||||
|
|
||||||
|
let uninstaller = guard((), |_| {
|
||||||
|
let _ = ffi::call_class_installer(devinfo, &devinfo_data, DIF_REMOVE);
|
||||||
|
});
|
||||||
|
|
||||||
|
ffi::call_class_installer(devinfo, &devinfo_data, DIF_REGISTERDEVICE)?;
|
||||||
|
|
||||||
|
let _ = ffi::call_class_installer(
|
||||||
|
devinfo,
|
||||||
|
&devinfo_data,
|
||||||
|
DIF_REGISTER_COINSTALLERS,
|
||||||
|
);
|
||||||
|
let _ = ffi::call_class_installer(
|
||||||
|
devinfo,
|
||||||
|
&devinfo_data,
|
||||||
|
DIF_INSTALLINTERFACES,
|
||||||
|
);
|
||||||
|
|
||||||
|
ffi::call_class_installer(devinfo, &devinfo_data, DIF_INSTALLDEVICE)?;
|
||||||
|
|
||||||
|
let key = ffi::open_dev_reg_key(
|
||||||
|
devinfo,
|
||||||
|
&devinfo_data,
|
||||||
|
DICS_FLAG_GLOBAL,
|
||||||
|
0,
|
||||||
|
DIREG_DRV,
|
||||||
|
KEY_QUERY_VALUE | KEY_NOTIFY,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
let key = RegKey::predef(key);
|
||||||
|
|
||||||
|
while let Err(_) = key.get_value::<DWORD, &str>("*IfType") {
|
||||||
|
ffi::notify_change_key_value(
|
||||||
|
key.raw_handle(),
|
||||||
|
TRUE,
|
||||||
|
REG_NOTIFY_CHANGE_NAME,
|
||||||
|
2000,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
while let Err(_) = key.get_value::<DWORD, &str>("NetLuidIndex") {
|
||||||
|
ffi::notify_change_key_value(
|
||||||
|
key.raw_handle(),
|
||||||
|
TRUE,
|
||||||
|
REG_NOTIFY_CHANGE_NAME,
|
||||||
|
2000,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
let if_type: DWORD = key.get_value("*IfType")?;
|
||||||
|
let luid_index: DWORD = key.get_value("NetLuidIndex")?;
|
||||||
|
|
||||||
|
// Defuse the uninstaller
|
||||||
|
ScopeGuard::into_inner(uninstaller);
|
||||||
|
|
||||||
|
let mut luid = NET_LUID { Value: 0 };
|
||||||
|
|
||||||
|
luid.set_IfType(if_type as _);
|
||||||
|
luid.set_NetLuidIndex(luid_index as _);
|
||||||
|
|
||||||
|
Ok(luid)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check if the given interface exists and is a valid tap-windows device
|
||||||
|
pub fn check_interface(luid: &NET_LUID) -> io::Result<()> {
|
||||||
|
let devinfo = ffi::get_class_devs(&GUID_NETWORK_ADAPTER, DIGCF_PRESENT)?;
|
||||||
|
|
||||||
|
let _guard = guard((), |_| {
|
||||||
|
let _ = ffi::destroy_device_info_list(devinfo);
|
||||||
|
});
|
||||||
|
|
||||||
|
let mut member_index = 0;
|
||||||
|
|
||||||
|
while let Some(devinfo_data) = ffi::enum_device_info(devinfo, member_index)
|
||||||
|
{
|
||||||
|
member_index += 1;
|
||||||
|
|
||||||
|
let devinfo_data = match devinfo_data {
|
||||||
|
Ok(devinfo_data) => devinfo_data,
|
||||||
|
Err(_) => continue,
|
||||||
|
};
|
||||||
|
|
||||||
|
let hardware_id = match ffi::get_device_registry_property(
|
||||||
|
devinfo,
|
||||||
|
&devinfo_data,
|
||||||
|
SPDRP_HARDWAREID,
|
||||||
|
) {
|
||||||
|
Ok(hardware_id) => hardware_id,
|
||||||
|
Err(_) => continue,
|
||||||
|
};
|
||||||
|
|
||||||
|
if !decode_utf16(&hardware_id).eq_ignore_ascii_case(HARDWARE_ID) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let key = match ffi::open_dev_reg_key(
|
||||||
|
devinfo,
|
||||||
|
&devinfo_data,
|
||||||
|
DICS_FLAG_GLOBAL,
|
||||||
|
0,
|
||||||
|
DIREG_DRV,
|
||||||
|
KEY_QUERY_VALUE | KEY_NOTIFY,
|
||||||
|
) {
|
||||||
|
Ok(key) => RegKey::predef(key),
|
||||||
|
Err(_) => continue,
|
||||||
|
};
|
||||||
|
|
||||||
|
let if_type: DWORD = match key.get_value("*IfType") {
|
||||||
|
Ok(if_type) => if_type,
|
||||||
|
Err(_) => continue,
|
||||||
|
};
|
||||||
|
|
||||||
|
let luid_index: DWORD = match key.get_value("NetLuidIndex") {
|
||||||
|
Ok(luid_index) => luid_index,
|
||||||
|
Err(_) => continue,
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut luid2 = NET_LUID { Value: 0 };
|
||||||
|
|
||||||
|
luid2.set_IfType(if_type as _);
|
||||||
|
luid2.set_NetLuidIndex(luid_index as _);
|
||||||
|
|
||||||
|
if luid.Value != luid2.Value {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Found it!
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
Err(io::Error::new(io::ErrorKind::NotFound, "TAP Device not found"))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Deletes an existing interface
|
||||||
|
pub fn delete_interface(luid: &NET_LUID) -> io::Result<()> {
|
||||||
|
let devinfo = ffi::get_class_devs(&GUID_NETWORK_ADAPTER, DIGCF_PRESENT)?;
|
||||||
|
|
||||||
|
let _guard = guard((), |_| {
|
||||||
|
let _ = ffi::destroy_device_info_list(devinfo);
|
||||||
|
});
|
||||||
|
|
||||||
|
let mut member_index = 0;
|
||||||
|
|
||||||
|
while let Some(devinfo_data) = ffi::enum_device_info(devinfo, member_index)
|
||||||
|
{
|
||||||
|
member_index += 1;
|
||||||
|
|
||||||
|
let devinfo_data = match devinfo_data {
|
||||||
|
Ok(devinfo_data) => devinfo_data,
|
||||||
|
Err(_) => continue,
|
||||||
|
};
|
||||||
|
|
||||||
|
let hardware_id = match ffi::get_device_registry_property(
|
||||||
|
devinfo,
|
||||||
|
&devinfo_data,
|
||||||
|
SPDRP_HARDWAREID,
|
||||||
|
) {
|
||||||
|
Ok(hardware_id) => hardware_id,
|
||||||
|
Err(_) => continue,
|
||||||
|
};
|
||||||
|
|
||||||
|
if !decode_utf16(&hardware_id).eq_ignore_ascii_case(HARDWARE_ID) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let key = match ffi::open_dev_reg_key(
|
||||||
|
devinfo,
|
||||||
|
&devinfo_data,
|
||||||
|
DICS_FLAG_GLOBAL,
|
||||||
|
0,
|
||||||
|
DIREG_DRV,
|
||||||
|
KEY_QUERY_VALUE | KEY_NOTIFY,
|
||||||
|
) {
|
||||||
|
Ok(key) => RegKey::predef(key),
|
||||||
|
Err(_) => continue,
|
||||||
|
};
|
||||||
|
|
||||||
|
let if_type: DWORD = match key.get_value("*IfType") {
|
||||||
|
Ok(if_type) => if_type,
|
||||||
|
Err(_) => continue,
|
||||||
|
};
|
||||||
|
|
||||||
|
let luid_index: DWORD = match key.get_value("NetLuidIndex") {
|
||||||
|
Ok(luid_index) => luid_index,
|
||||||
|
Err(_) => continue,
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut luid2 = NET_LUID { Value: 0 };
|
||||||
|
|
||||||
|
luid2.set_IfType(if_type as _);
|
||||||
|
luid2.set_NetLuidIndex(luid_index as _);
|
||||||
|
|
||||||
|
if luid.Value != luid2.Value {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Found it!
|
||||||
|
return ffi::call_class_installer(devinfo, &devinfo_data, DIF_REMOVE);
|
||||||
|
}
|
||||||
|
|
||||||
|
Err(io::Error::new(io::ErrorKind::NotFound, "TAP Device not found"))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Open an handle to an interface
|
||||||
|
pub fn open_interface(luid: &NET_LUID) -> io::Result<HANDLE> {
|
||||||
|
let guid = ffi::luid_to_guid(luid)
|
||||||
|
.and_then(|guid| ffi::string_from_guid(&guid))?;
|
||||||
|
|
||||||
|
let path = format!(r"\\.\Global\{}.tap", &decode_utf16(&guid));
|
||||||
|
|
||||||
|
ffi::create_file(
|
||||||
|
&encode_utf16(&path),
|
||||||
|
GENERIC_READ | GENERIC_WRITE,
|
||||||
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||||
|
OPEN_EXISTING,
|
||||||
|
FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED,//FILE_ATTRIBUTE_SYSTEM,
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -0,0 +1,182 @@
|
|||||||
|
use std::{io, time};
|
||||||
|
use std::net::Ipv4Addr;
|
||||||
|
|
||||||
|
use winapi::shared::ifdef::NET_LUID;
|
||||||
|
use winapi::um::winioctl::*;
|
||||||
|
use winapi::um::winnt::HANDLE;
|
||||||
|
|
||||||
|
use crate::{decode_utf16, encode_utf16, ffi, IFace, netsh, route};
|
||||||
|
|
||||||
|
mod iface;
|
||||||
|
|
||||||
|
pub struct TapDevice {
|
||||||
|
index: u32,
|
||||||
|
luid: NET_LUID,
|
||||||
|
handle: HANDLE,
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl Send for TapDevice {}
|
||||||
|
|
||||||
|
unsafe impl Sync for TapDevice {}
|
||||||
|
|
||||||
|
impl TapDevice {
|
||||||
|
/// Retieve the mac of the interface
|
||||||
|
pub fn get_mac(&self) -> io::Result<[u8; 6]> {
|
||||||
|
let mut mac = [0; 6];
|
||||||
|
|
||||||
|
ffi::device_io_control(
|
||||||
|
self.handle,
|
||||||
|
CTL_CODE(FILE_DEVICE_UNKNOWN, 1, METHOD_BUFFERED, FILE_ANY_ACCESS),
|
||||||
|
&(),
|
||||||
|
&mut mac,
|
||||||
|
)
|
||||||
|
.map(|_| mac)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Retrieve the version of the driver
|
||||||
|
pub fn get_version(&self) -> io::Result<[u32; 3]> {
|
||||||
|
let mut version = [0; 3];
|
||||||
|
|
||||||
|
ffi::device_io_control(
|
||||||
|
self.handle,
|
||||||
|
CTL_CODE(FILE_DEVICE_UNKNOWN, 2, METHOD_BUFFERED, FILE_ANY_ACCESS),
|
||||||
|
&(),
|
||||||
|
&mut version,
|
||||||
|
)
|
||||||
|
.map(|_| version)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Retieve the mtu of the interface
|
||||||
|
pub fn get_mtu(&self) -> io::Result<u32> {
|
||||||
|
let mut mtu = 0;
|
||||||
|
|
||||||
|
ffi::device_io_control(
|
||||||
|
self.handle,
|
||||||
|
CTL_CODE(FILE_DEVICE_UNKNOWN, 3, METHOD_BUFFERED, FILE_ANY_ACCESS),
|
||||||
|
&(),
|
||||||
|
&mut mtu,
|
||||||
|
)
|
||||||
|
.map(|_| mtu)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Set the status of the interface, true for connected,
|
||||||
|
/// false for disconnected.
|
||||||
|
pub fn set_status(&self, status: bool) -> io::Result<()> {
|
||||||
|
let status: u32 = if status { 1 } else { 0 };
|
||||||
|
ffi::device_io_control(
|
||||||
|
self.handle,
|
||||||
|
CTL_CODE(FILE_DEVICE_UNKNOWN, 6, METHOD_BUFFERED, FILE_ANY_ACCESS),
|
||||||
|
&status,
|
||||||
|
&mut (),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TapDevice {
|
||||||
|
pub fn create() -> io::Result<Self> {
|
||||||
|
let luid = iface::create_interface()?;
|
||||||
|
// Even after retrieving the luid, we might need to wait
|
||||||
|
let start = time::Instant::now();
|
||||||
|
let handle = loop {
|
||||||
|
// If we surpassed 2 seconds just return
|
||||||
|
let now = time::Instant::now();
|
||||||
|
if now - start > time::Duration::from_secs(3) {
|
||||||
|
return Err(io::Error::new(
|
||||||
|
io::ErrorKind::TimedOut,
|
||||||
|
"Interface timed out",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
match iface::open_interface(&luid) {
|
||||||
|
Err(_) => {
|
||||||
|
std::thread::yield_now();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Ok(handle) => break handle,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
let index = ffi::luid_to_index(&luid).map(|index| index as u32)?;
|
||||||
|
Ok(Self { index, luid, handle })
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn open(name: &str) -> io::Result<Self> {
|
||||||
|
let name = encode_utf16(name);
|
||||||
|
|
||||||
|
let luid = ffi::alias_to_luid(&name)?;
|
||||||
|
iface::check_interface(&luid)?;
|
||||||
|
|
||||||
|
let handle = iface::open_interface(&luid)?;
|
||||||
|
let index = ffi::luid_to_index(&luid).map(|index| index as u32)?;
|
||||||
|
Ok(Self { index, luid, handle })
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn delete(self) -> io::Result<()> {
|
||||||
|
iface::delete_interface(&self.luid)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IFace for TapDevice {
|
||||||
|
fn shutdown(&self) -> io::Result<()> {
|
||||||
|
self.set_status(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_index(&self) -> io::Result<u32> {
|
||||||
|
Ok(self.index)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_name(&self) -> io::Result<String> {
|
||||||
|
ffi::luid_to_alias(&self.luid).map(|name| decode_utf16(&name))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_name(&self, new_name: &str) -> io::Result<()> {
|
||||||
|
let name = self.get_name()?;
|
||||||
|
netsh::set_interface_name(&name, new_name)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_ip<IP>(&self, address: IP, mask: IP) -> io::Result<()> where IP: Into<Ipv4Addr> {
|
||||||
|
let index = self.get_index()?;
|
||||||
|
netsh::set_interface_ip(index, &address.into(), &mask.into())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_route<IP>(&self, dest: IP, netmask: IP, gateway: IP) -> io::Result<()> where IP: Into<Ipv4Addr> {
|
||||||
|
let index = self.get_index()?;
|
||||||
|
route::add_route(index, dest.into(), netmask.into(), gateway.into())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn delete_route<IP>(&self, dest: IP, netmask: IP, gateway: IP) -> io::Result<()> where IP: Into<Ipv4Addr> {
|
||||||
|
let index = self.get_index()?;
|
||||||
|
route::delete_route(index, dest.into(), netmask.into(), gateway.into())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_mtu(&self, mtu: u16) -> io::Result<()> {
|
||||||
|
let index = self.get_index()?;
|
||||||
|
netsh::set_interface_mtu(index, mtu)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_metric(&self, metric: u16) -> io::Result<()> {
|
||||||
|
let index = self.get_index()?;
|
||||||
|
netsh::set_interface_metric(index, metric)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl TapDevice {
|
||||||
|
pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
|
||||||
|
ffi::read_file(self.handle, buf).map(|res| res as _)
|
||||||
|
}
|
||||||
|
pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
|
||||||
|
ffi::write_file(self.handle, buf).map(|res| res as _)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for TapDevice {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
let _ = ffi::close_handle(self.handle);
|
||||||
|
let _ = iface::delete_interface(&self.luid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
use log::*;
|
||||||
|
|
||||||
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
|
use widestring::U16CStr;
|
||||||
|
use crate::tun::wintun_raw;
|
||||||
|
|
||||||
|
/// Sets the logger wintun will use when logging. Maps to the WintunSetLogger C function
|
||||||
|
pub fn set_logger(win_tun: &wintun_raw::wintun, f: wintun_raw::WINTUN_LOGGER_CALLBACK) {
|
||||||
|
unsafe { win_tun.WintunSetLogger(f) };
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn reset_logger(win_tun: &wintun_raw::wintun) {
|
||||||
|
set_logger(win_tun, None);
|
||||||
|
}
|
||||||
|
|
||||||
|
static SET_LOGGER: AtomicBool = AtomicBool::new(false);
|
||||||
|
|
||||||
|
/// The logger that is active by default. Logs messages to the log crate
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
/// `message` must be a valid pointer that points to an aligned null terminated UTF-16 string
|
||||||
|
pub unsafe extern "C" fn default_logger(
|
||||||
|
level: wintun_raw::WINTUN_LOGGER_LEVEL,
|
||||||
|
_timestamp: wintun_raw::DWORD64,
|
||||||
|
message: *const wintun_raw::WCHAR,
|
||||||
|
) {
|
||||||
|
//Cant wait for RFC 2585
|
||||||
|
#[allow(unused_unsafe)]
|
||||||
|
//Wintun will always give us a valid UTF16 null termineted string
|
||||||
|
let msg = unsafe { U16CStr::from_ptr_str(message) };
|
||||||
|
let utf8_msg = msg.to_string_lossy();
|
||||||
|
match level {
|
||||||
|
wintun_raw::WINTUN_LOGGER_LEVEL_WINTUN_LOG_INFO => info!("WinTun: {}", utf8_msg),
|
||||||
|
wintun_raw::WINTUN_LOGGER_LEVEL_WINTUN_LOG_WARN => warn!("WinTun: {}", utf8_msg),
|
||||||
|
wintun_raw::WINTUN_LOGGER_LEVEL_WINTUN_LOG_ERR => error!("WinTun: {}", utf8_msg),
|
||||||
|
_ => error!("WinTun: {} (with invalid log level {})", utf8_msg, level),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn set_default_logger_if_unset(win_tun: &wintun_raw::wintun) {
|
||||||
|
if SET_LOGGER
|
||||||
|
.compare_exchange(false, true, Ordering::SeqCst, Ordering::Relaxed)
|
||||||
|
.is_ok()
|
||||||
|
{
|
||||||
|
set_logger(win_tun, Some(default_logger));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,314 @@
|
|||||||
|
use std::io;
|
||||||
|
use std::net::Ipv4Addr;
|
||||||
|
|
||||||
|
use winapi::um::{handleapi, synchapi, winbase, winnt};
|
||||||
|
|
||||||
|
use crate::{decode_utf16, encode_utf16, ffi, IFace, netsh, route};
|
||||||
|
|
||||||
|
mod wintun_raw;
|
||||||
|
mod log;
|
||||||
|
pub mod packet;
|
||||||
|
|
||||||
|
/// The maximum size of wintun's internal ring buffer (in bytes)
|
||||||
|
pub const MAX_RING_CAPACITY: u32 = 0x400_0000;
|
||||||
|
|
||||||
|
/// The minimum size of wintun's internal ring buffer (in bytes)
|
||||||
|
pub const MIN_RING_CAPACITY: u32 = 0x2_0000;
|
||||||
|
|
||||||
|
/// Maximum pool name length including zero terminator
|
||||||
|
pub const MAX_POOL: usize = 256;
|
||||||
|
|
||||||
|
|
||||||
|
pub struct TunDevice {
|
||||||
|
pub(crate) luid:u64,
|
||||||
|
pub(crate) index: u32,
|
||||||
|
/// The session handle given to us by WintunStartSession
|
||||||
|
pub(crate) session: wintun_raw::WINTUN_SESSION_HANDLE,
|
||||||
|
|
||||||
|
/// Shared dll for required wintun driver functions
|
||||||
|
pub(crate) win_tun: wintun_raw::wintun,
|
||||||
|
|
||||||
|
/// Windows event handle that is signaled by the wintun driver when data becomes available to
|
||||||
|
/// read
|
||||||
|
pub(crate) read_event: winnt::HANDLE,
|
||||||
|
|
||||||
|
/// Windows event handle that is signaled when [`TunSession::shutdown`] is called force blocking
|
||||||
|
/// readers to exit
|
||||||
|
pub(crate) shutdown_event: winnt::HANDLE,
|
||||||
|
|
||||||
|
/// The adapter that owns this session
|
||||||
|
pub(crate) adapter: wintun_raw::WINTUN_ADAPTER_HANDLE,
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl Send for TunDevice {}
|
||||||
|
|
||||||
|
unsafe impl Sync for TunDevice {}
|
||||||
|
winapi::DEFINE_GUID! {
|
||||||
|
GUID_NETWORK_ADAPTER,
|
||||||
|
0x4d36e972, 0xe325, 0x11ce,
|
||||||
|
0xbf, 0xc1, 0x08, 0x00, 0x2b, 0xe1, 0x03, 0x18
|
||||||
|
}
|
||||||
|
impl TunDevice {
|
||||||
|
pub unsafe fn create<L>(library: L, pool: &str, name: &str) -> io::Result<Self>
|
||||||
|
where L: Into<libloading::Library>, {
|
||||||
|
let win_tun = match wintun_raw::wintun::from_library(library) {
|
||||||
|
Ok(win_tun) => { win_tun }
|
||||||
|
Err(e) => {
|
||||||
|
return Err(io::Error::new(io::ErrorKind::Other, format!("library error {:?} ", e)));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let pool_utf16 = encode_utf16(pool);
|
||||||
|
if pool_utf16.len() > MAX_POOL {
|
||||||
|
return Err(io::Error::new(io::ErrorKind::Other, format!("长度大于{}:{:?}", MAX_POOL, pool)));
|
||||||
|
}
|
||||||
|
let name_utf16 = encode_utf16(name);
|
||||||
|
if name_utf16.len() > MAX_POOL {
|
||||||
|
return Err(io::Error::new(io::ErrorKind::Other, format!("长度大于{}:{:?}", MAX_POOL, pool)));
|
||||||
|
}
|
||||||
|
//SAFETY: guid is a unique integer so transmuting either all zeroes or the user's preferred
|
||||||
|
//guid to the winapi guid type is safe and will allow the windows kernel to see our GUID
|
||||||
|
let guid_struct: wintun_raw::GUID = unsafe { std::mem::transmute(GUID_NETWORK_ADAPTER) };
|
||||||
|
let guid_ptr = &guid_struct as *const wintun_raw::GUID;
|
||||||
|
|
||||||
|
log::set_default_logger_if_unset(&win_tun);
|
||||||
|
|
||||||
|
//SAFETY: the function is loaded from the wintun dll properly, we are providing valid
|
||||||
|
//pointers, and all the strings are correct null terminated UTF-16. This safety rationale
|
||||||
|
//applies for all Wintun* functions below
|
||||||
|
let adapter = win_tun.WintunCreateAdapter(pool_utf16.as_ptr(), name_utf16.as_ptr(), guid_ptr);
|
||||||
|
if adapter.is_null() {
|
||||||
|
return Err(io::Error::new(io::ErrorKind::Other, "Failed to crate adapter"));
|
||||||
|
}
|
||||||
|
Self::init(win_tun, adapter)
|
||||||
|
}
|
||||||
|
pub unsafe fn init(win_tun: wintun_raw::wintun, adapter: wintun_raw::WINTUN_ADAPTER_HANDLE) -> io::Result<Self> {
|
||||||
|
// 开启session
|
||||||
|
let session = win_tun.WintunStartSession(adapter, 128 * 1024);
|
||||||
|
if session.is_null() {
|
||||||
|
return Err(io::Error::new(io::ErrorKind::Other, "WintunStartSession failed"));
|
||||||
|
}
|
||||||
|
//SAFETY: We follow the contract required by CreateEventA. See MSDN
|
||||||
|
//(the pointers are allowed to be null, and 0 is okay for the others)
|
||||||
|
let shutdown_event = synchapi::CreateEventA(std::ptr::null_mut(),
|
||||||
|
0, 0, std::ptr::null_mut());
|
||||||
|
let read_event = win_tun.WintunGetReadWaitEvent(session) as winnt::HANDLE;
|
||||||
|
let mut luid: wintun_raw::NET_LUID = std::mem::zeroed();
|
||||||
|
win_tun.WintunGetAdapterLUID(adapter, &mut luid as *mut wintun_raw::NET_LUID);
|
||||||
|
let index = ffi::luid_to_index(&std::mem::transmute(luid)).map(|index| index as u32)?;
|
||||||
|
Ok(TunDevice {
|
||||||
|
luid:std::mem::transmute(luid),
|
||||||
|
index,
|
||||||
|
session,
|
||||||
|
win_tun,
|
||||||
|
read_event,
|
||||||
|
shutdown_event,
|
||||||
|
adapter,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
pub unsafe fn delete_for_name<L>(library: L, name: &str) -> io::Result<()>
|
||||||
|
where L: Into<libloading::Library>, {
|
||||||
|
let win_tun = match wintun_raw::wintun::from_library(library) {
|
||||||
|
Ok(win_tun) => win_tun,
|
||||||
|
Err(e) => {
|
||||||
|
return Err(io::Error::new(io::ErrorKind::Other, format!("library error {:?} ", e)));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
log::set_default_logger_if_unset(&win_tun);
|
||||||
|
let name_utf16 = encode_utf16(name);
|
||||||
|
let adapter = win_tun.WintunOpenAdapter(name_utf16.as_ptr());
|
||||||
|
if adapter.is_null() {
|
||||||
|
return Err(io::Error::new(io::ErrorKind::Other, "Failed to open adapter"));
|
||||||
|
}
|
||||||
|
win_tun.WintunCloseAdapter(adapter);
|
||||||
|
win_tun.WintunDeleteDriver();
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
pub fn delete(self) -> io::Result<()> {
|
||||||
|
drop(self);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
pub fn version(&self) -> io::Result<Version> {
|
||||||
|
let version = unsafe { self.win_tun.WintunGetRunningDriverVersion() };
|
||||||
|
if version == 0 {
|
||||||
|
return Err(io::Error::new(io::ErrorKind::Other, "WintunGetRunningDriverVersion"));
|
||||||
|
} else {
|
||||||
|
Ok(Version {
|
||||||
|
major: ((version >> 16) & 0xFF) as u16,
|
||||||
|
minor: (version & 0xFF) as u16,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||||
|
pub struct Version {
|
||||||
|
pub major: u16,
|
||||||
|
pub minor: u16,
|
||||||
|
}
|
||||||
|
|
||||||
|
// impl TunDevice {
|
||||||
|
// fn get_adapter_luid(&self) -> u64 {
|
||||||
|
// let mut luid: wintun_raw::NET_LUID = unsafe { std::mem::zeroed() };
|
||||||
|
// unsafe { self.win_tun.WintunGetAdapterLUID(self.adapter, &mut luid as *mut wintun_raw::NET_LUID) };
|
||||||
|
// unsafe { std::mem::transmute(luid) }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
impl IFace for TunDevice {
|
||||||
|
fn shutdown(&self) -> io::Result<()> {
|
||||||
|
let _ = unsafe { synchapi::SetEvent(self.shutdown_event) };
|
||||||
|
let _ = unsafe { handleapi::CloseHandle(self.shutdown_event) };
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_index(&self) -> io::Result<u32> {
|
||||||
|
Ok(self.index)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_name(&self) -> io::Result<String> {
|
||||||
|
let luid = self.luid;
|
||||||
|
ffi::luid_to_alias(&unsafe { std::mem::transmute(luid) }).map(|name| {
|
||||||
|
decode_utf16(&name)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_name(&self, new_name: &str) -> io::Result<()> {
|
||||||
|
let name = self.get_name()?;
|
||||||
|
netsh::set_interface_name(&name, new_name)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_ip<IP>(&self, address: IP, mask: IP) -> io::Result<()> where IP: Into<Ipv4Addr> {
|
||||||
|
netsh::set_interface_ip(self.get_index()?, &address.into(), &mask.into())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_route<IP>(&self, dest: IP, netmask: IP, gateway: IP) -> io::Result<()> where IP: Into<Ipv4Addr> {
|
||||||
|
route::add_route(self.get_index()?, dest.into(), netmask.into(), gateway.into())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn delete_route<IP>(&self, dest: IP, netmask: IP, gateway: IP) -> io::Result<()> where IP: Into<Ipv4Addr> {
|
||||||
|
route::delete_route(self.get_index()?, dest.into(), netmask.into(), gateway.into())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_mtu(&self, mtu: u16) -> io::Result<()> {
|
||||||
|
netsh::set_interface_mtu(self.get_index()?, mtu)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_metric(&self, metric: u16) -> io::Result<()> {
|
||||||
|
let index = self.get_index()?;
|
||||||
|
netsh::set_interface_metric(index, metric)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TunDevice {
|
||||||
|
pub fn try_receive(&self) -> io::Result<Option<packet::TunPacket>> {
|
||||||
|
let mut size = 0u32;
|
||||||
|
|
||||||
|
let bytes_ptr = unsafe {
|
||||||
|
self.win_tun
|
||||||
|
.WintunReceivePacket(self.session, &mut size as *mut u32)
|
||||||
|
};
|
||||||
|
|
||||||
|
debug_assert!(size <= u16::MAX as u32);
|
||||||
|
if bytes_ptr.is_null() {
|
||||||
|
//Wintun returns ERROR_NO_MORE_ITEMS instead of blocking if packets are not available
|
||||||
|
let last_error = unsafe { winapi::um::errhandlingapi::GetLastError() };
|
||||||
|
if last_error == winapi::shared::winerror::ERROR_NO_MORE_ITEMS {
|
||||||
|
Ok(None)
|
||||||
|
} else {
|
||||||
|
Err(io::Error::new(io::ErrorKind::Other, "try_receive failed"))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Ok(Some(packet::TunPacket {
|
||||||
|
kind: packet::Kind::ReceivePacket,
|
||||||
|
size: size as usize,
|
||||||
|
//SAFETY: ptr is non null, aligned for u8, and readable for up to size bytes (which
|
||||||
|
//must be less than isize::MAX because bytes is a u16
|
||||||
|
bytes_ptr,
|
||||||
|
tun_device: Some(&self),
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn receive_blocking(&self) -> io::Result<packet::TunPacket> {
|
||||||
|
loop {
|
||||||
|
//Try 5 times to receive without blocking so we don't have to issue a syscall to wait
|
||||||
|
//for the event if packets are being received at a rapid rate
|
||||||
|
for _ in 0..5 {
|
||||||
|
match self.try_receive()? {
|
||||||
|
None => {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Some(packet) => {
|
||||||
|
return Ok(packet);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//Wait on both the read handle and the shutdown handle so that we stop when requested
|
||||||
|
let handles = [self.read_event, self.shutdown_event];
|
||||||
|
let result = unsafe {
|
||||||
|
//SAFETY: We abide by the requirements of WaitForMultipleObjects, handles is a
|
||||||
|
//pointer to valid, aligned, stack memory
|
||||||
|
synchapi::WaitForMultipleObjects(
|
||||||
|
2,
|
||||||
|
&handles as *const winnt::HANDLE,
|
||||||
|
0,
|
||||||
|
winbase::INFINITE,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
match result {
|
||||||
|
winbase::WAIT_FAILED => return Err(io::Error::new(io::ErrorKind::Other, "WAIT_FAILED")),
|
||||||
|
_ => {
|
||||||
|
if result == winbase::WAIT_OBJECT_0 {
|
||||||
|
//We have data!
|
||||||
|
continue;
|
||||||
|
} else if result == winbase::WAIT_OBJECT_0 + 1 {
|
||||||
|
//Shutdown event triggered
|
||||||
|
return Err(io::Error::new(io::ErrorKind::Other, "Shutdown event triggered"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TunDevice {
|
||||||
|
pub fn allocate_send_packet(&self, size: u16) -> io::Result<packet::TunPacket> {
|
||||||
|
let bytes_ptr = unsafe {
|
||||||
|
self.win_tun.WintunAllocateSendPacket(self.session, size as u32)
|
||||||
|
};
|
||||||
|
if bytes_ptr.is_null() {
|
||||||
|
Err(io::Error::new(io::ErrorKind::Other, "allocate_send_packet failed"))
|
||||||
|
} else {
|
||||||
|
Ok(packet::TunPacket {
|
||||||
|
kind: packet::Kind::SendPacketPending,
|
||||||
|
size: size as usize,
|
||||||
|
//SAFETY: ptr is non null, aligned for u8, and readable for up to size bytes (which
|
||||||
|
//must be less than isize::MAX because bytes is a u16
|
||||||
|
bytes_ptr,
|
||||||
|
tun_device: None,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn send_packet(&self, mut packet: packet::TunPacket) {
|
||||||
|
assert!(matches!(packet.kind, packet::Kind::SendPacketPending));
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
self.win_tun
|
||||||
|
.WintunSendPacket(self.session, packet.bytes_ptr)
|
||||||
|
};
|
||||||
|
//Mark the packet at sent
|
||||||
|
packet.kind = packet::Kind::SendPacketSent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl Drop for TunDevice {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
//Close adapter on drop
|
||||||
|
//This is why we need an Arc of wintun
|
||||||
|
unsafe {
|
||||||
|
self.win_tun.WintunCloseAdapter(self.adapter);
|
||||||
|
self.win_tun.WintunDeleteDriver()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
|
||||||
|
use crate::TunDevice;
|
||||||
|
|
||||||
|
pub(crate) enum Kind {
|
||||||
|
SendPacketPending,
|
||||||
|
//Send packet type, but not sent yet
|
||||||
|
SendPacketSent,
|
||||||
|
//Send packet type - sent
|
||||||
|
ReceivePacket,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Represents a wintun packet
|
||||||
|
pub struct TunPacket<'a> {
|
||||||
|
pub(crate) kind: Kind,
|
||||||
|
pub(crate) size:usize,
|
||||||
|
pub(crate) bytes_ptr: *const u8,
|
||||||
|
|
||||||
|
//Share ownership of session to prevent the session from being dropped before packets that
|
||||||
|
//belong to it
|
||||||
|
pub(crate) tun_device: Option<&'a TunDevice>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl <'a>TunPacket<'a> {
|
||||||
|
/// Returns the bytes this packet holds as &mut.
|
||||||
|
/// The lifetime of the bytes is tied to the lifetime of this packet.
|
||||||
|
pub fn bytes_mut(&mut self) -> &mut [u8] {
|
||||||
|
unsafe { std::slice::from_raw_parts_mut(self.bytes_ptr as *mut u8, self.size) }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns an immutable reference to the bytes this packet holds.
|
||||||
|
/// The lifetime of the bytes is tied to the lifetime of this packet.
|
||||||
|
pub fn bytes(&self) -> &[u8] {
|
||||||
|
unsafe { std::slice::from_raw_parts(self.bytes_ptr,self.size) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl <'a>Drop for TunPacket<'a> {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
match self.kind {
|
||||||
|
Kind::ReceivePacket => {
|
||||||
|
unsafe {
|
||||||
|
//SAFETY:
|
||||||
|
//
|
||||||
|
// 1. We share ownership of the session therefore it hasn't been dropped yet
|
||||||
|
// 2. Bytes is valid because each packet holds exclusive access to a region of the
|
||||||
|
// ring buffer that the wintun session owns. We return that region of
|
||||||
|
// memory back to wintun here
|
||||||
|
let tun_device = self.tun_device.unwrap();
|
||||||
|
tun_device.win_tun
|
||||||
|
.WintunReleaseReceivePacket(tun_device.session, self.bytes_ptr)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
Kind::SendPacketPending => {
|
||||||
|
//If someone allocates a packet with session.allocate_send_packet() and then it is
|
||||||
|
//dropped without being sent, this will hold up the send queue because wintun expects
|
||||||
|
//that every allocated packet is sent
|
||||||
|
panic!("Packet was never sent!");
|
||||||
|
}
|
||||||
|
Kind::SendPacketSent => {
|
||||||
|
//Nop
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,447 @@
|
|||||||
|
/* automatically generated by rust-bindgen 0.59.1 */
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Copy, Clone, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
|
||||||
|
pub struct __BindgenBitfieldUnit<Storage> {
|
||||||
|
storage: Storage,
|
||||||
|
}
|
||||||
|
impl<Storage> __BindgenBitfieldUnit<Storage> {
|
||||||
|
#[inline]
|
||||||
|
pub const fn new(storage: Storage) -> Self {
|
||||||
|
Self { storage }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<Storage> __BindgenBitfieldUnit<Storage>
|
||||||
|
where
|
||||||
|
Storage: AsRef<[u8]> + AsMut<[u8]>,
|
||||||
|
{
|
||||||
|
#[inline]
|
||||||
|
pub fn get_bit(&self, index: usize) -> bool {
|
||||||
|
debug_assert!(index / 8 < self.storage.as_ref().len());
|
||||||
|
let byte_index = index / 8;
|
||||||
|
let byte = self.storage.as_ref()[byte_index];
|
||||||
|
let bit_index = if cfg!(target_endian = "big") {
|
||||||
|
7 - (index % 8)
|
||||||
|
} else {
|
||||||
|
index % 8
|
||||||
|
};
|
||||||
|
let mask = 1 << bit_index;
|
||||||
|
byte & mask == mask
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
pub fn set_bit(&mut self, index: usize, val: bool) {
|
||||||
|
debug_assert!(index / 8 < self.storage.as_ref().len());
|
||||||
|
let byte_index = index / 8;
|
||||||
|
let byte = &mut self.storage.as_mut()[byte_index];
|
||||||
|
let bit_index = if cfg!(target_endian = "big") {
|
||||||
|
7 - (index % 8)
|
||||||
|
} else {
|
||||||
|
index % 8
|
||||||
|
};
|
||||||
|
let mask = 1 << bit_index;
|
||||||
|
if val {
|
||||||
|
*byte |= mask;
|
||||||
|
} else {
|
||||||
|
*byte &= !mask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
pub fn get(&self, bit_offset: usize, bit_width: u8) -> u64 {
|
||||||
|
debug_assert!(bit_width <= 64);
|
||||||
|
debug_assert!(bit_offset / 8 < self.storage.as_ref().len());
|
||||||
|
debug_assert!((bit_offset + (bit_width as usize)) / 8 <= self.storage.as_ref().len());
|
||||||
|
let mut val = 0;
|
||||||
|
for i in 0..(bit_width as usize) {
|
||||||
|
if self.get_bit(i + bit_offset) {
|
||||||
|
let index = if cfg!(target_endian = "big") {
|
||||||
|
bit_width as usize - 1 - i
|
||||||
|
} else {
|
||||||
|
i
|
||||||
|
};
|
||||||
|
val |= 1 << index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
pub fn set(&mut self, bit_offset: usize, bit_width: u8, val: u64) {
|
||||||
|
debug_assert!(bit_width <= 64);
|
||||||
|
debug_assert!(bit_offset / 8 < self.storage.as_ref().len());
|
||||||
|
debug_assert!((bit_offset + (bit_width as usize)) / 8 <= self.storage.as_ref().len());
|
||||||
|
for i in 0..(bit_width as usize) {
|
||||||
|
let mask = 1 << i;
|
||||||
|
let val_bit_is_set = val & mask == mask;
|
||||||
|
let index = if cfg!(target_endian = "big") {
|
||||||
|
bit_width as usize - 1 - i
|
||||||
|
} else {
|
||||||
|
i
|
||||||
|
};
|
||||||
|
self.set_bit(index + bit_offset, val_bit_is_set);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub type wchar_t = ::std::os::raw::c_ushort;
|
||||||
|
pub type DWORD = ::std::os::raw::c_ulong;
|
||||||
|
pub type BOOL = ::std::os::raw::c_int;
|
||||||
|
pub type BYTE = ::std::os::raw::c_uchar;
|
||||||
|
pub type ULONG64 = ::std::os::raw::c_ulonglong;
|
||||||
|
pub type DWORD64 = ::std::os::raw::c_ulonglong;
|
||||||
|
pub type WCHAR = wchar_t;
|
||||||
|
pub type LPCWSTR = *const WCHAR;
|
||||||
|
pub type HANDLE = *mut ::std::os::raw::c_void;
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Debug, Copy, Clone)]
|
||||||
|
pub struct _GUID {
|
||||||
|
pub Data1: ::std::os::raw::c_ulong,
|
||||||
|
pub Data2: ::std::os::raw::c_ushort,
|
||||||
|
pub Data3: ::std::os::raw::c_ushort,
|
||||||
|
pub Data4: [::std::os::raw::c_uchar; 8usize],
|
||||||
|
}
|
||||||
|
#[test]
|
||||||
|
fn bindgen_test_layout__GUID() {
|
||||||
|
assert_eq!(
|
||||||
|
::std::mem::size_of::<_GUID>(),
|
||||||
|
16usize,
|
||||||
|
concat!("Size of: ", stringify!(_GUID))
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
::std::mem::align_of::<_GUID>(),
|
||||||
|
4usize,
|
||||||
|
concat!("Alignment of ", stringify!(_GUID))
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
unsafe { &(*(::std::ptr::null::<_GUID>())).Data1 as *const _ as usize },
|
||||||
|
0usize,
|
||||||
|
concat!(
|
||||||
|
"Offset of field: ",
|
||||||
|
stringify!(_GUID),
|
||||||
|
"::",
|
||||||
|
stringify!(Data1)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
unsafe { &(*(::std::ptr::null::<_GUID>())).Data2 as *const _ as usize },
|
||||||
|
4usize,
|
||||||
|
concat!(
|
||||||
|
"Offset of field: ",
|
||||||
|
stringify!(_GUID),
|
||||||
|
"::",
|
||||||
|
stringify!(Data2)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
unsafe { &(*(::std::ptr::null::<_GUID>())).Data3 as *const _ as usize },
|
||||||
|
6usize,
|
||||||
|
concat!(
|
||||||
|
"Offset of field: ",
|
||||||
|
stringify!(_GUID),
|
||||||
|
"::",
|
||||||
|
stringify!(Data3)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
unsafe { &(*(::std::ptr::null::<_GUID>())).Data4 as *const _ as usize },
|
||||||
|
8usize,
|
||||||
|
concat!(
|
||||||
|
"Offset of field: ",
|
||||||
|
stringify!(_GUID),
|
||||||
|
"::",
|
||||||
|
stringify!(Data4)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
pub type GUID = _GUID;
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
pub union _NET_LUID_LH {
|
||||||
|
pub Value: ULONG64,
|
||||||
|
pub Info: _NET_LUID_LH__bindgen_ty_1,
|
||||||
|
}
|
||||||
|
#[repr(C)]
|
||||||
|
#[repr(align(8))]
|
||||||
|
#[derive(Debug, Copy, Clone)]
|
||||||
|
pub struct _NET_LUID_LH__bindgen_ty_1 {
|
||||||
|
pub _bitfield_align_1: [u32; 0],
|
||||||
|
pub _bitfield_1: __BindgenBitfieldUnit<[u8; 8usize]>,
|
||||||
|
}
|
||||||
|
#[test]
|
||||||
|
fn bindgen_test_layout__NET_LUID_LH__bindgen_ty_1() {
|
||||||
|
assert_eq!(
|
||||||
|
::std::mem::size_of::<_NET_LUID_LH__bindgen_ty_1>(),
|
||||||
|
8usize,
|
||||||
|
concat!("Size of: ", stringify!(_NET_LUID_LH__bindgen_ty_1))
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
::std::mem::align_of::<_NET_LUID_LH__bindgen_ty_1>(),
|
||||||
|
8usize,
|
||||||
|
concat!("Alignment of ", stringify!(_NET_LUID_LH__bindgen_ty_1))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
impl _NET_LUID_LH__bindgen_ty_1 {
|
||||||
|
#[inline]
|
||||||
|
pub fn Reserved(&self) -> ULONG64 {
|
||||||
|
unsafe { ::std::mem::transmute(self._bitfield_1.get(0usize, 24u8) as u64) }
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
pub fn set_Reserved(&mut self, val: ULONG64) {
|
||||||
|
unsafe {
|
||||||
|
let val: u64 = ::std::mem::transmute(val);
|
||||||
|
self._bitfield_1.set(0usize, 24u8, val as u64)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
pub fn NetLuidIndex(&self) -> ULONG64 {
|
||||||
|
unsafe { ::std::mem::transmute(self._bitfield_1.get(24usize, 24u8) as u64) }
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
pub fn set_NetLuidIndex(&mut self, val: ULONG64) {
|
||||||
|
unsafe {
|
||||||
|
let val: u64 = ::std::mem::transmute(val);
|
||||||
|
self._bitfield_1.set(24usize, 24u8, val as u64)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
pub fn IfType(&self) -> ULONG64 {
|
||||||
|
unsafe { ::std::mem::transmute(self._bitfield_1.get(48usize, 16u8) as u64) }
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
pub fn set_IfType(&mut self, val: ULONG64) {
|
||||||
|
unsafe {
|
||||||
|
let val: u64 = ::std::mem::transmute(val);
|
||||||
|
self._bitfield_1.set(48usize, 16u8, val as u64)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
pub fn new_bitfield_1(
|
||||||
|
Reserved: ULONG64,
|
||||||
|
NetLuidIndex: ULONG64,
|
||||||
|
IfType: ULONG64,
|
||||||
|
) -> __BindgenBitfieldUnit<[u8; 8usize]> {
|
||||||
|
let mut __bindgen_bitfield_unit: __BindgenBitfieldUnit<[u8; 8usize]> = Default::default();
|
||||||
|
__bindgen_bitfield_unit.set(0usize, 24u8, {
|
||||||
|
let Reserved: u64 = unsafe { ::std::mem::transmute(Reserved) };
|
||||||
|
Reserved as u64
|
||||||
|
});
|
||||||
|
__bindgen_bitfield_unit.set(24usize, 24u8, {
|
||||||
|
let NetLuidIndex: u64 = unsafe { ::std::mem::transmute(NetLuidIndex) };
|
||||||
|
NetLuidIndex as u64
|
||||||
|
});
|
||||||
|
__bindgen_bitfield_unit.set(48usize, 16u8, {
|
||||||
|
let IfType: u64 = unsafe { ::std::mem::transmute(IfType) };
|
||||||
|
IfType as u64
|
||||||
|
});
|
||||||
|
__bindgen_bitfield_unit
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[test]
|
||||||
|
fn bindgen_test_layout__NET_LUID_LH() {
|
||||||
|
assert_eq!(
|
||||||
|
::std::mem::size_of::<_NET_LUID_LH>(),
|
||||||
|
8usize,
|
||||||
|
concat!("Size of: ", stringify!(_NET_LUID_LH))
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
::std::mem::align_of::<_NET_LUID_LH>(),
|
||||||
|
8usize,
|
||||||
|
concat!("Alignment of ", stringify!(_NET_LUID_LH))
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
unsafe { &(*(::std::ptr::null::<_NET_LUID_LH>())).Value as *const _ as usize },
|
||||||
|
0usize,
|
||||||
|
concat!(
|
||||||
|
"Offset of field: ",
|
||||||
|
stringify!(_NET_LUID_LH),
|
||||||
|
"::",
|
||||||
|
stringify!(Value)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
unsafe { &(*(::std::ptr::null::<_NET_LUID_LH>())).Info as *const _ as usize },
|
||||||
|
0usize,
|
||||||
|
concat!(
|
||||||
|
"Offset of field: ",
|
||||||
|
stringify!(_NET_LUID_LH),
|
||||||
|
"::",
|
||||||
|
stringify!(Info)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
pub type NET_LUID_LH = _NET_LUID_LH;
|
||||||
|
pub type NET_LUID = NET_LUID_LH;
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Debug, Copy, Clone)]
|
||||||
|
pub struct _WINTUN_ADAPTER {
|
||||||
|
_unused: [u8; 0],
|
||||||
|
}
|
||||||
|
#[doc = " A handle representing Wintun adapter"]
|
||||||
|
pub type WINTUN_ADAPTER_HANDLE = *mut _WINTUN_ADAPTER;
|
||||||
|
#[doc = "< Informational"]
|
||||||
|
pub const WINTUN_LOGGER_LEVEL_WINTUN_LOG_INFO: WINTUN_LOGGER_LEVEL = 0;
|
||||||
|
#[doc = "< Warning"]
|
||||||
|
pub const WINTUN_LOGGER_LEVEL_WINTUN_LOG_WARN: WINTUN_LOGGER_LEVEL = 1;
|
||||||
|
#[doc = "< Error"]
|
||||||
|
pub const WINTUN_LOGGER_LEVEL_WINTUN_LOG_ERR: WINTUN_LOGGER_LEVEL = 2;
|
||||||
|
#[doc = " Determines the level of logging, passed to WINTUN_LOGGER_CALLBACK."]
|
||||||
|
pub type WINTUN_LOGGER_LEVEL = ::std::os::raw::c_int;
|
||||||
|
#[doc = " Called by internal logger to report diagnostic messages"]
|
||||||
|
#[doc = ""]
|
||||||
|
#[doc = " @param Level Message level."]
|
||||||
|
#[doc = ""]
|
||||||
|
#[doc = " @param Timestamp Message timestamp in in 100ns intervals since 1601-01-01 UTC."]
|
||||||
|
#[doc = ""]
|
||||||
|
#[doc = " @param Message Message text."]
|
||||||
|
pub type WINTUN_LOGGER_CALLBACK = ::std::option::Option<
|
||||||
|
unsafe extern "C" fn(Level: WINTUN_LOGGER_LEVEL, Timestamp: DWORD64, Message: LPCWSTR),
|
||||||
|
>;
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Debug, Copy, Clone)]
|
||||||
|
pub struct _TUN_SESSION {
|
||||||
|
_unused: [u8; 0],
|
||||||
|
}
|
||||||
|
#[doc = " A handle representing Wintun session"]
|
||||||
|
pub type WINTUN_SESSION_HANDLE = *mut _TUN_SESSION;
|
||||||
|
extern crate libloading;
|
||||||
|
pub struct wintun {
|
||||||
|
__library: ::libloading::Library,
|
||||||
|
pub WintunCreateAdapter: unsafe extern "C" fn(
|
||||||
|
arg1: LPCWSTR,
|
||||||
|
arg2: LPCWSTR,
|
||||||
|
arg3: *const GUID,
|
||||||
|
) -> WINTUN_ADAPTER_HANDLE,
|
||||||
|
pub WintunCloseAdapter: unsafe extern "C" fn(arg1: WINTUN_ADAPTER_HANDLE),
|
||||||
|
pub WintunOpenAdapter: unsafe extern "C" fn(arg1: LPCWSTR) -> WINTUN_ADAPTER_HANDLE,
|
||||||
|
pub WintunGetAdapterLUID:
|
||||||
|
unsafe extern "C" fn(arg1: WINTUN_ADAPTER_HANDLE, arg2: *mut NET_LUID),
|
||||||
|
pub WintunGetRunningDriverVersion: unsafe extern "C" fn() -> DWORD,
|
||||||
|
pub WintunDeleteDriver: unsafe extern "C" fn() -> BOOL,
|
||||||
|
pub WintunSetLogger: unsafe extern "C" fn(arg1: WINTUN_LOGGER_CALLBACK),
|
||||||
|
pub WintunStartSession:
|
||||||
|
unsafe extern "C" fn(arg1: WINTUN_ADAPTER_HANDLE, arg2: DWORD) -> WINTUN_SESSION_HANDLE,
|
||||||
|
pub WintunEndSession: unsafe extern "C" fn(arg1: WINTUN_SESSION_HANDLE),
|
||||||
|
pub WintunGetReadWaitEvent: unsafe extern "C" fn(arg1: WINTUN_SESSION_HANDLE) -> HANDLE,
|
||||||
|
pub WintunReceivePacket:
|
||||||
|
unsafe extern "C" fn(arg1: WINTUN_SESSION_HANDLE, arg2: *mut DWORD) -> *mut BYTE,
|
||||||
|
pub WintunReleaseReceivePacket:
|
||||||
|
unsafe extern "C" fn(arg1: WINTUN_SESSION_HANDLE, arg2: *const BYTE),
|
||||||
|
pub WintunAllocateSendPacket:
|
||||||
|
unsafe extern "C" fn(arg1: WINTUN_SESSION_HANDLE, arg2: DWORD) -> *mut BYTE,
|
||||||
|
pub WintunSendPacket: unsafe extern "C" fn(arg1: WINTUN_SESSION_HANDLE, arg2: *const BYTE),
|
||||||
|
}
|
||||||
|
impl wintun {
|
||||||
|
pub unsafe fn new<P>(path: P) -> Result<Self, ::libloading::Error>
|
||||||
|
where
|
||||||
|
P: AsRef<::std::ffi::OsStr>,
|
||||||
|
{
|
||||||
|
let library = ::libloading::Library::new(path)?;
|
||||||
|
Self::from_library(library)
|
||||||
|
}
|
||||||
|
pub unsafe fn from_library<L>(library: L) -> Result<Self, ::libloading::Error>
|
||||||
|
where
|
||||||
|
L: Into<::libloading::Library>,
|
||||||
|
{
|
||||||
|
let __library = library.into();
|
||||||
|
let WintunCreateAdapter = __library.get(b"WintunCreateAdapter\0").map(|sym| *sym)?;
|
||||||
|
let WintunCloseAdapter = __library.get(b"WintunCloseAdapter\0").map(|sym| *sym)?;
|
||||||
|
let WintunOpenAdapter = __library.get(b"WintunOpenAdapter\0").map(|sym| *sym)?;
|
||||||
|
let WintunGetAdapterLUID = __library.get(b"WintunGetAdapterLUID\0").map(|sym| *sym)?;
|
||||||
|
let WintunGetRunningDriverVersion = __library
|
||||||
|
.get(b"WintunGetRunningDriverVersion\0")
|
||||||
|
.map(|sym| *sym)?;
|
||||||
|
let WintunDeleteDriver = __library.get(b"WintunDeleteDriver\0").map(|sym| *sym)?;
|
||||||
|
let WintunSetLogger = __library.get(b"WintunSetLogger\0").map(|sym| *sym)?;
|
||||||
|
let WintunStartSession = __library.get(b"WintunStartSession\0").map(|sym| *sym)?;
|
||||||
|
let WintunEndSession = __library.get(b"WintunEndSession\0").map(|sym| *sym)?;
|
||||||
|
let WintunGetReadWaitEvent = __library.get(b"WintunGetReadWaitEvent\0").map(|sym| *sym)?;
|
||||||
|
let WintunReceivePacket = __library.get(b"WintunReceivePacket\0").map(|sym| *sym)?;
|
||||||
|
let WintunReleaseReceivePacket = __library
|
||||||
|
.get(b"WintunReleaseReceivePacket\0")
|
||||||
|
.map(|sym| *sym)?;
|
||||||
|
let WintunAllocateSendPacket = __library
|
||||||
|
.get(b"WintunAllocateSendPacket\0")
|
||||||
|
.map(|sym| *sym)?;
|
||||||
|
let WintunSendPacket = __library.get(b"WintunSendPacket\0").map(|sym| *sym)?;
|
||||||
|
Ok(wintun {
|
||||||
|
__library,
|
||||||
|
WintunCreateAdapter,
|
||||||
|
WintunCloseAdapter,
|
||||||
|
WintunOpenAdapter,
|
||||||
|
WintunGetAdapterLUID,
|
||||||
|
WintunGetRunningDriverVersion,
|
||||||
|
WintunDeleteDriver,
|
||||||
|
WintunSetLogger,
|
||||||
|
WintunStartSession,
|
||||||
|
WintunEndSession,
|
||||||
|
WintunGetReadWaitEvent,
|
||||||
|
WintunReceivePacket,
|
||||||
|
WintunReleaseReceivePacket,
|
||||||
|
WintunAllocateSendPacket,
|
||||||
|
WintunSendPacket,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
pub unsafe fn WintunCreateAdapter(
|
||||||
|
&self,
|
||||||
|
arg1: LPCWSTR,
|
||||||
|
arg2: LPCWSTR,
|
||||||
|
arg3: *const GUID,
|
||||||
|
) -> WINTUN_ADAPTER_HANDLE {
|
||||||
|
(self.WintunCreateAdapter)(arg1, arg2, arg3)
|
||||||
|
}
|
||||||
|
pub unsafe fn WintunCloseAdapter(&self, arg1: WINTUN_ADAPTER_HANDLE) -> () {
|
||||||
|
(self.WintunCloseAdapter)(arg1)
|
||||||
|
}
|
||||||
|
pub unsafe fn WintunOpenAdapter(&self, arg1: LPCWSTR) -> WINTUN_ADAPTER_HANDLE {
|
||||||
|
(self.WintunOpenAdapter)(arg1)
|
||||||
|
}
|
||||||
|
pub unsafe fn WintunGetAdapterLUID(
|
||||||
|
&self,
|
||||||
|
arg1: WINTUN_ADAPTER_HANDLE,
|
||||||
|
arg2: *mut NET_LUID,
|
||||||
|
) -> () {
|
||||||
|
(self.WintunGetAdapterLUID)(arg1, arg2)
|
||||||
|
}
|
||||||
|
pub unsafe fn WintunGetRunningDriverVersion(&self) -> DWORD {
|
||||||
|
(self.WintunGetRunningDriverVersion)()
|
||||||
|
}
|
||||||
|
pub unsafe fn WintunDeleteDriver(&self) -> BOOL {
|
||||||
|
(self.WintunDeleteDriver)()
|
||||||
|
}
|
||||||
|
pub unsafe fn WintunSetLogger(&self, arg1: WINTUN_LOGGER_CALLBACK) -> () {
|
||||||
|
(self.WintunSetLogger)(arg1)
|
||||||
|
}
|
||||||
|
pub unsafe fn WintunStartSession(
|
||||||
|
&self,
|
||||||
|
arg1: WINTUN_ADAPTER_HANDLE,
|
||||||
|
arg2: DWORD,
|
||||||
|
) -> WINTUN_SESSION_HANDLE {
|
||||||
|
(self.WintunStartSession)(arg1, arg2)
|
||||||
|
}
|
||||||
|
pub unsafe fn WintunEndSession(&self, arg1: WINTUN_SESSION_HANDLE) -> () {
|
||||||
|
(self.WintunEndSession)(arg1)
|
||||||
|
}
|
||||||
|
pub unsafe fn WintunGetReadWaitEvent(&self, arg1: WINTUN_SESSION_HANDLE) -> HANDLE {
|
||||||
|
(self.WintunGetReadWaitEvent)(arg1)
|
||||||
|
}
|
||||||
|
pub unsafe fn WintunReceivePacket(
|
||||||
|
&self,
|
||||||
|
arg1: WINTUN_SESSION_HANDLE,
|
||||||
|
arg2: *mut DWORD,
|
||||||
|
) -> *mut BYTE {
|
||||||
|
(self.WintunReceivePacket)(arg1, arg2)
|
||||||
|
}
|
||||||
|
pub unsafe fn WintunReleaseReceivePacket(
|
||||||
|
&self,
|
||||||
|
arg1: WINTUN_SESSION_HANDLE,
|
||||||
|
arg2: *const BYTE,
|
||||||
|
) -> () {
|
||||||
|
(self.WintunReleaseReceivePacket)(arg1, arg2)
|
||||||
|
}
|
||||||
|
pub unsafe fn WintunAllocateSendPacket(
|
||||||
|
&self,
|
||||||
|
arg1: WINTUN_SESSION_HANDLE,
|
||||||
|
arg2: DWORD,
|
||||||
|
) -> *mut BYTE {
|
||||||
|
(self.WintunAllocateSendPacket)(arg1, arg2)
|
||||||
|
}
|
||||||
|
pub unsafe fn WintunSendPacket(&self, arg1: WINTUN_SESSION_HANDLE, arg2: *const BYTE) -> () {
|
||||||
|
(self.WintunSendPacket)(arg1, arg2)
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user