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協議棧的移植,以太網和其他接口的轉換等。
審核編輯:湯梓紅
-
嵌入式
+關注
關注
5089文章
19169瀏覽量
306757 -
WINDOWS
+關注
關注
4文章
3556瀏覽量
89081 -
開發環境
+關注
關注
1文章
229瀏覽量
16672
發布評論請先 登錄
相關推薦
評論