公众号关注 「奇妙的 Linux 世界」

设为「星标」,每天带你玩转 Linux !

前一段时间,一直在找寻 Windows 操作系统上的虚拟网卡接口,主要是为了搭建隧道使用。但是 Windows 操作系统不像 Linux 操作系统,它的代码不开源,导致这方面的资料很少,因此花费了较长时间来寻找相关实现框架,最终找到了两款开源项目的虚拟接口驱动:

  • Wireguard 项目的 Wintun 接口[1]

  • OpenVPN 的 Tap 接口[2]

这两个项目都是非常出名的搭建隧道的开源 V.P.N 项目。由于目前对 openVPN 项目不太了解,也没有适配 Tap 接口,因此这里重点介绍下 WinTun 接口。此接口实现我是非常非常的喜欢,喜欢到简直不要不要的。

1简介

说到 Wintun 项目,就不得不说到它的父亲:WireGuard 项目(以下简称 WG)。Github 传送门[3]

WG 项目作为开源 V.P.N 项目,不同于 OpenVPN, Openswan, Strongswan 等,它的实现非常简介,Linux 内核代码实现不到 4000 行。相对于上述的三个 “按行收费” 的项目(代码 10 万行起步),它简直是太简洁了。故而得到了众多好评,其中就包括 Linux 鼻祖:Linus Torvalds。他的评价如下:

Btw, on an unrelated issue: I see that Jason actually made the pull request to have wireguard included in the kernel.

Can I just once again state my love for it and hope it gets merged soon? Maybe the code isn’t perfect, but I’ve skimmed it, and compared to the horrors that are OpenVPN and IPSec, it’s a work of art.

Linus

简而言之就是:劳资稀罕你,要把你合入我的 Linux 项目中。因此 Linux 内核自 5.6 之后便自带 WG 隧道功能,配置非常的简单。通过几行代码便可以完成一个 WG 隧道:

$ ip link add dev wg0 type wireguard
$ ip address add dev wg0 10.0.0.1/24
$ wg set wg0 listen-port 51820 private-key ./private.key peer NIk5TyDpRDoU9tfIckTTXCsz1eht2aEmdN7l0Q31ow0= allowed-ips 10.0.0.2/32 endpoint 192.168.1.5:51820
$ ip link set dev wg0 up

配置非常简单。除此之外,还提供了 Windows 客户端,这也是此项目为何包含 Wintun 虚拟网络接口的原因。

客户端页面也是非常简洁,没有多余的东西 (客户端链接[4]):

客户端上隧道协商成功之后,会根据隧道名称建立一个虚拟网卡,隧道拆除后接口自动删除。由于我的隧道名称为 Tun-1,因此在 “控制版面” 的“网络连接”中出现了一个 Tun-1 的网络接口:

好了,下面开始介绍此虚拟网络接口。

2WinTun 虚拟网络接口

  • Github 传送门[5]

  • wintun 官网传送门[6]

常见的 windwos 的接口驱动开发[7]、安装比较复杂。常见的驱动安装包有:.inf 文件、.sys 文件、.cat 文件; 除此之外还涉及驱动程序签名,否则无法安装成功。尤其在开发调试阶段,每次都得签名,太磨叽了。

但是 WinTun 接口用法非常简单高效非常简单高效非常简单高效

  1. 引入头文件:wintun.h

  2. 加载动态库,解析动态库中的函数指针

它通过动态库中方式来提供接口,我们可以加载此动态库,然后调用动态库中的函数指针来完成虚拟接口的创建、销毁、收发数据包等工作。此外它提供了一个示例供大家学习[8],我便是通过参考开源代码中的示例(example.c),将 Wintun 接口移植到我的工程之中。非常简单,我太喜欢它了。

实例代码就 400 行,其中大部分为 log 信息,供大家查看程序运行状态和报文收发信息。

加载动态库中的函数指针

此函数的作用:

  • 加载动态库,获取到动态库中的函数指针,后面通过函数指针来操作虚拟网卡接口。

