基于 Boost.Asio 范式的用户态 TUN 虚拟网络引擎。引擎将 Linux TUN、macOS
utun 及 Windows Wintun 设备产生的 L3 原始 IP 包处理全面封装于内部,向上层
暴露一套完全对齐 Boost.Asio 网络编程范式的现代 C++ 异步接口,可无缝接入
C++20 协程(co_await),适用于 tun2socks、透明代理与轻量级 VPN 网关等
场景。
协议栈采用轻量级转发策略:接收方向维护乱序重排缓存并按序交付,动态
接收窗口(按剩余缓冲通告)避免对端超发;发送方向以最精简的 RTO 重传
(直接重读用户写缓冲,无重传队列)与零窗口持久探测保证写操作在丢包链路
上仍能完成,从而兼顾低 CPU 开销与基本可靠性。所有内部状态变更强制串行执行:
单线程模式(默认)直接运行于 io_context 执行器上,省去每包 Strand 派发
开销;多线程模式运行于单个 Strand 上,无锁竞争。构造时通过
tunio(io, single_thread) 选择。
- 双模设备管理:引擎自主创建并配置 TUN 设备,或接管外部应用已打开的 平台原生句柄(文件描述符 / HANDLE),便于提权前置、多实例共享设备。
- 完全 Asio 风格异步接口:所有公开 API 采用
CompletionToken与async_initiate实现,与use_awaitable、use_future及自定义 CompletionToken 无缝协作。 - TCP/UDP 对称抽象:TCP 提供
tun_tcp_socket/tun_tcp_acceptor,UDP 提供tun_udp_socket/tun_udp_acceptor,命名与行为习惯对齐 Boost.Asio, 降低学习成本。 - 极低协议开销:接收方向缓存乱序段并静默等待补齐,避免人为乱序触发 快速重传;发送方向仅以 RTO 计时器重读用户缓冲实现重传,无重传队列与拷贝。
- IPv4/IPv6 双栈:双栈报文解析与构造,内置 ICMP/ICMPv6 回显响应, 丢弃分片与扩展头报文。
- 生产级健壮性:资源上限(流数、队列字节数、总缓冲)、空闲超时与
半开连接清理、环路与本地地址防护,均可通过
tun_config或编译宏调整。 - 统计接口:
engine_stats原子计数,实时暴露收发包、丢弃、活动连接 与会话等指标。
| 平台 | 设备实现 | 说明 |
|---|---|---|
| Linux | TUN(posix::stream_descriptor) |
需 root 或 CAP_NET_ADMIN |
| macOS | utun | 需 root;自主打开经内核控制套接字(com.apple.net.utun_control)创建并配置 |
| Windows | TAP(overlapped I/O)或 Wintun | 自主打开支持 tap0901 等 TAP 驱动;编译时 USE_WINTUN_DRIVER 切换 Wintun |
- CMake 3.20+
- C++20 编译器
- Boost 1.81+(asio 头文件;代码使用
boost::unordered_flat_map与net::any_completion_handler,最低要求 1.81;作为第三方库被 superproject 引入时可复用其内置 Boost 目标) - Windows + Wintun 还需链接
iphlpapi、cfgmgr32、setupapi、ws2_32 - Windows + TAP 驱动需链接
ws2_32、iphlpapi(CMake 已自动处理)
cmake -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build -j
ctest --test-dir build --output-on-failure构建产物统一输出:可执行文件(示例与测试)位于 build/bin/,库位于
build/lib/。
常用选项:
TUNIO_BUILD_TESTS(默认ON):构建单元测试(基于 Boost.Test, header-only 模式,无需额外链接测试库)。TUNIO_BUILD_EXAMPLES(默认ON):构建示例程序。USE_WINTUN_DRIVER(默认OFF,仅 Windows):使用 Wintun 驱动。TUNIO_DISABLE_LOOPBACK_GUARD(默认OFF):关闭环路与本地地址防护 (定义编译宏TUNIO_DISABLE_LOOPBACK_GUARD效果相同)。TUNIO_BUILD_C(默认OFF):构建 C 绑定(bindings/c的tunio_cC API 共享库),不依赖 Python。TUNIO_BUILD_PYTHON(默认OFF):构建 Python 绑定(自动启用TUNIO_BUILD_C),共享库输出到bindings/python/tunio/供直接import tunio(见下文)。TUNIO_INSTALL(默认OFF):生成安装/导出规则(cmake --install、find_package(tunio)与 pkg-config);tunio 多以add_subdirectory方式 集成,需要对外安装发布时才开启。
仓库提供两层绑定接口:
- C 绑定(
bindings/c/):bindings/c/include/tunio/c_api.h只定义一套 句柄(tunio_engine*/tunio_tcp_conn*/tunio_udp_session*)与一套函数族, 阻塞调用与回调风格异步变体共享同一句柄,实现于bindings/c/src/c_api.cpp。 阻塞风格tunio_tcp_accept/recv/send、tunio_udp_accept/recvfrom/sendto在调用线程阻塞至完成,引擎内部维护io_context与 io 线程在后台推进协议 状态机,tunio_engine_close()会唤醒全部阻塞调用;同一引擎/连接/会话上 的tunio_tcp_async_*/tunio_udp_async_*变体以完成回调驱动:异步 accept 通过回调下发新连接/会话,读写回调内续发(单挂起读/写、零拷贝, 语义与 Boost.Asio 一致),回调在引擎串行执行器上串行派发,无操作级取消 与主动关闭事件。tunio_strerror()对两族通用。整个libtunio_c便于 C/其他语言集成。 - Python 绑定(
bindings/python/tunio/):基于上述 C API 的 ctypes 薄封装,无编译期绑定依赖,天然跟随解释器版本。模块直接暴露Engine/TcpSocket/UdpSocket,语义与 C++ 套接字一一对应。
构建并运行 Python 回显与 SOCKS5 代理示例:
cmake -B build -DTUNIO_BUILD_PYTHON=ON
cmake --build build -j
sudo python3 examples/python/tun_echo.py --tun tun0 \
--ip 10.0.0.1 --netmask 255.255.255.0
sudo python3 examples/python/tun2socks.py --tun tun0 \
--ip 10.0.0.1 --netmask 255.255.255.0 --proxy 127.0.0.1:1080libtunio_c 共享库输出到 bindings/python/tunio/ 包目录,源码树内可直接
import:
import tunio
engine = tunio.Engine() # threads 参数可开多 io 线程
engine.open(dev_name="tun0", ipv4_addr="10.0.0.1",
netmask="255.255.255.0")
try:
while True:
client = engine.accept_tcp() # 阻塞等待虚拟 TCP 连接
try:
data = client.recv(4096)
if data:
client.send(data) # 回显
finally:
client.close()
except tunio.Closed: # engine.close() 后 accept 退出
pass配置项与 tun_config 字段同名(mtu/num_queues/各超时项等),也支持
external_handle/external_handles 注入外部 TUN 句柄与 --inject-fd
等价用法。引擎 close() 后仍可再次 open()。
默认仅支持 add_subdirectory 集成;需要 cmake --install / find_package
时以 TUNIO_INSTALL=ON 配置并安装:
cmake -B build -DTUNIO_INSTALL=ON -DCMAKE_BUILD_TYPE=Release
cmake --build build -j
cmake --install build --prefix /usr/local随安装提供 tunioConfig.cmake 与版本文件(依赖 Boost 1.81+),消费方通过
导出的 tunio::tunio 目标使用:
find_package(tunio CONFIG REQUIRED)
target_link_libraries(app PRIVATE tunio::tunio)安装目录同时提供 tunio.pc,可用 pkg-config 获取编译与链接参数:
pkg-config --cflags --libs tunio安装包包含公开头内联依赖的实现头(include/tunio/detail/ 下的引擎、队列
写入器等,被 tun_tcp_socket_ops.hpp 等模板定义引用),消费方无需源码树
即可编译;CI 每次构建都会安装到临时前缀,并以 find_package 与
pkg-config 两条路径各编译一次消费方(tests/install/)做冒烟验证。
以下是一个完整的最小示例:打开 TUN 设备,将虚拟网内的 TCP 连接桥接到本机
回环端口的 echo 服务,并在引擎层直接回显 UDP 数据报。完整版本见
examples/cpp/tun_echo.cpp。
#include "tunio/tun_tcp_acceptor.hpp"
#include "tunio/tun_config.hpp"
#include "tunio/tun_tcp_socket.hpp"
#include "tunio/tun_udp_acceptor.hpp"
#include "tunio/tun_udp_socket.hpp"
#include "tunio/tunio.hpp"
#include <boost/asio.hpp>
#include <array>
#include <iostream>
#include <memory>
namespace net = boost::asio;
using tunio::tun_tcp_acceptor;
using tunio::tun_tcp_socket;
using tunio::tun_udp_acceptor;
using tunio::tun_udp_socket;
// ---- TCP 全双工桥接:虚拟连接 <-> 本机 echo 服务 ----
net::awaitable<void> bidirectional_bridge(tun_tcp_socket client,
net::ip::tcp::endpoint target)
{
auto ex = co_await net::this_coro::executor;
auto proxy = std::make_shared<net::ip::tcp::socket>(ex);
boost::system::error_code ec;
co_await proxy->async_connect(target,
net::redirect_error(net::use_awaitable, ec));
if (ec) {
client.reset(); // 后端不可达:立即向客户端发送 RST
co_return;
}
auto c = std::make_shared<tun_tcp_socket>(std::move(client));
net::co_spawn(
ex,
[c, proxy]() -> net::awaitable<void> {
std::array<char, 8192> buf;
try {
for (;;) {
size_t n = co_await c->async_read_some(net::buffer(buf),
net::use_awaitable);
co_await net::async_write(*proxy, net::buffer(buf, n),
net::use_awaitable);
}
} catch (...) {
}
boost::system::error_code sec;
proxy->shutdown(net::ip::tcp::socket::shutdown_send, sec);
},
net::detached);
net::co_spawn(
ex,
[c, proxy]() -> net::awaitable<void> {
std::array<char, 8192> buf;
try {
for (;;) {
size_t n = co_await proxy->async_read_some(
net::buffer(buf), net::use_awaitable);
co_await net::async_write(*c, net::buffer(buf, n),
net::use_awaitable);
}
} catch (...) {
c->close();
}
},
net::detached);
}
// ---- TCP 监听:每个虚拟连接派生一个桥接协程 ----
net::awaitable<void> tcp_listener(tunio::tunio &engine, uint16_t echo_port)
{
auto ex = co_await net::this_coro::executor;
tun_tcp_acceptor acceptor(engine);
for (;;) {
tun_tcp_socket client(ex);
boost::system::error_code ec;
co_await acceptor.async_accept(
client, net::redirect_error(net::use_awaitable, ec));
if (ec) {
co_return;
}
const auto dest = client.original_destination();
const net::ip::tcp::endpoint target =
dest.address().is_v6()
? net::ip::tcp::endpoint(net::ip::address_v6::loopback(),
echo_port)
: net::ip::tcp::endpoint(net::ip::address_v4::loopback(),
echo_port);
net::co_spawn(ex, bidirectional_bridge(std::move(client), target),
net::detached);
}
}
// ---- UDP 回显会话:一个虚拟客户端会话对应一个协程 ----
net::awaitable<void> udp_echo_handler(tun_udp_socket session)
{
std::array<char, 2048> buf;
try {
for (;;) {
net::ip::udp::endpoint sender;
size_t n = co_await session.async_receive_from(
net::buffer(buf), sender, net::use_awaitable);
co_await session.async_send_to(sender, net::buffer(buf, n),
net::use_awaitable);
}
} catch (...) {
session.close();
}
}
net::awaitable<void> udp_listener(tunio::tunio &engine)
{
auto ex = co_await net::this_coro::executor;
tun_udp_acceptor acceptor(engine);
for (;;) {
tun_udp_socket session(ex);
boost::system::error_code ec;
co_await acceptor.async_accept(
session, net::redirect_error(net::use_awaitable, ec));
if (ec) {
co_return;
}
net::co_spawn(ex, udp_echo_handler(std::move(session)), net::detached);
}
}
int main()
{
net::io_context io(1);
tunio::tunio engine(io);
tunio::tun_config cfg;
cfg.dev_name = "tun0";
cfg.ipv4_addr = "10.0.0.1";
cfg.netmask = "255.255.255.0";
cfg.mtu = 1500;
boost::system::error_code ec;
if (!engine.open(cfg, ec)) {
std::cerr << "open TUN failed: " << ec.message() << std::endl;
return 1;
}
net::co_spawn(io, tcp_listener(engine, 7), net::detached);
net::co_spawn(io, udp_listener(engine), net::detached);
io.run();
return 0;
}以 root 运行并配置路由后,虚拟网内客户端即可访问本机 echo 服务:
sudo ./build/bin/tun_echo --tun tun0 --ip 10.0.0.1 --netmask 255.255.255.0
sudo ip route add 10.0.0.0/24 dev tun0 # 或由外部路由/策略路由注入流量系统采用四层解耦架构:设备抽象层(tun_device)负责跨平台 TUN I/O;
协议引擎层(TCP/UDP Flow Engine)在引擎串行执行器上维护流表与 NAT;
异步 API 层向上层暴露四个套接字抽象;应用层通过协程实现业务逻辑。所有
内部状态变更均串行执行:单线程模式(默认)要求 io_context 单线程
run();多线程模式(tunio(io, false))使用 Strand,多线程 io_context
下无锁竞争。
应用层 (Proxy Logic / SOCKS5 Client)
| co_await / CompletionToken
异步 API 层
tun_tcp_socket / tun_tcp_acceptor tun_udp_socket / tun_udp_acceptor
协议引擎层
TCP Flow Engine UDP Flow Engine
Flow Dispatcher & NAT 表 (串行执行器)
设备抽象层
tun_device (Linux TUN / macOS utun / Windows Wintun)
└─ async_read_packet / async_write_packet (原始字节包)
└─ async_read_ip / async_write_ip (ip_packet 解析级接口)
| 类型 | 头文件 | 说明 |
|---|---|---|
tunio::tunio |
tunio/tunio.hpp |
引擎入口:打开/关闭设备、查询 MTU/本地 IP/统计 |
tunio::tun_config |
tunio/tun_config.hpp |
引擎配置:网络、句柄注入、资源上限、超时 |
tunio::engine_stats |
tunio/tun_config.hpp |
原子统计计数(收发包/丢弃/连接/会话/ICMP) |
tunio::tun_tcp_socket |
tunio/tun_tcp_socket.hpp |
虚拟 TCP 流,可读写、握手批准/拒绝、RST |
tunio::tun_tcp_acceptor |
tunio/tun_tcp_acceptor.hpp |
虚拟 TCP 监听器,SYN 到达时触发 accept |
tunio::tun_udp_socket |
tunio/tun_udp_socket.hpp |
虚拟 UDP 数据报会话,一次一报 |
tunio::tun_udp_acceptor |
tunio/tun_udp_acceptor.hpp |
新 UDP 会话监听器 |
tunio::tun_device |
tunio/tun_device.hpp |
跨平台设备抽象:自主打开/句柄注入,原始字节包与解析级 IP 包异步 I/O |
tunio::ip_packet |
tunio/ip_packet.hpp |
解析后的 IP 报文:IP 头信息 + TCP/UDP/ICMP 传输层视图 + 载荷;支持字段构造与校验和计算 |
explicit tunio(net::io_context &ctx, bool single_thread = true);
bool open(const tun_config &config, boost::system::error_code &ec);
void close();
bool is_open() const noexcept;
size_t mtu() const noexcept;
net::ip::address local_address() const noexcept;
const engine_stats &stats() const noexcept;
executor_type get_executor() const noexcept; // 引擎内部串行执行器open() 同步完成设备创建与配置;close() 停止数据通路并清理全部会话与
挂起操作;get_executor() 返回引擎内部串行执行器(单线程模式为 io 执行器,
多线程模式为 Strand),应用层可借其提交任务与引擎状态串行化。
四个套接字类型的行为与 Boost.Asio 对应类型对齐,全部异步操作均支持
CompletionToken(协程 co_await 或 net::use_future 等):
tun_tcp_socket:async_read_some/async_write_some/original_destination()/remote_endpoint()/accept()/reject()/reset()/shutdown()/close()/is_open()。tun_tcp_acceptor:async_accept(tun_tcp_socket &peer, token)/cancel()。tun_udp_socket:async_receive_from/async_send_to(remote, ...)/client_endpoint()/set_timeout()/close()/is_open()。tun_udp_acceptor:async_accept(tun_udp_socket &peer, token)/cancel()。
握手语义:收到客户端 SYN 后引擎不立即回复,由 accept()/reject()(或
首次读写隐式批准)决定握手结果;三次握手完成前的读写操作会缓冲,完成后
交付。TCP 转发为按序交付(乱序段经重排缓存补齐),超时与资源上限见
tun_config。
tun_device 可脱离引擎独立使用:打开真实 TUN 设备或注入外部句柄后,直接
读写 IP 报文。除原始字节包接口 async_read_packet / async_write_packet
外,还提供解析级接口 async_read_ip / async_write_ip,操作对象为
ip_packet —— 一次读取即得到一个完整解析的 IP 报文:
#include "tunio/tun_device.hpp"
#include "tunio/ip_packet.hpp"
tunio::tun_device dev(io);
boost::system::error_code ec;
if (!dev.open(cfg, ec)) { /* ... */ }
// 读:解析 IP 头 + 传输层(TCP/UDP/ICMP)视图 + 载荷,零拷贝
tunio::ip_packet pkt;
size_t n = co_await dev.async_read_ip(pkt, net::use_awaitable);
if (pkt.valid()) {
const net::ip::address src = pkt.source_address();
const net::ip::address dst = pkt.destination_address();
if (pkt.is_tcp()) {
uint16_t sport = pkt.source_port(); // 主机字节序
const auto *tcp = pkt.tcp(); // 原始 TCP 头视图
const uint8_t *data = pkt.transport_data();
} else if (pkt.is_udp()) {
// ...
} else if (pkt.is_icmp() && pkt.icmp_type() == 8) {
uint16_t id = pkt.icmp_echo_id();
}
}
// 写:从字段构造报文(自动计算长度与 IP/TCP/UDP/ICMP 校验和)后写出
tunio::ip_packet out;
out.begin_ipv4(src_v4, dst_v4);
out.begin_udp(12345, 53);
out.append_payload(data, len);
out.finalize();
co_await dev.async_write_ip(out, net::use_awaitable);行为约定:
async_read_ip完成签名为void(error_code, size_t),ec仅反映设备 I/O 错误;报文结构非法时ec为no_error,通过pkt.valid()/pkt.error()判断(解析失败原因含非法版本、报文过短、IHL/total_len 非法、 传输层头非法等)。- 解析只做结构校验,不验证校验和;IPv4 分片包解析并暴露
fragmented()/fragment_offset()(分片非首片不解析传输层视图); IPv6 扩展头不遍历,ip_protocol()返回原始扩展头号。 - 每个未完成的
async_read_ip需要独立的ip_packet对象(自持缓冲), 同一对象不可并发发起多次读取;packet_buffer默认容量 2048,大 MTU 场景构造ip_packet(dev.mtu() + 64)。 - macOS utun 的 4 字节家族前缀在平台实现层透明剥离/附加,
ip_packet始终看到纯 IP 报文。
| 字段 | 默认值 | 说明 |
|---|---|---|
dev_name / ipv4_addr / netmask |
空 / 空 | 自主打开模式下的设备名(默认空,Linux 内核自动命名)与 IPv4 配置 |
ipv6_addr / ipv6_prefix_len |
空 / 64 |
可选 IPv6 地址 |
mtu |
1500 |
自主打开模式 MTU |
num_queues |
1 |
Linux TUN 多队列数(IFF_MULTI_QUEUE,上限 256;其他平台忽略) |
external_handle / external_mtu |
invalid / 1500 |
外部句柄注入(优先于自主打开) |
external_handles |
空 | 多句柄注入:每元素一个队列 fd(非空时优先于 external_handle;仅 Linux TUN 多队列有意义) |
max_tcp_flows / max_udp_flows |
65536 |
流/会话数上限 |
max_rx_queue_per_flow |
8 MiB |
每流接收队列字节上限 |
max_total_buffer |
512 MiB |
全局缓冲上限 |
udp_idle_timeout |
30s |
UDP 会话空闲超时 |
tcp_time_wait_timeout / tcp_accept_timeout |
10s / 30s |
TCP 清理超时 |
tcp_syn_timeout / tcp_close_timeout |
30s / 30s |
半开/关闭流程超时 |
tcp_persist_timeout / tcp_persist_max_probes |
5s / 15 |
零窗口探测初始间隔与最大次数(超限以 RST 关闭连接) |
- 首次
open()必须在io_context开始运行(io.run())之前调用。 - 引擎必须在所有
tun_tcp_socket/tun_udp_socket销毁之后、且io_context停止运行(所有run()已返回、io 线程已 join)之后销毁。 若在 io 线程仍在执行完成回调时销毁引擎,引擎内部状态与在途异步操作将 与销毁线程并发访问(数据竞争),设备层读回调引用的内部缓冲也可能已 释放。运行期间需要关闭请调用close(),其内部在串行执行器上完成清理。 - 对已打开(或 close 后尚未完成异步清理)的引擎再次
open()时,io_context必须正在运行:open()会在串行执行器上同步收尾上一代实例,io_context未运行时该收尾任务无法执行,将导致调用线程阻塞等待。 - 运行期间需要重新
open()时,请通过get_executor()派发屏障任务, 确保与引擎内部任务串行。 - 所有异步操作完成回调在调用方绑定的执行器上触发;引擎内部状态由
串行执行器串行化。单线程模式要求
io_context单线程run();多线程 模式由 Strand 串行化,多线程运行io_context是安全的。 is_open()等同步状态查询仅在 io 线程(或与引擎串行执行器同步的 上下文)调用(与 Boost.Asio 对共享 socket 对象"并发访问不安全"的约定 一致);多线程模式下从任意线程调用会构成数据竞争。async_write_some/async_send_to的缓冲区必须保持有效至完成回调 触发(与 Boost.Asio 语义一致,引擎只引用不拷贝)。
Linux 下可通过 num_queues 以多队列模式打开 TUN 设备(内核 ≥ 2.6.30,
需 CAP_NET_ADMIN):每个队列一个独立 fd,内核按流哈希并行投递入站包,
引擎为每个队列分配并发读槽、出站包按五元组哈希分发到各队列 fd,读写
吞吐随队列数扩展(建议配合多线程 io_context 使用):
tunio::tun_config cfg;
cfg.dev_name = "tun0";
cfg.ipv4_addr = "10.0.0.1";
cfg.netmask = "255.255.255.0";
cfg.num_queues = 4; // 4 队列多队列模式
boost::system::error_code ec;
if (!engine.open(cfg, ec)) {
std::cerr << "open failed: " << ec.message() << std::endl;
return 1;
}
std::cout << "queues: " << engine.queue_count() << std::endl; // 4多队列也可以经 external_handles 注入外部已打开的队列 fd(每个句柄对应
一个队列,队列数 = 句柄数);非 Linux 平台忽略多队列配置,queue_count()
恒为 1。若内核不支持 IFF_MULTI_QUEUE(老内核),显式请求多队列打开会
失败并返回 EINVAL,不会静默降级。
需要特殊权限前置(如提前获取 CAP_NET_ADMIN)或接管外部已打开的设备时,
通过 external_handle 注入,此时必须显式指定 MTU:
int fd = open("/dev/net/tun", O_RDWR); // 外部已打开并配置好的 TUN fd
tunio::tun_config cfg;
cfg.external_handle = fd;
cfg.external_mtu = 1500;
boost::system::error_code ec;
if (!engine.open(cfg, ec)) {
std::cerr << "open failed: " << ec.message() << std::endl;
return 1;
}引擎内部全部状态由 Strand 串行化,可直接以线程池运行 io_context(每个
线程执行 io.run(),线程数即并发度):
net::io_context io(4);
tunio::tunio engine(io);
// ... open + 注册监听协程 ...
std::vector<std::thread> threads;
for (size_t i = 1; i < 4; ++i) {
threads.emplace_back([&io] { io.run(); });
}
io.run(); // 主线程也参与事件循环
for (auto &t : threads) {
t.join();
}示例源码按语言分目录存放:C++ 示例位于 examples/cpp/,C 示例位于
examples/c/(需开启 TUNIO_BUILD_C 或 TUNIO_BUILD_PYTHON),Python
示例位于 examples/python/。
| 程序 | 说明 |
|---|---|
tun_echo |
最小示例:TCP 桥接本机 echo 服务 + UDP 回显 |
tun2socks |
SOCKS5 透明代理:TCP CONNECT + UDP ASSOCIATE |
examples/python/tun_echo.py |
tun_echo 的 Python 绑定版本(ctypes 绑定) |
examples/python/tun2socks.py |
tun2socks 的 Python 绑定版本(纯 Python SOCKS5 客户端) |
examples/c/tun2socks.c |
tun2socks 的 C API 版本(阻塞接口 + pthread,构建产物 tun2socks_c) |
tun_packet |
原始 IP 包中继/打印:直接使用 tun_device + ip_packet,解析并打印 TCP/UDP/ICMP 协议详情,--echo 回环中继 |
benchmark |
异步接口每操作堆分配与吞吐基准(基于 socketpair 注入) |
Boost Software License 1.0,见 LICENSE_1_0.txt。