主页 > 互联网 > 内容页

Windows下基于MSVC搭建Wintun开发环境-环球速看料

2023-06-08 10:09:55 来源:嵌入式USB开发

本文转自公众号,欢迎关注

Windows下基于MSVC搭建Wintun开发环境 (qq.com)

前言

l有这么一种场景,某个windows下的应用程序底层数据接口基于以太网,现在想修改为串口,那么一般来说需要修改该应用程序,添加对串口的支持,但是很多时候应用程序可能是第三方开发的并不能修改,有没有在不修改应用程序的情况下实现兼容呢,


(相关资料图)

Wintun就提供了解决方案,Wintun可以创建虚拟网卡,提供IP层的数据链路,那么我们只需要使用Wintun创建虚拟网卡,将串口数据组包成指定协议层的包(UDP或者TCP/IP)等进行转发,那么该应用软件可以访问该虚拟网卡,无需任何修改。

由于wintun工作在IP层,所以需要根据实际情况去实现UDP或者TCP/IP等包的组包和解包。

l还有一种场景,我们希望在windows下进行嵌入式tcp/ip协议栈的源码级别开发测试,那么就可以使用Wintun来模拟IP层的数据链路,而不直接访问真实的MAC和PHY,基于此进行协议栈的开发调试,由于Wintun是IP层的,所以无法模拟数据链路层的部分,真实的场景是以太网控制器实现帧的收发,而Wintun的是更上一层基于IP包的收发,也就是从IP层截断了,所以不能进行ARP等数据链路层的协议的分析调试。

准备

官网

https://www.wintun.net/

下载代码

git clone https://git.zx2c4.com/wintun

下载编译好的库

https://www.wintun.net/builds/wintun-0.14.1.zip

编译库

参考 https:/ /git.zx2c4.com/wintun/about/#building

在自己的工程中使用

解压wintun-0.14.1.zip复制文件夹wintun到自己的工程目录

将下载的源码wintun\\example下的example.c复制到自己的工程中。

右键点击项目名->属性 设置相关属性,Window2和X86都同样设置。

设置头文件包含路径

$(MSBuildProjectDirectory)\\Src\\wintun\\include;

设置链接的库

iphlpapi.lib;kernel32.lib;ntdll.lib;ws2_32.lib;

设置输出路径

$(ProjectDir)$(Platform)\\$(Configuration)\\

切换X86和X64版本,都进行编译

点击项目名->重新生成构建。

将wintun\\bin\\amd64和wintun\\bin\\x86下的wintun.dll分别放入

工程的输出目录\\x64\\Debug和\\Win32\\Debug下

右键点击exe文件,以管理员身份运行(一定要管理员权限,否则出错)

控制面板,网络和共享中心,更改适配器设置,可以看到多了网卡Demo

命令行ipconfig可以看到

也可以ping通

基本API的使用

上面使用example进行了测试,为了熟悉API,可以自己写一个测试代码。

参考https://git.zx2c4.com/wintun/about/

加载库,解析函数地址

LoadLibraryExW

GetProcAddress

先定义14个API函数的指针,

static WINTUN_CREATE_ADAPTER_FUNC *WintunCreateAdapter;static WINTUN_CLOSE_ADAPTER_FUNC *WintunCloseAdapter;static WINTUN_OPEN_ADAPTER_FUNC *WintunOpenAdapter;static WINTUN_GET_ADAPTER_LUID_FUNC *WintunGetAdapterLUID;static WINTUN_GET_RUNNING_DRIVER_VERSION_FUNC *WintunGetRunningDriverVersion;static WINTUN_DELETE_DRIVER_FUNC *WintunDeleteDriver;static WINTUN_SET_LOGGER_FUNC *WintunSetLogger;static WINTUN_START_SESSION_FUNC *WintunStartSession;static WINTUN_END_SESSION_FUNC *WintunEndSession;static WINTUN_GET_READ_WAIT_EVENT_FUNC *WintunGetReadWaitEvent;static WINTUN_RECEIVE_PACKET_FUNC *WintunReceivePacket;static WINTUN_RELEASE_RECEIVE_PACKET_FUNC *WintunReleaseReceivePacket;static WINTUN_ALLOCATE_SEND_PACKET_FUNC *WintunAllocateSendPacket;static WINTUN_SEND_PACKET_FUNC *WintunSendPacket;

加载库

HMODULE Wintun = LoadLibraryExW(L"wintun.dll", NULL, LOAD_LIBRARY_SEARCH_APPLICATION_DIR | LOAD_LIBRARY_SEARCH_SYSTEM32);if (!Wintun){return -1;}

解析函数地址,其他13个API类似

if ((*(FARPROC*)&WintunCreateAdapter = GetProcAddress(Wintun, "WintunCreateAdapter")) == NULL){FreeLibrary(Wintun);return -2;}

以上为了方便理解分开了写,example.c中用宏的形式更简洁。

创建适配器

GUID ExampleGuid = { 0xdeadbabe, 0xcafe, 0xbeef, { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef } };WINTUN_ADAPTER_HANDLE Adapter = WintunCreateAdapter(L"Demo", L"Example", &ExampleGuid);if (!Adapter){FreeLibrary(Wintun);return -3;}

获取版本

DWORD Version = WintunGetRunningDriverVersion();printf("Wintun v%u.%u loaded", (Version > > 16) & 0xff, (Version > > 0) & 0xff);

启动会话

MIB_UNICASTIPADDRESS_ROW AddressRow;InitializeUnicastIpAddressEntry(&AddressRow);              /* 单播IP地址 */WintunGetAdapterLUID(Adapter, &AddressRow.InterfaceLuid);  /* 获取LUID */AddressRow.Address.Ipv4.sin_family = AF_INET;AddressRow.Address.Ipv4.sin_addr.S_un.S_addr = htonl(ip);     /* IP地址  16进制表示的xxx.xxx.xxx.xxx 高8位表示第一个xxx的16进制值 */AddressRow.OnLinkPrefixLength = 24;                           /* /24 网络,即子网掩码为255.255.255.000 */AddressRow.DadState = IpDadStatePreferred;DWORD LastError = CreateUnicastIpAddressEntry(&AddressRow);if (LastError != ERROR_SUCCESS && LastError != ERROR_OBJECT_ALREADY_EXISTS){printf("Failed to set IP address %d", LastError);WintunCloseAdapter(Adapter);FreeLibrary(Wintun);}WINTUN_SESSION_HANDLE Session = WintunStartSession(Adapter, 0x400000);if (!Session){printf("Failed to create adapter");WintunCloseAdapter(Adapter);FreeLibrary(Wintun);}

发送包

Wintun工作在第三层IP层,发送的是IP包。

BYTE* Packet = WintunAllocateSendPacket(Session, len); /* 先分配空间 */if (Packet){memcpy(Packet,buffer,len);WintunSendPacket(Session, Packet);   /* Packet中包含了长度信息,所以不需要再添加长度 */}

接收包

DWORD PacketSize;BYTE* Packet = WintunReceivePacket(Session, &PacketSize);if (Packet){/* 使用接收到的数据 *//* 释放 */WintunReleaseReceivePacket(Session, Packet);}

总结

Wintun提供了简洁的接口,在用户空间即可创建虚拟网卡,进行IP层的数据传输,基于此可以应用于很多应用场景,比如tcp/ip协议栈的移植,以太网和其他接口的转换等。

审核编辑:汤梓红

标签:

上一篇:Windows下创建虚拟网卡和网卡桥接进行调试和接口扩展
下一篇:最后一页