static HMODULE
InitializeWintun(void)
{HMODULE Wintun =LoadLibraryExW(L"wintun.dll", NULL, LOAD_LIBRARY_SEARCH_APPLICATION_DIR | LOAD_LIBRARY_SEARCH_SYSTEM32);if (!Wintun)return NULL;
#define X(Name, Type) ((Name = (Type)GetProcAddress(Wintun, #Name)) == NULL)if (X(WintunCreateAdapter, WINTUN_CREATE_ADAPTER_FUNC) || X(WintunDeleteAdapter, WINTUN_DELETE_ADAPTER_FUNC) ||X(WintunDeletePoolDriver, WINTUN_DELETE_POOL_DRIVER_FUNC) || X(WintunEnumAdapters, WINTUN_ENUM_ADAPTERS_FUNC) ||X(WintunFreeAdapter, WINTUN_FREE_ADAPTER_FUNC) || X(WintunOpenAdapter, WINTUN_OPEN_ADAPTER_FUNC) ||X(WintunGetAdapterLUID, WINTUN_GET_ADAPTER_LUID_FUNC) ||X(WintunGetAdapterName, WINTUN_GET_ADAPTER_NAME_FUNC) ||X(WintunSetAdapterName, WINTUN_SET_ADAPTER_NAME_FUNC) ||X(WintunGetRunningDriverVersion, WINTUN_GET_RUNNING_DRIVER_VERSION_FUNC) ||X(WintunSetLogger, WINTUN_SET_LOGGER_FUNC) || X(WintunStartSession, WINTUN_START_SESSION_FUNC) ||X(WintunEndSession, WINTUN_END_SESSION_FUNC) || X(WintunGetReadWaitEvent, WINTUN_GET_READ_WAIT_EVENT_FUNC) ||X(WintunReceivePacket, WINTUN_RECEIVE_PACKET_FUNC) ||X(WintunReleaseReceivePacket, WINTUN_RELEASE_RECEIVE_PACKET_FUNC) ||X(WintunAllocateSendPacket, WINTUN_ALLOCATE_SEND_PACKET_FUNC) || X(WintunSendPacket, WINTUN_SEND_PACKET_FUNC))
#undef X{DWORD LastError = GetLastError();FreeLibrary(Wintun);SetLastError(LastError);return NULL;}return Wintun;
}

main() 函数

作用:

  • 通过函数指针创建虚拟网卡

  • 创建虚拟网卡的收发线程

int
main(void)
{HMODULE Wintun = InitializeWintun();if (!Wintun)return LogError(L"Failed to initialize Wintun", GetLastError());WintunSetLogger(ConsoleLogger);Log(WINTUN_LOG_INFO, L"Wintun library loaded");WintunEnumAdapters(L"Example", PrintAdapter, 0);DWORD LastError;HaveQuit = FALSE;QuitEvent = CreateEventW(NULL, TRUE, FALSE, NULL);if (!QuitEvent){LastError = LogError(L"Failed to create event", GetLastError());goto cleanupWintun;}if (!SetConsoleCtrlHandler(CtrlHandler, TRUE)){LastError = LogError(L"Failed to set console handler", GetLastError());goto cleanupQuit;}GUID ExampleGuid = { 0xdeadbabe, 0xcafe, 0xbeef, { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef } };WINTUN_ADAPTER_HANDLE Adapter = WintunOpenAdapter(L"Example", L"Demo");if (!Adapter){Adapter = WintunCreateAdapter(L"Example", L"Demo", &ExampleGuid, NULL);if (!Adapter){LastError = GetLastError();LogError(L"Failed to create adapter", LastError);goto cleanupQuit;}}DWORD Version = WintunGetRunningDriverVersion();Log(WINTUN_LOG_INFO, L"Wintun v%u.%u loaded", (Version >> 16) & 0xff, (Version >> 0) & 0xff);MIB_UNICASTIPADDRESS_ROW AddressRow;InitializeUnicastIpAddressEntry(&AddressRow);WintunGetAdapterLUID(Adapter, &AddressRow.InterfaceLuid);AddressRow.Address.Ipv4.sin_family = AF_INET;AddressRow.Address.Ipv4.sin_addr.S_un.S_addr = htonl((10 << 24) | (6 << 16) | (7 << 8) | (7 << 0)); /* 10.6.7.7 */AddressRow.OnLinkPrefixLength = 24; /* This is a /24 network */LastError = CreateUnicastIpAddressEntry(&AddressRow);if (LastError != ERROR_SUCCESS && LastError != ERROR_OBJECT_ALREADY_EXISTS){LogError(L"Failed to set IP address", LastError);goto cleanupAdapter;}WINTUN_SESSION_HANDLE Session = WintunStartSession(Adapter, 0x400000);if (!Session){LastError = LogLastError(L"Failed to create adapter");goto cleanupAdapter;}Log(WINTUN_LOG_INFO, L"Launching threads and mangling packets...");HANDLE Workers[] = { CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ReceivePackets, (LPVOID)Session, 0, NULL),CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)SendPackets, (LPVOID)Session, 0, NULL) };if (!Workers[0] || !Workers[1]){LastError = LogError(L"Failed to create threads", GetLastError());goto cleanupWorkers;}WaitForMultipleObjectsEx(_countof(Workers), Workers, TRUE, INFINITE, TRUE);LastError = ERROR_SUCCESS;cleanupWorkers:HaveQuit = TRUE;SetEvent(QuitEvent);for (size_t i = 0; i < _countof(Workers); ++i){if (Workers[i]){WaitForSingleObject(Workers[i], INFINITE);CloseHandle(Workers[i]);}}WintunEndSession(Session);
cleanupAdapter:WintunDeleteAdapter(Adapter, FALSE, NULL);WintunFreeAdapter(Adapter);
cleanupQuit:SetConsoleCtrlHandler(CtrlHandler, FALSE);CloseHandle(QuitEvent);
cleanupWintun:FreeLibrary(Wintun);return LastError;
}

