Rust网络隧道库wintun的使用,高性能Windows虚拟网卡驱动开发插件包

Rust网络隧道库wintun的使用,高性能Windows虚拟网卡驱动开发插件包

wintun是Wintun C库的安全Rust惯用绑定。该库的所有功能都使用纯Rust类型和函数进行包装,使使用感觉符合人体工程学。

使用说明

在代码中加载wintun.dll签名驱动文件,使用loadload_from_pathload_from_library方法。

然后调用Adapter::createAdapter::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));
    }
}

注意事项

  1. 需要管理员权限运行程序
  2. 需要将wintun.dll放在可访问路径或与可执行文件相同目录
  3. 适配器创建后会在网络连接中显示为新的网络接口
  4. 程序退出时应正确关闭适配器以避免资源泄漏

性能优化建议

  1. 使用大尺寸的环形缓冲区减少上下文切换
  2. 批量处理数据包提高吞吐量
  3. 在多核系统上使用多线程处理数据包

wintun为Windows平台上的高性能网络应用开发提供了强大支持,特别适合需要自定义网络协议栈的场景。

回到顶部