Rust网络隧道库wintun的使用,高性能Windows虚拟网卡驱动开发插件包
Rust网络隧道库wintun的使用,高性能Windows虚拟网卡驱动开发插件包
wintun是Wintun C库的安全Rust惯用绑定。该库的所有功能都使用纯Rust类型和函数进行包装,使使用感觉符合人体工程学。
使用说明
在代码中加载wintun.dll签名驱动文件,使用load
、load_from_path
或load_from_library
方法。
然后调用Adapter::create
或Adapter::open
获取wintun适配器。使用Adapter::start_session
开始会话。
示例代码
use std::sync::Arc;
//必须以管理员身份运行,因为我们要创建网络适配器
//加载wintun dll文件以便调用底层C函数
//不安全,因为我们加载的是任意dll文件
let wintun = unsafe { wintun::load_from_path("path/to/wintun.dll") }
.expect("Failed to load wintun dll");
//尝试打开名为"Demo"的适配器
let adapter = match wintun::Adapter::open(&wintun, "Demo") {
Ok(a) => a,
Err(_) => {
//如果加载失败(很可能不存在),则创建新的
wintun::Adapter::create(&wintun, "Demo", "Example", None)
.expect("Failed to create wintun adapter!")
}
};
//指定wintun驱动程序应使用的环形缓冲区大小
let session = Arc::new(adapter.start_session(wintun::MAX_RING_CAPACITY).unwrap());
//从环形缓冲区获取20字节的包
let mut packet = session.allocate_send_packet(20).unwrap();
let bytes: &mut [u8] = packet.bytes_mut();
//写入IPV4版本和头部长度
bytes[0] = 0x40;
//完成IP头部写入
bytes[9] = 0x69;
bytes[10] = 0x04;
bytes[11] = 0x20;
//...
//将包发送到wintun虚拟适配器进行系统处理
session.send_packet(packet);
//停止任何在其他线程上阻塞等待数据的读取器
//仅在阻塞读取器阻止关闭时需要,即它持有对会话的Arc引用,阻止其被丢弃
session.shutdown();
//会话在drop时停止
//drop(session);
//drop(adapter)
//适配器在丢弃时关闭其资源
完整示例
下面是一个更完整的示例,展示了如何创建虚拟网卡并处理网络数据包:
use std::{sync::Arc, time::Duration};
use wintun::Adapter;
fn main() {
// 加载wintun驱动
let wintun = unsafe { wintun::load_from_path("wintun/bin/wintun.dll") }
.expect("Failed to load wintun dll");
// 创建或打开适配器
let adapter = match Adapter::open(&wintun, "WintunRustDemo") {
Ok(adapter) => adapter,
Err(_) => {
Adapter::create(&wintun, "WintunRustDemo", "Wintun Rust Demo", None)
.expect("Failed to create adapter")
}
};
// 设置MTU并启动会话
adapter.set_adapter_mtu(1500).expect("Failed to set MTU");
let session = Arc::new(
adapter
.start_session(wintun::MAX_RING_CAPACITY)
.expect("Failed to start session"),
);
// 接收线程
let recv_session = session.clone();
std::thread::spawn(move || {
loop {
match recv_session.receive_blocking() {
Ok(packet) => {
let bytes = packet.bytes();
println!("Received packet with {} bytes", bytes.len());
// 处理包数据...
}
Err(e) => {
println!("Receive error: {}", e);
break;
}
}
}
});
// 发送线程
let send_session = session.clone();
std::thread::spawn(move || {
let mut counter = 0;
loop {
std::thread::sleep(Duration::from_secs(1));
// 分配发送包
let mut packet = match send_session.allocate_send_packet(20) {
Ok(p) => p,
Err(e) => {
println!("Allocate packet error: {}", e);
continue;
}
};
// 填充测试数据
let bytes = packet.bytes_mut();
bytes[0] = 0x45; // IP版本和头部长度
bytes[9] = 0x01; // 协议类型
bytes[10] = (counter >> 8) as u8;
bytes[11] = counter as u8;
counter += 1;
// 发送包
if let Err(e) = send_session.send_packet(packet) {
println!("Send packet error: {}", e);
}
}
});
// 等待用户输入退出
println!("Press Enter to exit...");
let mut input = String::new();
std::io::stdin().read_line(&mut input).unwrap();
// 关闭会话
session.shutdown();
}
特性
panic_on_unsent_packets
: 如果发送包被丢弃而没有发送,则panic。对于调试包问题很有用,因为未发送而被丢弃的包会占用wintun的内部环形缓冲区。
待办事项
- 添加异步支持 需要挂钩到Windows特定的反应器并在wintun的读取句柄上注册读取兴趣。通过tokio::spawn_blocking异步化其他慢操作。
许可证: MIT
1 回复
Rust网络隧道库wintun使用指南
概述
wintun是一个高性能的Windows虚拟网卡驱动开发插件包,专为Rust语言设计。它允许开发者在Windows系统上创建虚拟网络接口,用于构建VPN、代理、隧道等网络工具。
主要特性
- 高性能虚拟网络接口实现
- 原生Windows驱动支持
- 简单的Rust API接口
- 适合构建VPN、隧道等网络工具
安装方法
在Cargo.toml中添加依赖:
[dependencies]
wintun = "0.3"
基本使用方法
1. 创建虚拟网卡
use wintun::Adapter;
fn main() -> Result<(), Box<dyn std::error::Error>> {
// 加载wintun.dll
let wintun = unsafe { wintun::load_from_path("wintun.dll") }?;
// 创建适配器
let adapter = Adapter::create(
&wintun,
"MyTunnel", // 适配器名称
"MyTunnelType", // 隧道类型标识
None, // 请求的GUID (可选)
)?;
Ok(())
}
2. 配置IP地址
use std::net::Ipv4Addr;
// 继续上面的代码
adapter.set_ip_address(Ipv4Addr::new(10, 0, 0, 1), 24)?;
3. 接收和发送数据包
use wintun::Session;
// 创建会话
let session = Session::new(&adapter, 0x400000)?; // 4MB环形缓冲区
// 接收数据包
if let Some(packet) = session.receive_blocking() {
println!("Received packet of size: {}", packet.bytes().len());
// 处理数据包...
// 释放数据包
packet.free();
}
// 发送数据包
{
let mut packet = session.allocate_send_packet(1500)?;
let bytes = packet.bytes_mut();
// 填充数据包内容...
session.send_packet(packet);
}
高级用法
多线程处理
use std::sync::Arc;
use std::thread;
let session = Arc::new(session);
for i in 0..4 {
let session = Arc::clone(&session);
thread::spawn(move || {
loop {
if let Some(packet) = session.receive_blocking() {
// 处理数据包
packet.free();
}
}
});
}
设置MTU
adapter.set_mtu(1500)?;
完整示例代码
use wintun::{Adapter, Session};
use std::net::Ipv4Addr;
use std::sync::Arc;
use std::thread;
fn main() -> Result<(), Box<dyn std::error::Error>> {
// 1. 加载wintun.dll
let wintun = unsafe { wintun::load_from_path("wintun.dll") }?;
// 2. 创建虚拟网卡适配器
let adapter = Adapter::create(
&wintun,
"MyTunnel", // 适配器名称
"MyTunnelType", // 隧道类型标识
None // 请求的GUID (可选)
)?;
// 3. 配置IP地址
adapter.set_ip_address(Ipv4Addr::new(10, 0, 0, 1), 24)?;
// 4. 设置MTU
adapter.set_mtu(1500)?;
// 5. 创建会话(4MB环形缓冲区)
let session = Arc::new(Session::new(&adapter, 0x400000)?);
// 6. 多线程处理数据包
for _ in 0..4 {
let session = Arc::clone(&session);
thread::spawn(move || {
loop {
if let Some(packet) = session.receive_blocking() {
// 处理接收到的数据包
println!("Received packet of size: {}", packet.bytes().len());
// 示例:简单回显数据包
if let Ok(mut send_packet) = session.allocate_send_packet(packet.bytes().len()) {
send_packet.bytes_mut().copy_from_slice(packet.bytes());
session.send_packet(send_packet);
}
packet.free();
}
}
});
}
// 主线程等待
loop {
thread::sleep(std::time::Duration::from_secs(1));
}
}
注意事项
- 需要管理员权限运行程序
- 需要将wintun.dll放在可访问路径或与可执行文件相同目录
- 适配器创建后会在网络连接中显示为新的网络接口
- 程序退出时应正确关闭适配器以避免资源泄漏
性能优化建议
- 使用大尺寸的环形缓冲区减少上下文切换
- 批量处理数据包提高吞吐量
- 在多核系统上使用多线程处理数据包
wintun为Windows平台上的高性能网络应用开发提供了强大支持,特别适合需要自定义网络协议栈的场景。