收发报文的接口操作也非常简单,但是与 windows 网络协议栈之间的关系仍需要继续摸索。

特别说明

Wintun 接口是严格意义上的 3 层逻辑接口。原文如下:

Wintun is a very simple and minimal TUN driver for the Windows kernel, which provides userspace programs with a simple network adapter for reading and writing packets. It is akin to Linux's /dev/net/tun and BSD's /dev/tun. Originally designed for use in WireGuard, Wintun is meant to be generally useful for a wide variety of layer 3 networking protocols and experiments. The driver is open source, so anybody can inspect and build it. Due to Microsoft's driver signing requirements, we provide precompiled and signed versions that may be distributed with your software. The goal of the project is to be as simple as possible, opting to do things in the most pure and straight-forward way provided by NDIS.

这里出现了一个小小的问题:Wireshark 上无法抓取此接口报文。如果想看封装后的报文信息,则需要单独记录日志而非抓包来完成。

导致这个问题原因没有找到,我认为是:wireshark 抓取的报文是二层报文 (一个完整的以太网帧),而 3 层逻辑接口上的报文尚未封装以太网帧,故无法抓取此接口。这只是个人猜测,根本原因不得而知。

好了,基本介绍完毕,重新表达下我对 WireGuard 和 WinTun 的态度:劳资稀罕你,very 喜欢。

原文链接:https://blog.csdn.net/s2603898260/article/details/117389372

脚注

[1]Wireguard 项目的 Wintun 接口: https://github.com/WireGuard

[2]OpenVPN 的 Tap 接口: https://github.com/Toney-Sun/openvpn

[3]Github 传送门: https://github.com/WireGuard

[4]客户端链接: https://www.wireguard.com/install/

[5]Github 传送门: https://github.com/Toney-Sun/wintun

[6]wintun 官网传送门: https://www.wintun.net/

[7]windwos 的接口驱动开发: https://docs.microsoft.com/zh-cn/windows-hardware/drivers/install/components-of-a-driver-package

[8]它提供了一个示例供大家学习: https://git.zx2c4.com/wintun/tree/example/example.c

本文转载自:「 云原生实验室]」,原文:https://tinyurl.com/y6mv2ym2 ,版权归原作者所有。欢迎投稿,投稿邮箱: editor@hi-linux.com。

你可能还喜欢

点击下方图片即可阅读

CentOS 之父创造的 Rocky Linux 8.4 正式版发布了!(内附镜像下载地址)

更多有趣的互联网新鲜事,关注「奇妙的互联网」视频号全了解!

