Windows下基于MSVC搭建Wintun开发环境

描述

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

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;

WINDOWS

设置链接的库

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

WINDOWS

设置输出路径

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

WINDOWS

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

WINDOWS

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

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

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

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

WINDOWS

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

WINDOWS

命令行ipconfig可以看到

WINDOWS

也可以ping通

WINDOWS

基本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协议栈的移植,以太网和其他接口的转换等。

  审核编辑:汤梓红

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分