Compare commits

..
26 Commits
Author SHA1 Message Date
lubeilin ed3c44d6cf 保存参数到配置文件 2023-05-07 19:05:15 +08:00
lubeilin 35ed7f7e45 支持tap网卡,优化tun网卡配置 2023-05-07 18:32:11 +08:00
lubeilin 068580e036 Merge remote-tracking branch 'upstream/main' 2023-05-07 13:34:28 +08:00
Droid-MAX ea61b06e58 Update rust.yml 2023-04-26 11:27:02 +08:00
Droid-MAX f260c26e4f Update rust.yml 2023-04-26 11:11:03 +08:00
lubeilin 9cea433a8b 修复不加日志启动失败的问题 2023-04-25 23:17:31 +08:00
Droid-MAX 38dce9c13b Keep log file names in the same format 2023-04-25 12:51:03 +08:00
lubeilin 04731f1ce5 解决部分linux CPU飙升问题 2023-04-24 23:11:10 +08:00
lubeilin 3ddcb629c0 修改版本 2023-04-23 18:45:35 +08:00
lubeilin 12bd058152 增加日志 2023-04-23 18:44:01 +08:00
lubeilin c9b1bf5a5e 完善错误提示 2023-04-23 17:41:16 +08:00
lubeilin 18df3c2c92 解决win7不能启动的问题 2023-04-23 15:54:15 +08:00
Droid-MAX c08b9cefe9 Update rust.yml 2023-04-22 19:31:50 +08:00
Droid-MAX 258a35740f Merge pull request #1 from lbl8603/main
Sync update from upstream repo
2023-04-20 10:09:15 +08:00
lubeilin 32cfe9a3a8 commit 2023-04-20 09:46:06 +08:00
lubeilin 930a4fcf29 Merge branch 'dev' 2023-04-20 09:45:12 +08:00
Droid-MAX 5a778d5fc3 fix build issue 2023-04-20 09:17:07 +08:00
Droid-MAX 1d64cfc930 Update rust.yml 2023-04-20 00:43:42 +08:00
Droid-MAX 3eab02bc68 rename output filename and remove unfinished part of code 2023-04-20 00:28:30 +08:00
Droid-MAX dcdd03b746 fix submodules init issue 2023-04-20 00:12:08 +08:00
Droid-MAX 51acb2da9b fix github action sytanx issue 2023-04-19 23:44:17 +08:00
Droid-MAX 0d2c107e20 add submodule init and change output filename 2023-04-19 23:34:09 +08:00
Droid-MAX 2089ba7997 use github action for multi targets cross-compilation 2023-04-19 23:04:30 +08:00
lubeilin 8a032f86d8 修复udp广播丢失的问题 2023-04-08 21:44:31 +08:00
lubeilin 5dcda4d088 增加线程名称 2023-03-30 12:09:12 +08:00
lubeilin 8d76214193 传递本地ip、修复延迟问题 2023-03-20 21:13:38 +08:00
59 changed files with 3469 additions and 728 deletions
+137
View File
@@ -0,0 +1,137 @@
name: Rust
on:
push:
pull_request:
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-musl # test in an alpine container on a mac
OS: ubuntu-latest
- TARGET: aarch64-unknown-linux-musl # tested on aws t4g.nano in alpine container
OS: ubuntu-latest
- TARGET: armv7-unknown-linux-musleabihf # raspberry pi 2-3-4, 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: x86_64-pc-windows-msvc # tested on a windows machine
OS: windows-latest
- TARGET: i686-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 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-musl]
linker = "aarch64-linux-gnu-gcc"
[target.armv7-unknown-linux-musleabihf]
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: softprops/action-gh-release@v1
with:
files: ./artifacts/*.tar.gz
+1 -1
View File
@@ -1,3 +1,3 @@
[submodule "switch/p2p_channel"]
path = switch/p2p_channel
url = git@github.com:lbl8603/p2p_channel.git
url = https://github.com/lbl8603/p2p_channel
+13 -1
View File
@@ -1,2 +1,14 @@
[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
+2
View File
@@ -42,6 +42,7 @@
2. ssh
<img width="506" alt="ssh" src="https://raw.githubusercontent.com/lbl8603/switch/dev/documents/img/ssh.jpg">
5. 帮助,使用-h命令查看
### 更多玩法
@@ -72,6 +73,7 @@
### 特性
- IP层数据转发
- tun虚拟网卡
- tap虚拟网卡
- NAT穿透
- 点对点穿透
- 服务端中继转发
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "switch-desktop"
version = "0.1.0"
version = "1.0.2"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+2 -5
View File
@@ -5,7 +5,7 @@ pub fn log_service_init() -> io::Result<()> {
log_init_("switch-service.log")
}
pub fn log_init() -> io::Result<()> {
log_init_("switch.log")
log_init_("switch-desktop.log")
}
pub fn log_init_(file_name:&str) -> io::Result<()> {
let home = SWITCH_HOME_PATH.lock().clone();
@@ -14,9 +14,6 @@ pub fn log_init_(file_name:&str) -> io::Result<()> {
} 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()
.target(log4rs::append::console::Target::Stderr)
.build();
@@ -47,4 +44,4 @@ pub fn log_init_(file_name:&str) -> io::Result<()> {
Err(_) => {}
}
Ok(())
}
}
+38 -5
View File
@@ -13,6 +13,7 @@ use crate::StartArgs;
pub mod log_config;
pub struct StartConfig {
pub tap: bool,
pub name: String,
pub token: String,
pub server: SocketAddr,
@@ -21,7 +22,20 @@ pub struct StartConfig {
}
pub fn default_config(start_args: StartArgs) -> Result<StartConfig, String> {
println!("========参数配置========");
let args_config = read_config();
let tap = start_args.tap.unwrap_or_else(|| {
if let Some(c) = &args_config {
c.tap
} else {
false
}
});
if tap {
println!("use tap");
} else {
println!("use tun");
}
if args_config.is_none() && start_args.token.is_none() {
return Err("找不到token(Token not found)".to_string());
}
@@ -32,6 +46,7 @@ pub fn default_config(start_args: StartArgs) -> Result<StartConfig, String> {
if token.len() > 64 {
return Err("token不能超过64字符(Token cannot exceed 64 characters)".to_string());
}
println!("token:{:?}", token);
let name = start_args.name.unwrap_or_else(|| {
if let Some(c) = &args_config {
if !c.name.is_empty() {
@@ -46,6 +61,7 @@ pub fn default_config(start_args: StartArgs) -> Result<StartConfig, String> {
} else {
name.to_string()
};
println!("name:{:?}", name);
let device_id = start_args.device_id.unwrap_or_else(|| {
if let Some(c) = &args_config {
if !c.device_id.is_empty() {
@@ -61,6 +77,7 @@ pub fn default_config(start_args: StartArgs) -> Result<StartConfig, 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 server = match start_args.server.unwrap_or_else(|| {
if let Some(c) = &args_config {
if !c.server.is_empty() {
@@ -80,6 +97,7 @@ pub fn default_config(start_args: StartArgs) -> Result<StartConfig, String> {
return Err(format!("中继服务器地址错误( Relay server address error) :{:?}", e));
}
};
println!("中继服务器:{:?}", server);
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() {
@@ -92,13 +110,16 @@ pub fn default_config(start_args: StartArgs) -> Result<StartConfig, String> {
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,
};
println!("========参数配置========");
Ok(base_config)
}
@@ -109,6 +130,8 @@ lazy_static! {
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct ArgsConfig {
#[serde(default = "default_tap")]
pub tap: bool,
#[serde(default = "default_version")]
pub version: String,
#[serde(default = "default_str")]
@@ -118,7 +141,7 @@ pub struct ArgsConfig {
pub command_port: Option<u16>,
#[serde(default = "default_str")]
pub server: String,
#[serde(default = "default_resource_vec")]
#[serde(default = "default_vec")]
pub nat_test_server: Vec<String>,
#[serde(default = "default_str")]
pub device_id: String,
@@ -126,6 +149,10 @@ pub struct ArgsConfig {
pub pid: u32,
}
fn default_tap() -> bool {
false
}
fn default_version() -> String {
"1.0".to_string()
}
@@ -134,7 +161,7 @@ fn default_str() -> String {
"".to_string()
}
fn default_resource_vec() -> Vec<String> {
fn default_vec() -> Vec<String> {
vec![]
}
@@ -143,19 +170,22 @@ fn default_pid() -> u32 {
}
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,
nat_test_server: &Vec<SocketAddr>, device_id: String, ) -> Self {
Self {
tap,
version: "1.0".to_string(),
token,
name,
command_port: None,
server,
nat_test_server,
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> {
let path = SWITCH_HOME_PATH.lock().clone().unwrap().join(".lock");
Ok(File::create(path)?)
@@ -240,6 +270,9 @@ pub fn read_config() -> Option<ArgsConfig> {
}
pub fn set_home(home: PathBuf) {
if !home.exists() {
std::fs::create_dir(&home).unwrap();
}
SWITCH_HOME_PATH.lock().replace(home);
}
+12 -6
View File
@@ -1,3 +1,5 @@
use std::thread;
use std::time::Duration;
use clap::{Parser, Subcommand};
use console::style;
@@ -58,7 +60,7 @@ enum Commands {
Status,
}
#[derive(Parser, Debug)]
#[derive(Parser, Debug,Default)]
pub struct StartArgs {
/// 不超过64个字符
/// 相同token的设备之间才能通信。
@@ -89,10 +91,13 @@ pub struct StartArgs {
#[cfg(any(unix))]
#[arg(long)]
off_command_server: bool,
/// 记录日志,输出在 home/.switch 目录下,长时间使用时不建议开启
/// Output the log in the "home/.switch" directory
/// 记录日志,输出在 home/.switch_desktop 目录下,长时间使用时不建议开启
/// Output the log in the "home/.switch_desktop" directory
#[arg(long)]
log: bool,
/// 使用tap网卡
#[arg(long)]
tap: Option<bool>,
}
#[cfg(target_os = "windows")]
@@ -127,7 +132,7 @@ fn main() {
windows::service::start();
return;
} else {
let home = dirs::home_dir().unwrap().join(".switch");
let home = dirs::home_dir().unwrap().join(".switch_desktop");
config::set_home(home);
let args = BaseArgs::parse();
if let Commands::Start(start_args) = &args.command {
@@ -141,7 +146,7 @@ fn main() {
#[cfg(any(target_os = "linux", target_os = "macos"))]
fn main() {
let home = dirs::home_dir().unwrap().join(".switch");
let home = dirs::home_dir().unwrap().join(".switch_desktop");
config::set_home(home);
let args = BaseArgs::parse();
if let Commands::Start(start_args) = &args.command {
@@ -155,7 +160,7 @@ fn main() {
pub fn console_listen(switch: &Switch) {
use console::Term;
let term = Term::stdout();
println!("{}", style("started").green());
println!("{}", style("启动成功 started").green());
let current_device = switch.current_device();
println!(
"当前虚拟ip(virtual ip): {:?}",
@@ -181,6 +186,7 @@ pub fn console_listen(switch: &Switch) {
if let Err(e) = switch.stop() {
println!("stop:{:?}", e);
}
thread::sleep(Duration::from_secs(2));
break;
}
}
+9 -5
View File
@@ -24,18 +24,19 @@ pub fn main0(base_args: BaseArgs) {
}
let config = Config::new(
start_config.tap,
start_config.token.clone(),
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.tap,
start_config.token.clone(),
start_config.name.clone(),
start_config.server.to_string(),
nat_test_server,
start_config.server,
&start_config.nat_test_server,
start_config.device_id.clone(),
);
let lock = match config::lock_file() {
@@ -44,6 +45,7 @@ pub fn main0(base_args: BaseArgs) {
}
Err(e) => {
log::error!("{:?}",e);
println!("文件锁定失败:{:?}", e);
return;
}
};
@@ -62,6 +64,7 @@ pub fn main0(base_args: BaseArgs) {
}
Err(e) => {
log::error!("{:?}", e);
println!("启动switch失败:{:?}", e);
lock.unlock().unwrap();
return;
}
@@ -76,11 +79,11 @@ pub fn main0(base_args: BaseArgs) {
log::error!("{:?}", e);
}
let switch1 = switch.clone();
let handle = std::thread::spawn(move || {
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);
@@ -91,6 +94,7 @@ pub fn main0(base_args: BaseArgs) {
lock.unlock().unwrap();
}
Err(e) => {
println!("{}", style(&e).red());
log::error!("{:?}", e);
}
}
+17 -12
View File
@@ -65,19 +65,20 @@ pub fn main0(base_args: BaseArgs) {
let out_log = args.log;
match config::default_config(args) {
Ok(start_config) => {
if let Err(e) = config::save_config(config::ArgsConfig::new(start_config.tap,
start_config.token.clone(),
start_config.name.clone(),
start_config.server,
&start_config.nat_test_server,
start_config.device_id.clone(),
)) {
println!("{}", style(&e).red());
log::error!("{:?}",e);
return;
}
match service_state() {
Ok(state) => {
if state == ServiceState::Stopped {
if let Err(e) = config::save_config(config::ArgsConfig::new(
start_config.token.clone(),
start_config.name.clone(),
start_config.server.to_string(),
start_config.nat_test_server.iter().map(|v| v.to_string()).collect::<Vec<String>>(),
start_config.device_id.clone(),
)) {
log::error!("{:?}",e);
return;
}
match start(out_log) {
Ok(_) => {
//需要检查启动状态
@@ -103,6 +104,7 @@ pub fn main0(base_args: BaseArgs) {
style("服务未安装,在当前进程启动(The service is not installed and started in the current process)").red()
);
let config = Config::new(
start_config.tap,
start_config.token,
start_config.device_id,
start_config.name,
@@ -114,7 +116,8 @@ pub fn main0(base_args: BaseArgs) {
lock
}
Err(e) => {
log::error!("{:?}",e);
log::error!("文件锁定失败:{:?}",e);
println!("文件锁定失败:{:?}", e);
return;
}
};
@@ -128,6 +131,7 @@ pub fn main0(base_args: BaseArgs) {
}
Err(e) => {
log::error!("{:?}", e);
println!("启动switch失败:{:?}", e);
}
}
lock.unlock().unwrap();
@@ -142,7 +146,8 @@ pub fn main0(base_args: BaseArgs) {
}
}
Err(e) => {
println!("{}", style(e).red());
println!("{}", style(&e).red());
log::error!("{:?}", e);
}
};
pause();
+27 -42
View File
@@ -2,7 +2,6 @@
// extern crate windows_service;
use std::ffi::OsString;
use std::net::ToSocketAddrs;
use std::sync::Arc;
use std::thread;
use std::time::Duration;
@@ -15,8 +14,7 @@ use windows_service::service_control_handler::ServiceControlHandlerResult;
use switch::core::{Config, Switch};
use crate::config;
use crate::windows::config::read_config;
use crate::{config, StartArgs};
use crate::windows::SERVICE_NAME;
define_windows_service!(ffi_service_main, switch_service_main);
@@ -93,47 +91,34 @@ fn service_main() -> windows_service::Result<()> {
}
fn start_switch() -> switch::Result<Arc<Switch>> {
if let Some(config) = read_config() {
let device_id = config.device_id;
if device_id.trim().is_empty() {
return Err(switch::error::Error::Stop("Device id error".to_string()));
match config::default_config(StartArgs::default()) {
Ok(start_config) => {
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,
);
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)
}
let server_address = if let Some(server_address) = config.server
.to_socket_addrs()?
.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()));
Err(e) => {
return Err(switch::error::Error::Stop(e));
}
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()))
}
}
-13
View File
@@ -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"
-267
View File
@@ -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())
}
+3 -2
View File
@@ -1,6 +1,6 @@
[package]
name = "switch"
version = "0.1.0"
version = "1.0.2"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
@@ -27,6 +27,7 @@ chrono = "0.4.23"
#moka = "0.9.6"
protobuf = "3.2.0"
#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.24.1", features = ["full"] }
@@ -34,7 +35,7 @@ protobuf = "3.2.0"
tun = { path = "./rust-tun" }
[target.'cfg(target_os = "windows")'.dependencies]
wintun = "0.2.1"
win-tun-tap = {path = "./win-tun-tap"}
libloading = "0.7.4"
[build-dependencies]
+123
View File
@@ -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响应,3RARP请求,4RARP响应
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响应,3RARP请求,4RARP响应
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()
}
}
+1
View File
@@ -0,0 +1 @@
pub mod arp;
+2
View File
@@ -0,0 +1,2 @@
pub mod packet;
pub mod protocol;
+78
View File
@@ -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()
}
}
+141
View File
@@ -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,
}
}
}
+4 -14
View File
@@ -1,7 +1,6 @@
use std::fmt;
use std::net::Ipv4Addr;
use byteorder::{BigEndian, ReadBytesExt};
use crate::cal_checksum;
use crate::error::*;
@@ -141,16 +140,12 @@ impl<B: AsRef<[u8]>> IpV4Packet<B> {
/// ip报总字节数
pub fn length(&self) -> u16 {
(&self.buffer.as_ref()[2..])
.read_u16::<BigEndian>()
.unwrap()
u16::from_be_bytes(self.buffer.as_ref()[2..4].try_into().unwrap())
}
/// 标识. ip报文在数据链路层可能会被拆分,同一报文的不同分组标识字段相同
pub fn id(&self) -> u16 {
(&self.buffer.as_ref()[4..])
.read_u16::<BigEndian>()
.unwrap()
u16::from_be_bytes(self.buffer.as_ref()[4..6].try_into().unwrap())
}
/// 标志 3位.
@@ -170,10 +165,7 @@ impl<B: AsRef<[u8]>> IpV4Packet<B> {
/// 以字节为单位,用于指明分段起始点相对于包头起始点的偏移量
/// 由于分段到达时可能错序,所以分段的偏移字段可以使接收者按照正确的顺序重组数据包
pub fn offset(&self) -> u16 {
(&self.buffer.as_ref()[6..])
.read_u16::<BigEndian>()
.unwrap()
& 0x1fff
u16::from_be_bytes(self.buffer.as_ref()[6..8].try_into().unwrap()) & 0x1fff
}
/// 生存时间.
@@ -189,9 +181,7 @@ impl<B: AsRef<[u8]>> IpV4Packet<B> {
/// 首部校验和
pub fn checksum(&self) -> u16 {
(&self.buffer.as_ref()[10..])
.read_u16::<BigEndian>()
.unwrap()
u16::from_be_bytes(self.buffer.as_ref()[10..12].try_into().unwrap())
}
/// 验证校验和
///
+2 -1
View File
@@ -8,7 +8,8 @@ pub mod icmp;
pub mod ip;
pub mod tcp;
pub mod udp;
pub mod ethernet;
pub mod arp;
// pub enum IpUpperLayer<B> {
// UDP(UdpPacket<B>),
// Unknown(B),
+11
View File
@@ -76,6 +76,17 @@ 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 update_checksum(&mut self) {
//先将校验和置0
self.set_checksum(0);
self.set_checksum(self.cal_checksum())
}
}
impl<B: AsRef<[u8]>> TcpPacket<B> {
/// 源端口
pub fn source_port(&self) -> u16 {
+1 -1
View File
@@ -11,7 +11,7 @@
// TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
//
// 0. You just DO WHAT THE FUCK YOU WANT TO.
#![cfg(unix)]
mod error;
pub use crate::error::*;
@@ -112,6 +112,11 @@ impl AsRawFd for Reader {
self.0.as_raw_fd()
}
}
impl AsRawFd for Writer {
fn as_raw_fd(&self) -> RawFd {
self.0.as_raw_fd()
}
}
//
// impl AsRawFd for Writer {
// fn as_raw_fd(&self) -> RawFd {
+49 -21
View File
@@ -7,15 +7,17 @@ use parking_lot::Mutex;
use p2p_channel::boot::Boot;
use p2p_channel::channel::{Channel, Route, RouteKey};
use p2p_channel::punch::NatInfo;
use crate::handle::{ConnectStatus, CurrentDeviceInfo, heartbeat_handler, PeerDeviceInfo, punch_handler, recv_handler, registration_handler, tun_handler};
use crate::handle::{ConnectStatus, CurrentDeviceInfo, heartbeat_handler, PeerDeviceInfo, punch_handler, recv_handler, registration_handler, tap_handler, tun_handler};
use crate::nat::NatTest;
use crate::tun_device;
use crate::tun_device::TunReader;
use crate::{tap_device, tun_device};
use crate::tap_device::TapWriter;
use crate::tun_device::TunWriter;
pub struct Switch {
name: String,
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
tun_reader: TunReader,
tun_writer: Option<TunWriter>,
tap_writer: Option<TapWriter>,
nat_channel: Channel<Ipv4Addr>,
/// 0. 机器纪元,每一次上线或者下线都会增1,用于感知网络中机器变化
/// 服务端和客户端的不一致,则服务端会推送新的设备列表
@@ -28,6 +30,7 @@ pub struct Switch {
impl Switch {
pub fn start(config: Config) -> crate::Result<Switch> {
log::info!("config:{:?}",config);
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 register = Arc::new(registration_handler::Register::new(channel.sender()?, config.server_address, config.token.clone(), config.device_id.clone(), config.name.clone()));
@@ -37,14 +40,40 @@ impl Switch {
let virtual_ip = Ipv4Addr::from(response.virtual_ip);
let virtual_gateway = Ipv4Addr::from(response.virtual_gateway);
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_port = channel.local_addr()?.port();
// 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);
// tun通道
let (tun_writer, tun_reader) = tun_device::create_tun(virtual_ip, virtual_netmask, virtual_gateway)?;
let (current_device, 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 = Arc::new(AtomicCell::new(CurrentDeviceInfo::new(virtual_ip, virtual_gateway, virtual_netmask,
config.server_address, mac)));
//tap数据处理
tap_handler::start(channel.sender()?, tap_reader.clone(), tap_writer.clone(), current_device.clone());
(current_device, 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)?;
let current_device = Arc::new(AtomicCell::new(CurrentDeviceInfo::new(virtual_ip, virtual_gateway, virtual_netmask, config.server_address, [0, 0, 0, 0, 0, 0])));
//tun数据接收处理
tun_handler::start(channel.sender()?, tun_reader.clone(), tun_writer.clone(), current_device.clone());
(current_device, Some(tun_writer), None)
};
//外部数据接收处理
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(), tap_writer.clone(), connect_status.clone(), peer_nat_info_map.clone());
recv_handler::start(channel_recv_handler);
// 定时心跳
heartbeat_handler::start_heartbeat(channel.sender()?, device_list.clone(), current_device.clone());
// 空闲检查
@@ -53,20 +82,12 @@ impl Switch {
punch_handler::start_cone(punch.try_clone()?, 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());
//tun数据接收处理
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()?);
}
log::info!("switch启动成功");
Ok(Switch {
name: config.name,
current_device,
tun_reader,
tun_writer,
tap_writer,
nat_channel: channel,
nat_test,
device_list,
@@ -108,7 +129,12 @@ impl Switch {
self.nat_channel.route_table()
}
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()?;
Ok(())
}
@@ -116,6 +142,7 @@ impl Switch {
#[derive(Clone, Debug)]
pub struct Config {
pub tap: bool,
pub token: String,
pub device_id: String,
pub name: String,
@@ -124,12 +151,13 @@ pub struct Config {
}
impl Config {
pub fn new(token: String,
pub fn new(tap: bool, token: String,
device_id: String,
name: String,
server_address: SocketAddr,
nat_test_server: Vec<SocketAddr>, ) -> Self {
Self {
tap,
token,
device_id,
name,
+59 -23
View File
@@ -1,48 +1,74 @@
use std::{io, thread};
use std::net::Ipv4Addr;
use std::sync::Arc;
use std::time::Duration;
use std::{io, thread};
use chrono::Local;
use crossbeam::atomic::AtomicCell;
use parking_lot::Mutex;
use rand::prelude::SliceRandom;
use p2p_channel::channel::Route;
use p2p_channel::channel::sender::Sender;
use p2p_channel::channel::Route;
use p2p_channel::idle::Idle;
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, NetPacket, Protocol, Version, MAX_TTL};
pub fn start_idle(idle: Idle<Ipv4Addr>, sender: Sender<Ipv4Addr>) {
thread::spawn(move || {
if let Err(e) = start_idle_(idle, sender) {
log::info!("空闲检测线程停止:{:?}",e);
}
});
thread::Builder::new()
.name("idle".into())
.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<()> {
loop {
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 {
sender.remove_route(&peer_ip);
}
}
}
pub fn start_heartbeat(sender: Sender<Ipv4Addr>, device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>, current_device: Arc<AtomicCell<CurrentDeviceInfo>>) {
thread::spawn(move || {
if let Err(e) = start_heartbeat_(sender, device_list, current_device) {
log::info!("空闲检测线程停止:{:?}",e);
}
});
pub fn start_heartbeat(
sender: Sender<Ipv4Addr>,
device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>,
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])?;
net_packet.set_version(Version::V1);
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();
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())?;
ping.set_time(current_time);
let epoch = { device_list.lock().0 };
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 peer_list = device_list.lock().1.clone();
for peer in peer_list {
set_now_time(&mut net_packet)?;
net_packet.first_set_ttl(MAX_TTL);
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);
//再随机发送到其他地址,看有没有客户端符合转发条件
@@ -78,6 +106,7 @@ fn start_heartbeat_(sender: Sender<Ipv4Addr>, device_list: Arc<Mutex<(u16, Vec<P
net_packet.first_set_ttl(2);
for (peer_ip, route) in route_list.iter() {
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());
num += 1;
}
@@ -88,15 +117,22 @@ fn start_heartbeat_(sender: Sender<Ipv4Addr>, device_list: Arc<Mutex<(u16, Vec<P
}
thread::sleep(Duration::from_millis(1));
}
set_now_time(&mut net_packet)?;
net_packet.set_destination(current_device.virtual_gateway());
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);
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
);
}
} else {
for (peer_ip, route) in sender.route_table().iter() {
set_now_time(&mut net_packet)?;
net_packet.set_destination(*peer_ip);
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));
}
@@ -105,4 +141,4 @@ fn start_heartbeat_(sender: Sender<Ipv4Addr>, device_list: Arc<Mutex<(u16, Vec<P
count += 1;
thread::sleep(Duration::from_millis(5000));
}
}
}
+6 -6
View File
@@ -1,10 +1,11 @@
use std::net::{Ipv4Addr, SocketAddr};
pub mod heartbeat_handler;
pub mod punch_handler;
pub mod registration_handler;
pub mod tun_handler;
pub mod tap_handler;
pub mod punch_handler;
pub mod recv_handler;
pub mod registration_handler;
/// 是否在一个网段
fn check_dest(dest: Ipv4Addr, virtual_netmask: Ipv4Addr, virtual_network: Ipv4Addr) -> bool {
@@ -70,6 +71,7 @@ pub struct CurrentDeviceInfo {
pub broadcast_address: Ipv4Addr,
//链接的服务器地址
pub connect_server: SocketAddr,
pub mac:[u8;6]
}
impl CurrentDeviceInfo {
@@ -78,6 +80,7 @@ impl CurrentDeviceInfo {
virtual_gateway: Ipv4Addr,
virtual_netmask: Ipv4Addr,
connect_server: SocketAddr,
mac:[u8;6],
) -> Self {
let broadcast_address = (!u32::from_be_bytes(virtual_netmask.octets()))
| u32::from_be_bytes(virtual_gateway.octets());
@@ -92,6 +95,7 @@ impl CurrentDeviceInfo {
virtual_network,
broadcast_address,
connect_server,
mac
}
}
#[inline]
@@ -103,7 +107,3 @@ impl CurrentDeviceInfo {
self.virtual_gateway
}
}
+67 -40
View File
@@ -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::nat::NatTest;
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>>) {
thread::spawn(move || {
if let Err(e) = start_(true, punch, current_device) {
log::warn!("锥形网络打洞处理线程停止 {:?}",e);
}
});
thread::Builder::new()
.name("punch-cone".into())
.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>>) {
thread::spawn(move || {
if let Err(e) = start_(false, punch, current_device) {
log::warn!("对称网络打洞处理线程停止 {:?}",e);
}
});
thread::Builder::new()
.name("punch-symmetric".into())
.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])?;
packet.set_version(Version::V1);
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_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) {
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>>) {
thread::spawn(move || {
if let Err(e) = start_punch_(nat_test, device_list, sender, current_device) {
log::warn!("对称网络打洞处理线程停止 {:?}",e);
}
});
pub fn start_punch(
nat_test: NatTest,
device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>,
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 {
if sender.is_close() {
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();
punch_reply.reply = false;
punch_reply.public_ip_list = nat_info.public_ips.iter().map(|i| {
match i {
IpAddr::V4(ip) => {
u32::from_be_bytes(ip.octets())
}
punch_reply.public_ip_list = nat_info
.public_ips
.iter()
.map(|i| match i {
IpAddr::V4(ip) => u32::from_be_bytes(ip.octets()),
IpAddr::V6(_) => {
panic!()
}
}
}).collect();
})
.collect();
punch_reply.public_port = nat_info.public_port as u32;
punch_reply.public_port_range = nat_info.public_port_range as u32;
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_payload(&bytes);
Ok(net_packet.into_buffer())
}
}
+67 -28
View File
@@ -10,6 +10,7 @@ use protobuf::Message;
use p2p_channel::channel::{Channel, Route, RouteKey};
use p2p_channel::punch::NatInfo;
use packet::ethernet;
use packet::icmp::{icmp, Kind};
use packet::ip::ipv4;
use packet::ip::ipv4::packet::IpV4Packet;
@@ -23,10 +24,11 @@ use crate::proto::message::{DeviceList, PunchInfo, PunchNatType, RegistrationRes
use crate::protocol::{control_packet, MAX_TTL, NetPacket, Protocol, service_packet, turn_packet, Version};
use crate::protocol::control_packet::ControlPacket;
use crate::protocol::error_packet::InErrorPacket;
use crate::tap_device::TapWriter;
use crate::tun_device::TunWriter;
pub fn start(mut handler: RecvHandler) {
thread::spawn(move || {
thread::Builder::new().name("udp-recv-handler".into()).spawn(move || {
let mut buf = [0; 4096];
loop {
match handler.channel.recv_from(&mut buf, None) {
@@ -48,7 +50,7 @@ pub fn start(mut handler: RecvHandler) {
}
}
}
});
}).unwrap();
}
pub struct RecvHandler {
@@ -57,7 +59,8 @@ pub struct RecvHandler {
device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>,
register: Arc<Register>,
nat_test: NatTest,
tun_writer: TunWriter,
tun_writer: Option<TunWriter>,
tap_writer: Option<TapWriter>,
connect_status: Arc<AtomicCell<ConnectStatus>>,
peer_nat_info_map: Arc<SkipMap<Ipv4Addr, NatInfo>>,
}
@@ -68,7 +71,8 @@ impl RecvHandler {
device_list: Arc<Mutex<(u16, Vec<PeerDeviceInfo>)>>,
register: Arc<Register>,
nat_test: NatTest,
tun_writer: TunWriter,
tun_writer: Option<TunWriter>,
tap_writer: Option<TapWriter>,
connect_status: Arc<AtomicCell<ConnectStatus>>,
peer_nat_info_map: Arc<SkipMap<Ipv4Addr, NatInfo>>,
) -> Self {
@@ -79,6 +83,7 @@ impl RecvHandler {
register,
nat_test,
tun_writer,
tap_writer,
connect_status,
peer_nat_info_map,
}
@@ -91,6 +96,7 @@ impl RecvHandler {
register: self.register.clone(),
nat_test: self.nat_test.clone(),
tun_writer: self.tun_writer.clone(),
tap_writer: self.tap_writer.clone(),
connect_status: self.connect_status.clone(),
peer_nat_info_map: self.peer_nat_info_map.clone(),
})
@@ -103,13 +109,15 @@ impl RecvHandler {
if net_packet.ttl() == 0 {
return Ok(());
}
net_packet.set_ttl(net_packet.ttl() - 1);
let source = net_packet.source();
let current_device = self.current_device.load();
if source == current_device.virtual_ip() {
return Ok(());
}
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) {
log::warn!("转发数据,源地址错误:{:?},当前网络:{:?},route_key:{:?}",source,current_device.virtual_network,route_key);
return Ok(());
@@ -121,7 +129,6 @@ impl RecvHandler {
let ttl = net_packet.ttl();
if ttl > 1 {
// 转发
net_packet.set_ttl(ttl - 1);
if let Some(route) = self.channel.route(&destination) {
if route.metric <= net_packet.ttl() {
self.channel.send_to_route(net_packet.buffer(), &route.route_key())?;
@@ -137,22 +144,38 @@ impl RecvHandler {
match net_packet.protocol() {
Protocol::Ipv4Turn => {
let mut ipv4 = IpV4Packet::new(net_packet.payload_mut())?;
if ipv4.protocol() == ipv4::protocol::Protocol::Icmp {
let mut icmp_packet = icmp::IcmpPacket::new(ipv4.payload_mut())?;
if icmp_packet.kind() == Kind::EchoRequest {
//开启ping
icmp_packet.set_kind(Kind::EchoReply);
icmp_packet.update_checksum();
ipv4.set_source_ip(destination);
ipv4.set_destination_ip(source);
ipv4.update_checksum();
net_packet.set_source(destination);
net_packet.set_destination(source);
self.channel.send_to_route(net_packet.buffer(), route_key)?;
return Ok(());
if ipv4.destination_ip() != destination {
//todo 外部数据转发
} else {
if ipv4.protocol() == ipv4::protocol::Protocol::Icmp {
let mut icmp_packet = icmp::IcmpPacket::new(ipv4.payload_mut())?;
if icmp_packet.kind() == Kind::EchoRequest {
//开启ping
icmp_packet.set_kind(Kind::EchoReply);
icmp_packet.update_checksum();
ipv4.set_source_ip(destination);
ipv4.set_destination_ip(source);
ipv4.update_checksum();
net_packet.set_source(destination);
net_packet.set_destination(source);
self.channel.send_to_route(net_packet.buffer(), route_key)?;
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(&current_device.mac);
ethernet_packet.set_protocol(ethernet::protocol::Protocol::Ipv4);
ethernet_packet.payload_mut().copy_from_slice(ipv4.buffer);
tap_writer.write(&ethernet_packet.buffer)?;
}
}
}
self.tun_writer.write(net_packet.payload())?;
}
Protocol::Service => {
self.service(current_device, source, net_packet, route_key)?;
@@ -194,9 +217,15 @@ impl RecvHandler {
let virtual_ip = Ipv4Addr::from(response.virtual_ip);
let virtual_gateway = Ipv4Addr::from(response.virtual_gateway);
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,
virtual_netmask, current_device.connect_server);
virtual_netmask, current_device.connect_server, current_device.mac);
if let Err(e) = self.current_device.compare_exchange(current_device, new_current_device) {
log::warn!("替换失败:{:?}",e);
}
@@ -254,11 +283,20 @@ impl RecvHandler {
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())? {
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_source(current_device.virtual_ip());
net_packet.set_destination(source);
net_packet.first_set_ttl(MAX_TTL);
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) => {
let current_time = Local::now().timestamp_millis() as u16;
@@ -330,18 +368,19 @@ impl RecvHandler {
let nat_info = self.nat_test.nat_info();
punch_reply.public_ip_list = nat_info.public_ips.iter().map(|i| {
match i {
IpAddr::V4(ip) => {
u32::from_be_bytes(ip.octets())
}
IpAddr::V6(_) => {
panic!()
}
IpAddr::V4(ip) => u32::from_be_bytes(ip.octets()),
IpAddr::V6(_) => 0
}
}).collect();
punch_reply.public_port = nat_info.public_port as u32;
punch_reply.public_port_range = nat_info.public_port_range as u32;
punch_reply.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 mut net_packet =
NetPacket::new(vec![0u8; 12 + bytes.len()])?;
+24 -26
View File
@@ -4,9 +4,9 @@ use std::sync::atomic::{AtomicI64, Ordering};
use std::time::Duration;
use chrono::Local;
use protobuf::Message;
use p2p_channel::channel::Channel;
use p2p_channel::channel::sender::Sender;
use p2p_channel::channel::Channel;
use protobuf::Message;
use crate::error::*;
use crate::proto::message::{RegistrationRequest, RegistrationResponse};
@@ -35,20 +35,14 @@ pub fn registration(
Protocol::Service => {
match service_packet::Protocol::from(net_packet.transport_protocol()) {
service_packet::Protocol::RegistrationResponse => {
let response =
RegistrationResponse::parse_from_bytes(net_packet.payload())?;
let response = RegistrationResponse::parse_from_bytes(net_packet.payload())?;
Ok(response)
}
_ => {
Err(Error::Warn(format!("数据错误:{:?}", net_packet)))
}
_ => Err(Error::Warn(format!("数据错误:{:?}", net_packet))),
}
}
Protocol::Error => {
match InErrorPacket::new(
net_packet.transport_protocol(),
net_packet.payload(),
) {
match InErrorPacket::new(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())),
@@ -61,9 +55,7 @@ pub fn registration(
Err(e) => Err(Error::Warn(format!("{:?}", e))),
}
}
_ => {
Err(Error::Warn(format!("数据错误:{:?}", net_packet)))
}
_ => Err(Error::Warn(format!("数据错误:{:?}", net_packet))),
};
}
@@ -99,11 +91,13 @@ pub struct Register {
}
impl Register {
pub fn new(sender: Sender<Ipv4Addr>,
server_address: SocketAddr,
token: String,
device_id: String,
name: String, ) -> Self {
pub fn new(
sender: Sender<Ipv4Addr>,
server_address: SocketAddr,
token: String,
device_id: String,
name: String,
) -> Self {
Self {
sender,
server_address,
@@ -117,18 +111,22 @@ impl Register {
let last = self.time.load(Ordering::Relaxed);
let new = Local::now().timestamp_millis();
if new - last < 1000
|| self.time
.compare_exchange(last, new, Ordering::Relaxed, Ordering::Relaxed)
.is_err()
|| self
.time
.compare_exchange(last, new, Ordering::Relaxed, Ordering::Relaxed)
.is_err()
{
//短时间不重复注册
return Ok(());
}
log::info!("重新连接");
let request_packet =
registration_request_packet(self.token.clone(),
self.device_id.clone(),
self.name.clone(), false).unwrap();
let request_packet = registration_request_packet(
self.token.clone(),
self.device_id.clone(),
self.name.clone(),
false,
)
.unwrap();
let buf = request_packet.buffer();
self.sender.send_to_addr(buf, self.server_address)?;
Ok(())
+112
View File
@@ -0,0 +1,112 @@
use std::net::Ipv4Addr;
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::handle::{check_dest, CurrentDeviceInfo};
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>>, ) {
thread::Builder::new().name("tap-handler".into()).spawn(move || {
if let Err(e) = start_(sender, tap_reader, tap_writer, current_device) {
log::warn!("{:?}",e);
}
}).unwrap();
}
fn start_(sender: Sender<Ipv4Addr>,
tap_reader: TapReader,
tap_writer: TapWriter,
current_device: Arc<AtomicCell<CurrentDeviceInfo>>, ) -> 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, &current_device, &tap_writer, &mut ethernet_packet, &sender) {
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>) -> io::Result<()> {
let current_device = current_device.load();
match ethernet_packet.protocol() {
ethernet::protocol::Protocol::Arp => {
let mut out_ethernet_packet = 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 dest_ip = ipv4_packet.destination_ip();
if src_ip != current_device.virtual_ip() || (!check_dest(dest_ip, current_device.virtual_netmask, current_device.virtual_network) && !dest_ip.is_broadcast()) {
return Ok(());
}
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)?;
}
}
p => {
log::warn!("不支持的二层协议:{:?}",p)
}
}
Ok(())
}
+10 -10
View File
@@ -1,7 +1,7 @@
use std::{io, thread};
/// 接收tun数据,并且转发到udp上
use std::net::Ipv4Addr;
use std::sync::Arc;
use crossbeam::atomic::AtomicCell;
use p2p_channel::channel::sender::Sender;
@@ -15,7 +15,6 @@ use crate::handle::{check_dest, CurrentDeviceInfo};
use crate::protocol::{MAX_TTL, NetPacket, Protocol, Version};
use crate::tun_device::{TunReader, TunWriter};
fn icmp(tun_writer: &TunWriter, mut ipv4_packet: IpV4Packet<&mut [u8]>) -> Result<()> {
if ipv4_packet.protocol() == ipv4::protocol::Protocol::Icmp {
let mut icmp = IcmpPacket::new(ipv4_packet.payload_mut())?;
@@ -32,6 +31,7 @@ fn icmp(tun_writer: &TunWriter, mut ipv4_packet: IpV4Packet<&mut [u8]>) -> Resul
Ok(())
}
/// 接收tun数据,并且转发到udp上
#[inline]
fn handle(sender: &Sender<Ipv4Addr>, data: &mut [u8], tun_writer: &TunWriter, current_device: CurrentDeviceInfo, net_packet: &mut NetPacket<Vec<u8>>) -> Result<()> {
let data_len = data.len();
@@ -49,7 +49,7 @@ fn handle(sender: &Sender<Ipv4Addr>, data: &mut [u8], tun_writer: &TunWriter, cu
// // 137端口是在局域网中提供计算机的名字或IP地址查询服务
// 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() || (!check_dest(dest_ip, current_device.virtual_netmask, current_device.virtual_network) && !dest_ip.is_broadcast()) {
return Ok(());
}
if src_ip == dest_ip {
@@ -68,19 +68,19 @@ fn handle(sender: &Sender<Ipv4Addr>, data: &mut [u8], tun_writer: &TunWriter, cu
pub fn start(sender: Sender<Ipv4Addr>,
tun_reader: TunReader,
tun_writer: TunWriter,
current_device: Arc<AtomicCell<CurrentDeviceInfo>>, ) {
thread::spawn(move || {
current_device: Arc<AtomicCell<CurrentDeviceInfo>>) {
thread::Builder::new().name("tun-handler".into()).spawn(move || {
if let Err(e) = start_(sender, tun_reader, tun_writer, current_device) {
log::warn!("{:?}",e);
}
});
}).unwrap();
}
#[cfg(target_os = "windows")]
fn start_(sender: Sender<Ipv4Addr>,
tun_reader: TunReader,
tun_writer: TunWriter,
current_device: Arc<AtomicCell<CurrentDeviceInfo>>, ) -> io::Result<()> {
current_device: Arc<AtomicCell<CurrentDeviceInfo>>) -> io::Result<()> {
let mut net_packet = NetPacket::new(vec![0u8; 4 + 8 + 1500])?;
net_packet.set_version(Version::V1);
net_packet.set_protocol(Protocol::Ipv4Turn);
@@ -97,7 +97,7 @@ 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>,
tun_reader: TunReader,
tun_writer: TunWriter,
@@ -109,8 +109,8 @@ fn start_(sender: Sender<Ipv4Addr>,
net_packet.set_ttl(MAX_TTL);
let mut buf = [0; 4096];
loop {
let data = tun_reader.read(&mut buf)?;
match handle(&sender, data, &tun_writer, current_device.load(), &mut net_packet) {
let len = tun_reader.read(&mut buf)?;
match handle(&sender, &mut buf[..len], &tun_writer, current_device.load(), &mut net_packet) {
Ok(_) => {}
Err(e) => {
log::warn!("{:?}", e)
+1 -1
View File
@@ -1,6 +1,5 @@
use crate::error::Error;
pub use p2p_channel::channel::{Route, RouteKey};
pub type Result<T> = std::result::Result<T, Error>;
@@ -11,4 +10,5 @@ pub mod nat;
pub mod proto;
pub mod protocol;
pub mod tun_device;
pub mod tap_device;
pub mod core;
+1 -2
View File
@@ -1,9 +1,8 @@
use p2p_channel::punch::NatType;
use std::collections::HashSet;
use std::net::{IpAddr, Ipv4Addr, SocketAddr, UdpSocket};
use std::time::Duration;
use std::{io, thread};
use p2p_channel::punch::NatType;
// #[derive(Debug, Copy, Clone, PartialEq)]
// pub enum NatType {
+52 -18
View File
@@ -1,9 +1,9 @@
use crate::proto::message::PunchNatType;
use p2p_channel::punch::{NatInfo, NatType};
use parking_lot::Mutex;
use std::io;
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
use std::sync::Arc;
use parking_lot::Mutex;
use p2p_channel::punch::{NatInfo, NatType};
use crate::proto::message::PunchNatType;
pub mod check;
@@ -26,7 +26,7 @@ impl From<NatType> for PunchNatType {
fn from(value: NatType) -> Self {
match value {
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 {
match self {
PunchNatType::Symmetric => NatType::Symmetric,
PunchNatType::Cone => NatType::Cone
PunchNatType::Cone => NatType::Cone,
}
}
}
impl NatTest {
pub fn new(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);
pub fn new(
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 {
nat_test_server: Arc::new(nat_test_server),
info: Arc::new(Mutex::new(info)),
@@ -51,12 +63,30 @@ impl NatTest {
pub fn nat_info(&self) -> NatInfo {
self.info.lock().clone()
}
pub fn re_test(&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);
pub fn re_test(
&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();
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) {
Ok((nat_type, ips, port_range)) => {
let mut public_ips = Vec::new();
@@ -66,22 +96,26 @@ impl NatTest {
public_ips.push(IpAddr::from(ip));
}
}
NatInfo::new(public_ips,
public_port,
port_range,
local_ip, local_port,
nat_type, )
NatInfo::new(
public_ips,
public_port,
port_range,
local_ip,
local_port,
nat_type,
)
}
Err(e) => {
log::warn!("{:?}",e);
log::warn!("{:?}", e);
NatInfo::new(
vec![IpAddr::from(public_ip)],
public_port,
0,
local_ip, local_port,
local_ip,
local_port,
NatType::Cone,
)
}
};
}
}
}
+1 -2
View File
@@ -1,6 +1,5 @@
use std::{fmt, io};
#[derive(Eq, PartialEq, Copy, Clone, Debug)]
pub enum Protocol {
/// ping请求
@@ -107,4 +106,4 @@ impl<B: AsRef<[u8]>> fmt::Debug for PingPacket<B> {
.field("epoch", &self.epoch())
.finish()
}
}
}
+17 -14
View File
@@ -1,19 +1,19 @@
use std::{fmt, io};
use std::net::Ipv4Addr;
use std::{fmt, io};
/*
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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 版本(8) | 协议(8) | 上层协议(8) | 初始ttl(4) | 生存时间(4) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 源ip地址(32) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 目的ip地址(32) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 数据体 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 版本(8) | 协议(8) | 上层协议(8) | 初始ttl(4) | 生存时间(4) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 源ip地址(32) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 目的ip地址(32) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 数据体 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
pub mod control_packet;
pub mod error_packet;
@@ -98,7 +98,10 @@ impl<B: AsRef<[u8]>> NetPacket<B> {
let len = buffer.as_ref().len();
// 不能大于udp最大载荷长度
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 })
}
-2
View File
@@ -1,5 +1,3 @@
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
pub enum Protocol {
Punch,
+58
View File
@@ -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
))
}
+13
View File
@@ -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!()
}
+21
View File
@@ -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};
+100
View File
@@ -0,0 +1,100 @@
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_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();
}
+3
View File
@@ -9,6 +9,7 @@ pub fn create_tun(
netmask: Ipv4Addr,
gateway: Ipv4Addr,
) -> crate::error::Result<(TunWriter, TunReader)> {
println!("========TUN网卡配置========");
let mut config = tun::Configuration::default();
config
@@ -28,6 +29,8 @@ pub fn create_tun(
let queue = dev.queue(0).unwrap();
let reader = queue.reader();
let writer = queue.writer();
println!("name:{:?}", dev.name());
println!("========TUN网卡配置========");
Ok((
TunWriter(writer, packet_information, Arc::new(Mutex::new(dev))),
TunReader(reader, packet_information),
+4 -12
View File
@@ -12,6 +12,7 @@ pub fn create_tun(
netmask: Ipv4Addr,
gateway: Ipv4Addr,
) -> crate::error::Result<(TunWriter, TunReader)> {
println!("========TUN网卡配置========");
let mut config = tun::Configuration::default();
config
@@ -23,22 +24,13 @@ pub fn create_tun(
let dev = tun::create(&config).unwrap();
config_ip(dev.name(), address, netmask, gateway)?;
// println!("{:?}", if_config_out);
// let cmd_str: String = " ifconfig|grep flags=8051|awk -F ':' '{print $1}'|tail -1".to_string();
//
// let cmd_str_out = Command::new("sh")
// .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 queue = dev.queue(0).unwrap();
let reader = queue.reader();
let writer = queue.writer();
println!("name:{:?}", dev.name());
println!("========TUN网卡配置========");
Ok((
TunWriter(writer, packet_information, Arc::new(Mutex::new(dev))),
TunReader(reader, packet_information),
+2
View File
@@ -7,6 +7,8 @@ pub use unix::{TunReader, TunWriter};
#[cfg(target_os = "windows")]
pub use windows::create_tun;
#[cfg(target_os = "windows")]
pub use windows::delete_tun;
#[cfg(target_os = "windows")]
pub use windows::{TunReader, TunWriter};
#[cfg(any(target_os = "linux", target_os = "android"))]
+11 -15
View File
@@ -15,21 +15,8 @@ use parking_lot::Mutex;
pub struct TunReader(pub(crate) Reader, pub(crate) bool);
impl TunReader {
pub fn read<'a>(&'a self, buf: &'a mut [u8]) -> io::Result<&mut [u8]> {
let len = 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);
}
}
pub fn read(&self, buf: & mut [u8]) -> io::Result<usize> {
self.0.read(buf)
}
}
@@ -52,6 +39,15 @@ impl TunWriter {
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,
gateway: Ipv4Addr, _old_netmask: Ipv4Addr, _old_gateway: Ipv4Addr) -> io::Result<()> {
let mut config = tun::Configuration::default();
+93 -131
View File
@@ -4,49 +4,62 @@ use std::sync::Arc;
use libloading::Library;
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)]
pub struct TunWriter(Arc<Session>, Arc<Mutex<u32>>);
pub struct TunWriter(Arc<TunDevice>, Arc<Mutex<()>>);
impl TunWriter {
pub fn write(&self, buf: &[u8]) -> io::Result<()> {
match self.0.allocate_send_packet(buf.len() as u16) {
Ok(mut packet) => {
packet.bytes_mut().copy_from_slice(buf);
self.0.send_packet(packet);
return Ok(());
}
Err(_) => {}
}
return Err(io::Error::new(io::ErrorKind::Other, "send err"));
let mut packet = self.0.allocate_send_packet(buf.len() as u16)?;
packet.bytes_mut().copy_from_slice(buf);
self.0.send_packet(packet);
return Ok(());
}
pub fn change_ip(&self, address: Ipv4Addr, netmask: Ipv4Addr,
gateway: Ipv4Addr, old_netmask: Ipv4Addr, old_gateway: Ipv4Addr) -> io::Result<()> {
let index = self.1.lock();
if let Err(e) = delete_route(*index, old_netmask, old_gateway) {
log::warn!("{:?}",e);
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);
}
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)]
pub struct TunReader(pub(crate) Arc<Session>);
pub struct TunReader(Arc<TunDevice>);
impl TunReader {
pub fn next(&self) -> io::Result<Packet> {
match 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()
pub fn next(&self) -> io::Result<TunPacket> {
self.0.receive_blocking()
}
}
@@ -55,117 +68,66 @@ pub fn create_tun(
netmask: Ipv4Addr,
gateway: Ipv4Addr,
) -> io::Result<(TunWriter, TunReader)> {
let win_tun = unsafe {
unsafe {
println!("========TUN网卡配置========");
match Library::new("wintun.dll") {
Ok(library) => match wintun::load_from_library(library) {
Ok(win_tun) => win_tun,
Err(e) => {
return Err(io::Error::new(io::ErrorKind::Other, format!("{:?}", e)));
Ok(lib) => match TunDevice::open(lib, TUN_INTERFACE_NAME) {
Ok(tun_device) => {
let _ = tun_device.delete();
}
Err(_) => {}
},
Err(e) => {
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 adapter = match Adapter::open(&win_tun, "Switch-V1") {
Ok(a) => a,
Err(_) => match Adapter::create(&win_tun, "Switch-V1", "Switch-V1", None) {
Ok(adapter) => adapter,
Err(e) => return Err(io::Error::new(io::ErrorKind::Other, format!("{:?}", e))),
},
};
let index = adapter.get_adapter_index().unwrap();
config_ip(index, address, netmask, gateway)?;
let session = Arc::new(adapter.start_session(wintun::MAX_RING_CAPACITY).unwrap());
let reader_session = session.clone();
Ok((TunWriter(session.clone(), Arc::new(Mutex::new(index))), TunReader(reader_session)))
let tun_device = match TunDevice::create(
Library::new("wintun.dll").unwrap(),
TUN_POOL_NAME,
TUN_INTERFACE_NAME,
) {
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()?);
log::error!("创建tun成功 {:?}",tun_device.get_name()?);
tun_device.set_ip(address, netmask)?;
tun_device.set_mtu(1420)?;
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<()> {
let set_mtu = format!(
"netsh interface ipv4 set subinterface {} mtu=1420 store=persistent",
index
);
let set_metric = format!("netsh interface ip set interface {} metric=1", index);
let set_address = format!(
"netsh interface ip set address {} static {:?} {:?} ", // gateway={:?}
index, address, netmask,
);
// 执行网卡初始化命令
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)));
pub fn delete_tun() {
unsafe {
match Library::new("wintun.dll") {
Ok(lib) => match TunDevice::open(lib, TUN_INTERFACE_NAME) {
Ok(tun_device) => {
let _ = tun_device.delete();
}
Err(_) => {}
},
Err(_) => {}
}
}
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(())
}
+33
View File
@@ -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"
]
+534
View File
@@ -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(()),
}
}
+48
View File
@@ -0,0 +1,48 @@
#![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<()>;
}
+48
View File
@@ -0,0 +1,48 @@
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(())
}
+44
View File
@@ -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(())
}
+328
View File
@@ -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,
)
}
+173
View File
@@ -0,0 +1,173 @@
use std::{io, net, time};
use std::net::Ipv4Addr;
use winapi::shared::ifdef::NET_LUID;
use winapi::shared::minwindef::*;
use winapi::um::winioctl::*;
use winapi::um::winnt::HANDLE;
use crate::{decode_utf16, encode_utf16, ffi, IFace, netsh, route};
mod iface;
pub struct TapDevice {
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,
};
};
Ok(Self { 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)?;
Ok(Self { 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> {
ffi::luid_to_index(&self.luid).map(|index| index as u32)
}
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)
}
}
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);
}
}
+47
View File
@@ -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));
}
}
+301
View File
@@ -0,0 +1,301 @@
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 {
/// 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;
Ok(TunDevice {
session,
win_tun,
read_event,
shutdown_event,
adapter,
})
}
pub unsafe fn open<L>(library: L, 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)));
}
};
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"));
}
Self::init(win_tun, adapter)
}
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> {
let luid = self.get_adapter_luid();
ffi::luid_to_index(&unsafe { std::mem::transmute(luid) }).map(|index| index as u32)
}
fn get_name(&self) -> io::Result<String> {
let luid = self.get_adapter_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)
}
}
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()
};
}
}
+64
View File
@@ -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
}
}
}
}
+447
View File
@@ -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)
}
}