Wintun:一款惊艳的 WireGuard 虚拟网卡接口驱动相关推荐

  1. 8款惊艳的名牌概念手机,让市面流行的Iphone黯然失色

    8款惊艳的名牌概念手机,让市面流行的Iphone黯然失色 [22P] 1. Windows 概念手机 设计师 Seunghan Song 的 Windows 概念手机设想了一种能从手机上看到你目前天气 ...

  2. html5 粒子动画效果制作,8款惊艳的HTML5粒子动画特效

    原标题:8款惊艳的HTML5粒子动画特效 HTML5确实非常强大,很多时候我们可以利用HTML5中的新技术实现非常炫酷的粒子动画效果,粒子动画在HTML5应用中也是比较消耗本地资源的,尤其是CPU,但 ...

  3. html5粒子效果,8款惊艳的HTML5粒子动画特效

    [导读] HTML5确实强大,很多时候我们可以利用HTML5中的新技术实现非常炫酷的粒子动画效果,粒子动画在HTML5应用中也是比较消耗本地资源的,尤其是CPU,但是有些HTML5粒子效果确实能给用户 ...

  4. 20款惊艳的矢量花纹素材

    20款惊艳的矢量花纹素材 1.三款时尚花卉花纹矢量图免费下载 查看内容>> 下载>> 2.光芒四射的金色花纹背景矢量图 查看内容>> 下载>> 3.怀旧 ...

  5. 一文盘点最近特别火的 10 款惊艳的 AI 工具(附项目代码)

    ‍‍2023可以称得上是脑洞大开的一年!人工智能的风口由‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍OpenAI的ChatGPT率先引爆. 今天,我们给大家推荐10款惊艳的AI工具,欢迎补充! ...

  6. 11款惊艳的HTML5粒子动画特效

    HTML5确实非常强大,很多时候我们可以利用HTML5中的新技术实现非常炫酷的粒子动画效果,粒子动画在HTML5应用中也是比较消耗本地资源的,尤其是CPU,但是有些HTML5粒子效果确实能给用户带来不 ...

  7. 『创意欣赏』60款惊艳的 iOS App 图标设计《第四季》

    每天都有大量的应用程序发布到 iOS App Store 上,在数量巨大的应用中想要引起用户的主要,首页的就是独特的图标设计.这篇文章收集了一组惊艳的 iPhone 和 iPad 应用程序图标,希望能 ...

  8. 3D虚拟数字人黎鹿惊艳亮相,虚拟数字人制作赋能数字文旅新形态

    7月6日至8日,以"海归携手自贸港 共享海南新未来"为主题的第九届年会暨海归创新创业海南自贸港峰会在三亚重点园区展馆举办,虚拟数字人黎鹿惊艳亮相,引爆全场.据悉,这是国内首个政府背 ...

  9. STM32MP157 | 虚拟网卡设备驱动

    一.网络设备驱动 1. 概念 网络设备是Linux的第三类标准设备,没有对应的设备文件,使用内部设备名访问.网络设备及其驱动属于整个TCP/IP协议层的一部分,实现遵循TCP/IP协议栈的要求. 网络 ...

最新文章

  1. 动态设置 GridView Web 服务器控件列宽
  2. Execution failed for task ':compileArmv7DebugJavaWithJavac' 解决办法
  3. Linux文件操作四剑客常用命令
  4. 艾媒咨询:泛娱乐「体验共享」报告发布,网易云信多个案例领衔
  5. Java的if判断对象为null时,null放在比较运算符的左边还是右边较好?
  6. springboot约定优于配置的体现
  7. mysql sql实现原理_Mysql的数据库原理
  8. C#常用42个操作类
  9. Silverlight 模拟Nano5 界面效果
  10. 数据结构以及相关排序
  11. easyui添加删除表格任意行(2)
  12. stm32CubeMx lwip + freeRTOS
  13. 舆情监控系统python开源_开源舆情监控系统
  14. php网站恶意注册表,突破封锁 解决注册表被恶意锁定的方法
  15. labview信号频域分析算法
  16. Pycharm中对代码进行注释和缩进
  17. 键盘分类 红黑青茶轴
  18. Python正则表达式匹配字符串中的数字
  19. 五大主流浏览器的内核,前端在IE浏览器中常见的兼容问题
  20. JAVA毕业设计国漫论坛网站计算机源码+lw文档+系统+调试部署+数据库

热门文章

  1. 18.1. Fabric2.2 区块链农产品溯源系统 - 多Peer部署(扩展)
  2. 数据结构之线性表 - Python实现
  3. 通过Charles获取看书神器API
  4. android获得SIM序号以及号码,获取sim卡序列号
  5. 量化交易系统-botvs
  6. php面包屑源码,ZBlogPHP面包屑导航的完整代码分享
  7. 《Android群英传》勘误
  8. 浅析RocketMQ-CommitLog异步刷盘
  9. 《唐诗三百首》数据源网络下载
  10. [HT/NHT/DQ]-三种基于EMD的瞬时频率计算方法的比较