├── .gitignore ├── itest.aps ├── stdafx.cpp ├── targetver.h ├── stdafx.h ├── resource.h ├── readme.md ├── itest.vcxproj.user ├── itest.vcxproj.filters ├── ReadMe.txt ├── lib.h ├── itest.vcxproj ├── itest.cpp └── lib.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | /*.exe 2 | /Debug 3 | /Release 4 | -------------------------------------------------------------------------------- /itest.aps: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InsZVA/ZJUBattlePlatform/HEAD/itest.aps -------------------------------------------------------------------------------- /stdafx.cpp: -------------------------------------------------------------------------------- 1 | // stdafx.cpp : source file that includes just the standard includes 2 | // itest.pch will be the pre-compiled header 3 | // stdafx.obj will contain the pre-compiled type information 4 | 5 | #include "stdafx.h" 6 | 7 | // TODO: reference any additional headers you need in STDAFX.H 8 | // and not in this file 9 | -------------------------------------------------------------------------------- /targetver.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Including SDKDDKVer.h defines the highest available Windows platform. 4 | 5 | // If you wish to build your application for a previous Windows platform, include WinSDKVer.h and 6 | // set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. 7 | 8 | #include 9 | -------------------------------------------------------------------------------- /stdafx.h: -------------------------------------------------------------------------------- 1 | // stdafx.h : include file for standard system include files, 2 | // or project specific include files that are used frequently, but 3 | // are changed infrequently 4 | // 5 | 6 | #pragma once 7 | 8 | #include "targetver.h" 9 | 10 | #include 11 | #include 12 | 13 | 14 | 15 | // TODO: reference additional headers your program requires here 16 | -------------------------------------------------------------------------------- /resource.h: -------------------------------------------------------------------------------- 1 | //{{NO_DEPENDENCIES}} 2 | // Microsoft Visual C++ generated include file. 3 | // Used by itest.rc 4 | 5 | // Next default values for new objects 6 | // 7 | #ifdef APSTUDIO_INVOKED 8 | #ifndef APSTUDIO_READONLY_SYMBOLS 9 | #define _APS_NEXT_RESOURCE_VALUE 101 10 | #define _APS_NEXT_COMMAND_VALUE 40001 11 | #define _APS_NEXT_CONTROL_VALUE 1001 12 | #define _APS_NEXT_SYMED_VALUE 101 13 | #endif 14 | #endif 15 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | 浙江大学校园网对战平台 2 | 3 | ## 如何使用 4 | 5 | 请先安装OpenVPN虚拟网卡,之后不用启动它,只需要OpenVPN的网卡驱动即可。使用VS2013编译源代码, 6 | 在编译得到的可执行文件所在目录中放置映射关系表文件map.txt,内容如下: 7 | 8 | ```txt 9 | 2 10 | 222 205 0 126 192 168 1 8 00 FF 82 A2 A6 21 11 | 222 205 44 217 192 168 1 10 00 FF 3F 58 68 18 12 | ``` 13 | 14 | 第一行为房间内IP总数,之后每行描述了一台主机,前4个数字是校园网VPN地址,中间4个数字是映射后的虚拟 15 | IP地址,最后6位十六进制是TAP网卡的MAC地址(除了虚拟网卡地址外,其他地址都可以从源码中的代码获取), 16 | 之后的版本会做服务器以及服务器自动分配IP、MAC地址等功能。 17 | 18 | ## 特点 19 | 20 | 使用校园网内网进行传输,延迟极低,理论上支持所有单机局域网游戏(只要是通过IPv4连接的就可以,红警2 21 | 这种太古老用IPX的,还没有写支持,有兴趣的可以提交PR)。 22 | 23 | ## 测试 24 | 25 | 2017.3.11 22:11 魔兽争霸3 测试通过 -------------------------------------------------------------------------------- /itest.vcxproj.user: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | ..\Debug 5 | WindowsLocalDebugger 6 | 7 | 8 | ..\Debug 9 | WindowsLocalDebugger 10 | 11 | -------------------------------------------------------------------------------- /itest.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | Header Files 23 | 24 | 25 | Header Files 26 | 27 | 28 | Header Files 29 | 30 | 31 | Header Files 32 | 33 | 34 | 35 | 36 | Source Files 37 | 38 | 39 | Source Files 40 | 41 | 42 | Source Files 43 | 44 | 45 | -------------------------------------------------------------------------------- /ReadMe.txt: -------------------------------------------------------------------------------- 1 | ======================================================================== 2 | CONSOLE APPLICATION : itest Project Overview 3 | ======================================================================== 4 | 5 | AppWizard has created this itest application for you. 6 | 7 | This file contains a summary of what you will find in each of the files that 8 | make up your itest application. 9 | 10 | 11 | itest.vcxproj 12 | This is the main project file for VC++ projects generated using an Application Wizard. 13 | It contains information about the version of Visual C++ that generated the file, and 14 | information about the platforms, configurations, and project features selected with the 15 | Application Wizard. 16 | 17 | itest.vcxproj.filters 18 | This is the filters file for VC++ projects generated using an Application Wizard. 19 | It contains information about the association between the files in your project 20 | and the filters. This association is used in the IDE to show grouping of files with 21 | similar extensions under a specific node (for e.g. ".cpp" files are associated with the 22 | "Source Files" filter). 23 | 24 | itest.cpp 25 | This is the main application source file. 26 | 27 | ///////////////////////////////////////////////////////////////////////////// 28 | Other standard files: 29 | 30 | StdAfx.h, StdAfx.cpp 31 | These files are used to build a precompiled header (PCH) file 32 | named itest.pch and a precompiled types file named StdAfx.obj. 33 | 34 | ///////////////////////////////////////////////////////////////////////////// 35 | Other notes: 36 | 37 | AppWizard uses "TODO:" comments to indicate parts of the source code you 38 | should add to or customize. 39 | 40 | ///////////////////////////////////////////////////////////////////////////// 41 | -------------------------------------------------------------------------------- /lib.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #define WIN32_LEAN_AND_MEAN 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #pragma comment(lib, "IPHLPAPI.lib") 16 | #pragma comment(lib, "ws2_32.lib") 17 | #pragma comment(lib, "Shell32.lib") 18 | 19 | class Defer { 20 | private: 21 | std::function func; 22 | public: 23 | Defer(std::function func) : func(func){} 24 | ~Defer(){ this->func(); } 25 | }; 26 | 27 | int getTuntapInfo(std::wstring& netCfgInstanceId); 28 | HANDLE openTuntap(std::wstring netCfgInstanceId, BYTE addr[4], BYTE network[4], BYTE mask[4], bool tunmode = true); 29 | DWORD getTuntapIfId(std::wstring& netCfgInstanceId); 30 | int setTuntapIp(std::wstring& networkName, std::wstring ip, std::wstring mask, std::wstring gateway); 31 | int getNetworkName(std::wstring& netCfgInstanceId, std::wstring& networkName); 32 | void readTuntap(HANDLE hFile, HANDLE exitEvent, std::function readHandler, std::function errorHandler = nullptr); 33 | int prepareWriteTuntap(OVERLAPPED& ol); 34 | int writeTuntap(HANDLE hFile, OVERLAPPED& ol, void* p, int length, DWORD& done); 35 | void tuntapCleanup(HANDLE hFile, OVERLAPPED& ol); 36 | DWORD setIpForwardTable(DWORD network, DWORD mask, DWORD gateway, DWORD metric, DWORD ifIndex); 37 | void protectIpRouteTableThread(std::function callback, HANDLE exitEvent); 38 | int getTuntapMac(DWORD ifIndex, BYTE(&mac)[6]); 39 | 40 | struct EthernetIIPacket { 41 | public: 42 | enum Protocol{ Unkown = 0x0000, IPv4 = 0x0800, IPX = 0x8137, ARP = 0x0806 }; 43 | EthernetIIPacket(); 44 | EthernetIIPacket(std::string& data); 45 | EthernetIIPacket(const char* data, int length); 46 | bool Parse(std::string& data); 47 | bool Parse(const char* data, int length); 48 | bool Encode(char* buff, int* buffsize); 49 | BYTE srcMac[6]; 50 | BYTE dstMac[6]; 51 | Protocol protocol = Unkown; 52 | BYTE userData[1500]; 53 | int userDataLen = 0; 54 | }; 55 | 56 | struct IPv4Packet { 57 | public: 58 | enum Protocol { Unkown = 0x00, UDP = 0x11 }; 59 | IPv4Packet(); 60 | IPv4Packet(std::string& data); 61 | IPv4Packet(const char* data, int length); 62 | bool Parse(std::string& data); 63 | bool Parse(const char* data, int length); 64 | BYTE srcIp[4], dstIp[4]; 65 | Protocol protocol = Unkown; 66 | BYTE userData[1480]; 67 | int userDataLen = 0; 68 | }; 69 | 70 | struct IPv4ARPPacket { 71 | public: 72 | // 1: request 2: reply 73 | BYTE opCode = 1; 74 | BYTE senderIpAddress[4], targetIpAddress[4], senderMac[6], targetMac[6]; 75 | IPv4ARPPacket(); 76 | IPv4ARPPacket(std::string& data); 77 | IPv4ARPPacket(const char* data, int length); 78 | bool Parse(std::string& data); 79 | bool Parse(const char* data, int length); 80 | bool Encode(char* buff, int* buffsize); 81 | }; -------------------------------------------------------------------------------- /itest.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | 14 | {78126B67-91E9-43FB-801E-A5913D040869} 15 | Win32Proj 16 | itest 17 | 18 | 19 | 20 | Application 21 | true 22 | v120 23 | Unicode 24 | 25 | 26 | Application 27 | false 28 | v120 29 | true 30 | Unicode 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | true 44 | 45 | 46 | false 47 | 48 | 49 | 50 | Use 51 | Level3 52 | Disabled 53 | WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) 54 | true 55 | Default 56 | 57 | 58 | Console 59 | true 60 | RequireAdministrator 61 | 62 | 63 | 64 | 65 | Level3 66 | Use 67 | MaxSpeed 68 | true 69 | true 70 | WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) 71 | true 72 | 73 | 74 | Console 75 | true 76 | true 77 | true 78 | RequireAdministrator 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | Create 95 | Create 96 | 97 | 98 | 99 | 100 | 101 | -------------------------------------------------------------------------------- /itest.cpp: -------------------------------------------------------------------------------- 1 | // itest.cpp : Defines the entry point for the console application. 2 | // 3 | 4 | #include "stdafx.h" 5 | #include "lib.h" 6 | #include 7 | #include 8 | #include 9 | #include 10 | #define LISTEN_PORT 6667 11 | 12 | // RawIp -> MappedIP 13 | std::unordered_map ipMappingTable; 14 | // MappedIP -> RawIP 15 | std::unordered_map rIpMappingTable; 16 | // RawIp -> RawMac 17 | std::unordered_map> macTable; 18 | // common UDP client 19 | SOCKET udpClient; 20 | 21 | BYTE myIp[4] = { 0 }, tuntapMac[6] = { 0 }; 22 | HANDLE tuntap; 23 | OVERLAPPED wol; 24 | 25 | // get a minimum metric ip of route 0.0.0.0 26 | int getZJUIPAddress(BYTE (&ip)[4]) { 27 | MIB_IPFORWARD_TABLE2* pIpForwardTable = NULL; 28 | MIB_IPFORWARD_ROW2* pRow = NULL; 29 | BOOL bOrder = FALSE; 30 | DWORD dwStatus = 0; 31 | unsigned int i; 32 | dwStatus = GetIpForwardTable2(AF_INET, &pIpForwardTable); 33 | Defer defer([&pIpForwardTable, &pRow](){ 34 | if (pIpForwardTable) 35 | FreeMibTable(pIpForwardTable); 36 | }); 37 | if (dwStatus != ERROR_SUCCESS) return dwStatus; 38 | DWORD prefixLength = 0; 39 | DWORD minMetric = INFINITE; 40 | for (i = 0; i < pIpForwardTable->NumEntries; i++) { 41 | if (pIpForwardTable->Table[i].DestinationPrefix.Prefix.Ipv4.sin_addr.S_un.S_addr == 0 && 42 | pIpForwardTable->Table[i].DestinationPrefix.PrefixLength == prefixLength) { 43 | if (pIpForwardTable->Table[i].Metric < minMetric) 44 | pRow = &pIpForwardTable->Table[i]; 45 | } 46 | } 47 | if (pRow == NULL) 48 | return -1; 49 | 50 | // iterator the ip table 51 | PMIB_IPADDRTABLE pIpAddrTable = NULL; 52 | ULONG pdwSize = 0; 53 | if (GetIpAddrTable(pIpAddrTable, &pdwSize, FALSE) == ERROR_INSUFFICIENT_BUFFER) { 54 | pIpAddrTable = (PMIB_IPADDRTABLE)(malloc(pdwSize)); 55 | if (GetIpAddrTable(pIpAddrTable, &pdwSize, FALSE) != NO_ERROR) { 56 | return -1; 57 | } 58 | } 59 | else return -1; 60 | Defer defer2([&pIpAddrTable](){ 61 | free(pIpAddrTable); 62 | }); 63 | for (int i = 0; i < pIpAddrTable->dwNumEntries; i++) { 64 | if (pIpAddrTable->table[i].dwIndex == pRow->InterfaceIndex) { 65 | *(DWORD*)(&ip[0]) = pIpAddrTable->table[i].dwAddr; 66 | return 0; 67 | } 68 | } 69 | return -1; 70 | } 71 | 72 | void receiver(DWORD ip, HANDLE exitEvent) { 73 | 74 | 75 | SOCKET listener = WSASocket(AF_INET, SOCK_DGRAM, IPPROTO_UDP, NULL, 0, WSA_FLAG_OVERLAPPED); 76 | sockaddr_in addr = { 0 }; 77 | addr.sin_family = AF_INET; 78 | addr.sin_addr.S_un.S_addr = ip; 79 | addr.sin_port = htons(LISTEN_PORT); 80 | if (bind(listener, (SOCKADDR*)&addr, sizeof(addr)) == SOCKET_ERROR) 81 | return; 82 | sockaddr_in remoteAddr = { 0 }; 83 | WSAOVERLAPPED ol = { 0 }; 84 | ol.hEvent = WSACreateEvent(); 85 | Defer defer([ol, listener](){ 86 | WSACloseEvent(ol.hEvent); 87 | closesocket(listener); 88 | }); 89 | int addrLen = sizeof(sockaddr); 90 | WSABUF buffer; 91 | char buf[1472]; 92 | buffer.buf = buf; 93 | buffer.len = 1472; 94 | DWORD result, nRecv, flags = 0; 95 | HANDLE handles[2] = { ol.hEvent, exitEvent }; 96 | char addStr[128]; 97 | EthernetIIPacket eth; 98 | char sendBuffer[1500]; 99 | DWORD rawIp, mappedIp; 100 | for (;;) { 101 | result = WSARecvFrom(listener, &buffer, 1, &nRecv, &flags, (sockaddr*)&remoteAddr, &addrLen, &ol, NULL); 102 | if (result == NO_ERROR) { 103 | //std::cout << "Receive From " << inet_ntop(AF_INET, &remoteAddr.sin_addr, addStr, 128) << ":" << nRecv << "Bytes." << std::endl; 104 | rawIp = remoteAddr.sin_addr.S_un.S_addr; 105 | mappedIp = ipMappingTable[rawIp]; 106 | if (mappedIp != 0) { 107 | memcpy(&buffer.buf[12], &mappedIp, 4); // not necessaty 108 | if (*(DWORD*)(&buffer.buf[16]) != 0xffffffff) { 109 | DWORD myIpMapped = ipMappingTable[*(DWORD*)(&myIp[0])]; 110 | memcpy(&buffer.buf[16], &myIpMapped, 4); // shoule check mac again? 111 | } 112 | auto m = macTable[*(DWORD*)(&myIp[0])]; 113 | for (int i = 0; i < 6; i++) sendBuffer[i] = m[i]; 114 | m = macTable[rawIp]; 115 | for (int i = 0; i < 6; i++) sendBuffer[6+i] = m[i]; 116 | *(unsigned short*)(&sendBuffer[12]) = htons(0x0800); // network order 117 | memcpy(sendBuffer + 14, buffer.buf, nRecv); 118 | DWORD done = 0; 119 | writeTuntap(tuntap, wol, &sendBuffer, nRecv + 14, done); 120 | } 121 | } 122 | else if ((result = WSAGetLastError()) == WSA_IO_PENDING) { 123 | switch (WaitForMultipleObjects(2, handles, FALSE, INFINITE)) { 124 | case WAIT_OBJECT_0: 125 | std::cout << "Receive From " << inet_ntop(AF_INET, &remoteAddr.sin_addr, addStr, 128) << ":" << ol.InternalHigh << "Bytes." << std::endl; 126 | rawIp = remoteAddr.sin_addr.S_un.S_addr; 127 | mappedIp = ipMappingTable[rawIp]; 128 | nRecv = ol.InternalHigh; 129 | if (mappedIp != 0 && nRecv > 20) { 130 | memcpy(&buffer.buf[12], &mappedIp, 4); // not necessaty 131 | if (*(DWORD*)(&buffer.buf[16]) != 0xffffffff) { 132 | DWORD myIpMapped = ipMappingTable[*(DWORD*)(&myIp[0])]; 133 | memcpy(&buffer.buf[16], &myIpMapped, 4); // shoule check mac again? 134 | } 135 | auto m = macTable[*(DWORD*)(&myIp[0])]; 136 | for (int i = 0; i < 6; i++) sendBuffer[i] = m[i]; 137 | m = macTable[rawIp]; 138 | for (int i = 0; i < 6; i++) sendBuffer[6 + i] = m[i]; 139 | *(unsigned short*)(&sendBuffer[12]) = htons(0x0800); // network order 140 | memcpy(sendBuffer + 14, buffer.buf, nRecv); 141 | DWORD done = 0; 142 | writeTuntap(tuntap, wol, &sendBuffer, nRecv + 14, done); 143 | } 144 | break; 145 | case WAIT_OBJECT_0 + 1: 146 | return; 147 | } 148 | } 149 | } 150 | } 151 | 152 | bool IPPacketAnalyse(std::string data) { 153 | BYTE b = data[0]; 154 | BYTE version = b >> 4; 155 | if (version == 6) return true; // ignore IPv6 156 | BYTE headSize = b & 0xf; 157 | for (int i = 12; i < 15; i++) { 158 | std::wcout << (BYTE)data[i] << L"."; 159 | } 160 | std::wcout << (BYTE)data[15] << L"->"; 161 | for (int i = 16; i < 19; i++) { 162 | std::wcout << (BYTE)data[i] << L"."; 163 | } 164 | std::wcout << (BYTE)data[19] << L" " << (int)(data.size() - headSize) << L"Bytes" << std::endl; 165 | return true; 166 | } 167 | 168 | void sendUdpData(DWORD dstIp, const char* data, int length) { 169 | BYTE* ip = (BYTE*)&dstIp; 170 | //printf("send udp to %d.%d.%d.%d\n", ip[0], ip[1], ip[2], ip[3]); 171 | sockaddr_in remoteAddr = { 0 }; 172 | remoteAddr.sin_addr.S_un.S_addr = dstIp; 173 | remoteAddr.sin_port = htons(LISTEN_PORT); 174 | remoteAddr.sin_family = AF_INET; 175 | sendto(udpClient, data, length, 0, (sockaddr*)(&remoteAddr), sizeof(remoteAddr)); 176 | } 177 | 178 | bool IPAnalyseFromEthernet(std::string data) { 179 | // TODO: optimize using mempool 180 | EthernetIIPacket* eth = new EthernetIIPacket(data); 181 | IPv4Packet* ip = NULL; 182 | BYTE* mac = NULL; 183 | char* buffer = NULL; 184 | switch (eth->protocol) { 185 | case EthernetIIPacket::IPv4: 186 | ip = new IPv4Packet((const char*)(ð->userData[0]), eth->userDataLen); 187 | if (ip->dstIp[3] == 0xff) { 188 | for (auto src : ipMappingTable) { 189 | if (src.first != *(DWORD*)(&myIp[0])) 190 | sendUdpData(src.first, (const char*)eth->userData, eth->userDataLen); 191 | } 192 | } 193 | else { 194 | DWORD rawIp = rIpMappingTable[*(DWORD*)(&ip->dstIp[0])]; 195 | if (rawIp != 0 && rawIp != *(DWORD*)(&myIp[0])) { 196 | sendUdpData(rawIp, (const char*)eth->userData, eth->userDataLen); 197 | } 198 | } 199 | delete ip; 200 | break; 201 | case EthernetIIPacket::ARP: 202 | IPv4ARPPacket* arp = new IPv4ARPPacket((const char*)(ð->userData[0]), eth->userDataLen); 203 | DWORD dstIp = *(DWORD*)arp->targetIpAddress; 204 | auto&& dstMac = macTable[rIpMappingTable[dstIp]]; 205 | arp->opCode = 2; 206 | if (dstMac.size() < 6 || *(DWORD*)arp->senderIpAddress == 0) { 207 | delete arp; 208 | break; 209 | } 210 | mac = new BYTE[6]{ dstMac[0], dstMac[1], dstMac[2], dstMac[3], dstMac[4], dstMac[5] }; 211 | buffer = new char[28 + 14]{0}; 212 | memcpy(arp->targetMac, arp->senderMac, 6); 213 | memcpy(arp->senderMac, mac, 6); 214 | DWORD tempIp = *(DWORD*)&arp->senderIpAddress; 215 | *(DWORD*)arp->senderIpAddress = *(DWORD*)arp->targetIpAddress; 216 | *(DWORD*)arp->targetIpAddress = tempIp; 217 | int length = 28; 218 | arp->Encode(buffer + 14, &length); 219 | *(unsigned short*)(&buffer[12]) = htons(0x0806); // network order 220 | memcpy(buffer, &arp->senderMac, 6); 221 | memcpy(buffer + 6, &arp->targetMac, 6); 222 | DWORD done = 0; 223 | writeTuntap(tuntap, wol, buffer, (DWORD)28 + 14, done); 224 | delete mac; 225 | delete buffer; 226 | delete arp; 227 | } 228 | delete eth; 229 | return true; 230 | } 231 | 232 | void initIPMapping() { 233 | // TODO: Get From Server 234 | std::ifstream inf("./map.txt", std::ios_base::in); 235 | if (!inf.is_open()) return; 236 | int n; 237 | inf >> n; 238 | int buf[6]; 239 | BYTE rawIp[4] = { 0 }, mappedIp[4] = { 0 }, mac[6] = { 0 }; 240 | for (int i = 0; i < n; i++) { 241 | for (int j = 0; j < 4; j++) { 242 | inf >> std::dec >> buf[j]; 243 | rawIp[j] = buf[j] & 0xff; 244 | } 245 | for (int j = 0; j < 4; j++) { 246 | inf >> std::dec >> buf[j]; 247 | mappedIp[j] = buf[j] & 0xff; 248 | } 249 | for (int j = 0; j < 6; j++) { 250 | inf >> std::hex >> buf[j]; 251 | mac[j] = buf[j] & 0xff; 252 | } 253 | ipMappingTable[*(DWORD*)(&rawIp[0])] = *(DWORD*)(&mappedIp[0]); 254 | rIpMappingTable[*(DWORD*)(&mappedIp[0])] = *(DWORD*)(&rawIp[0]); 255 | std::vector v; 256 | v.reserve(6); 257 | v.resize(6); 258 | for (int j = 0; j < 6; j++) 259 | v[j] = mac[j]; 260 | macTable[*(DWORD*)(&rawIp[0])] = v; 261 | } 262 | udpClient = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); 263 | inf.close(); 264 | } 265 | 266 | int _tmain(int argc, _TCHAR* argv[]) 267 | { 268 | WSADATA wsaData = { 0 }; 269 | if (WSAStartup(MAKEWORD(2, 2), &wsaData) != NO_ERROR) return -1; 270 | initIPMapping(); 271 | std::wstring s1; 272 | getTuntapInfo(s1); 273 | std::wcout << s1 << std::endl; 274 | DWORD ifIndex = getTuntapIfId(s1); 275 | std::wcout << ifIndex << std::endl; 276 | if (getZJUIPAddress(myIp) == 0 && getTuntapMac(ifIndex, tuntapMac) == 0) 277 | printf("My ip is: %d.%d.%d.%d\n Tuntap mac is: %X:%X:%X:%X:%X:%X\n", myIp[0], myIp[1], myIp[2], myIp[3], 278 | tuntapMac[0], tuntapMac[1], tuntapMac[2], tuntapMac[3], tuntapMac[4], tuntapMac[5]); 279 | else { 280 | printf("Getting my ip failed.\n"); 281 | return -1; 282 | } 283 | std::wstring networkName; 284 | getNetworkName(s1, networkName); 285 | std::wcout.imbue(std::locale("chs")); 286 | std::wcout << networkName << std::endl; 287 | std::wostringstream os; 288 | BYTE myIpMapped[4] = { 0 }; 289 | *(DWORD*)(&myIpMapped[0]) = ipMappingTable[*(DWORD*)(&myIp[0])]; 290 | os << std::dec << myIpMapped[0] << L"." << std::dec << myIpMapped[1] << L"." << std::dec << myIpMapped[2] << L"." << std::dec << myIpMapped[3]; 291 | setTuntapIp(networkName, os.str(), L"255.255.255.0", L""); 292 | BYTE addr[4] = { myIp[0], myIp[1], myIp[2], myIp[3] }, network[4] = { 192, 168, 1, 0 }, mask[4] = { 255, 255, 255, 0 }; 293 | tuntap = openTuntap(s1, addr, network, mask, false); 294 | Sleep(1000); 295 | prepareWriteTuntap(wol); 296 | setIpForwardTable(0xffffffff, 0xffffffff, 0x0000000, 0, ifIndex); 297 | HANDLE threadExit = CreateEvent(NULL, NULL, NULL, NULL); 298 | std::thread tProtect([ifIndex, threadExit](){ 299 | protectIpRouteTableThread([ifIndex, threadExit](){ 300 | setIpForwardTable(0xffffffff, 0xffffffff, 0x0000000, 0, ifIndex); 301 | }, threadExit); 302 | }); 303 | std::thread tReadTuntap([threadExit](){ 304 | readTuntap(tuntap, threadExit, IPAnalyseFromEthernet); 305 | }); 306 | std::thread tListener([threadExit](){ 307 | receiver(*(DWORD*)(&myIp[0]), threadExit); 308 | }); 309 | getchar(); 310 | SetEvent(threadExit); 311 | SetEvent(threadExit); 312 | SetEvent(threadExit); 313 | tProtect.join(); 314 | tReadTuntap.join(); 315 | tListener.join(); 316 | CloseHandle(wol.hEvent); 317 | CloseHandle(threadExit); 318 | CloseHandle(tuntap); 319 | closesocket(udpClient); 320 | WSACleanup(); 321 | return 0; 322 | } 323 | -------------------------------------------------------------------------------- /lib.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "lib.h" 3 | 4 | #define ADAPTER_KEY (L"SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}") 5 | #define NETWORK_KEY (L"SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}") 6 | #define TUNTAP_COMPONENT_ID (L"tap0901") 7 | #define CTL_CODE(device_type, function, method, access) ((device_type << 16) | (access << 14) | (function << 2) | method) 8 | #define TAP_CONTROL_CODE(request, method) (CTL_CODE(34, request, method, 0)) 9 | #define TAP_IOCTL_CONFIG_TUN TAP_CONTROL_CODE(10, 0) 10 | #define TAP_IOCTL_CONFIG_POINT_TO_POINT TAP_CONTROL_CODE(5, 0) 11 | #define TAP_IOCTL_SET_MEDIA_STATUS TAP_CONTROL_CODE(6, 0) 12 | 13 | /** 14 | * read the device item's "ComponentId" SZ & "DriverDesc" SZ 15 | * @private 16 | */ 17 | static int readKeyInfo(HKEY hKey, LPWSTR subKeyName, std::wstring& netCfgInstanceId) { 18 | HKEY k; 19 | if (LONG result = RegOpenKeyEx(hKey, subKeyName, NULL, KEY_READ, &k) != ERROR_SUCCESS) return result; 20 | DWORD len = 64; 21 | DWORD type; 22 | BYTE *data = new BYTE[len]; 23 | Defer defer([&data, &k](){ 24 | delete data; 25 | RegCloseKey(k); 26 | }); 27 | redo0: 28 | LONG result = RegQueryValueEx(k, L"ComponentId", NULL, &type, data, &len); 29 | switch (result) { 30 | case ERROR_SUCCESS: 31 | if (!(type == REG_SZ || type == REG_EXPAND_SZ)) 32 | return -1; 33 | if (lstrcmpW((const wchar_t*)(data), TUNTAP_COMPONENT_ID) != 0) 34 | return -1; 35 | break; 36 | case ERROR_MORE_DATA: 37 | delete data; 38 | data = new BYTE[++len]; 39 | goto redo0; 40 | default: 41 | return result; 42 | } 43 | redo1: 44 | result = RegQueryValueEx(k, L"NetCfgInstanceId", NULL, &type, data, &len); 45 | switch (result) { 46 | case ERROR_SUCCESS: 47 | if (type == REG_SZ || type == REG_EXPAND_SZ) 48 | netCfgInstanceId = (wchar_t*)data; 49 | break; 50 | case ERROR_MORE_DATA: 51 | delete data; 52 | data = new BYTE[++len]; 53 | goto redo1; 54 | default: 55 | return result; 56 | } 57 | return ERROR_SUCCESS; 58 | } 59 | 60 | /** 61 | * get the tuntap device info 62 | * @public 63 | * @return ERROR_SUCCESS if ok, -1 else 64 | */ 65 | int getTuntapInfo(std::wstring& netCfgInstanceId) { 66 | HKEY hKey; 67 | if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, ADAPTER_KEY, NULL, KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE, &hKey) != ERROR_SUCCESS) 68 | return -1; 69 | DWORD subKeyCount = 0, maxSubKeyLen = 0, valueCount = 0, maxValueNameLen = 0, maxValueLen = 0; 70 | if (RegQueryInfoKey(hKey, NULL, NULL, NULL, &subKeyCount, &maxSubKeyLen, NULL, &valueCount, &maxValueNameLen, &maxValueLen, NULL, NULL) != ERROR_SUCCESS) 71 | return -1; 72 | 73 | wchar_t *buf = new wchar_t[maxSubKeyLen + 1]; 74 | Defer defer([&buf, &hKey](){ 75 | delete buf; 76 | RegCloseKey(hKey); 77 | }); 78 | 79 | DWORD cName = maxSubKeyLen + 1; 80 | LONG result; 81 | for (unsigned int i = 0; i < subKeyCount; i++) { 82 | result = RegEnumKeyEx(hKey, i, buf, &cName, NULL, NULL, NULL, NULL); 83 | switch (result) { 84 | case ERROR_MORE_DATA: 85 | delete buf; 86 | buf = new wchar_t[++cName]; 87 | i--; 88 | continue; 89 | case ERROR_SUCCESS: 90 | break; 91 | case ERROR_NO_MORE_ITEMS: 92 | break; 93 | default: 94 | return result; 95 | } 96 | if (readKeyInfo(hKey, buf, netCfgInstanceId) == ERROR_SUCCESS) 97 | return ERROR_SUCCESS; 98 | } 99 | return -1; 100 | } 101 | 102 | // return HANDLE if ok, INVALID_HANDLE_VALUE else 103 | HANDLE openTuntap(std::wstring netCfgInstanceId, BYTE addr[4], BYTE network[4], BYTE mask[4], bool tunmode) { 104 | std::wstring path = L"\\\\.\\Global\\" + netCfgInstanceId + L".tap"; 105 | HANDLE f = CreateFile(path.c_str(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED, NULL); 106 | if (f == INVALID_HANDLE_VALUE) return INVALID_HANDLE_VALUE; 107 | BYTE* config = new BYTE[12]; 108 | Defer defer([&config, &f](){ 109 | delete config; 110 | }); 111 | memcpy(config, addr, 4); 112 | memcpy(config + 4, network, 4); 113 | memcpy(config + 8, mask, 4); 114 | DWORD returnLen; 115 | if (tunmode) 116 | if (DeviceIoControl(f, (tunmode?TAP_IOCTL_CONFIG_TUN:TAP_IOCTL_CONFIG_POINT_TO_POINT), config, (tunmode?12:8), config, (tunmode?12:8), &returnLen, NULL) == 0) { 117 | if (GetLastError() == ERROR_IO_PENDING) { 118 | //TODO: 119 | } 120 | else { 121 | return INVALID_HANDLE_VALUE; 122 | } 123 | } 124 | config[0] = 0x01; config[1] = 0x00; config[2] = 0x00; config[3] = 0x00; 125 | if (DeviceIoControl(f, TAP_IOCTL_SET_MEDIA_STATUS, config, 4, config, 4, &returnLen, NULL) == 0) { 126 | if (GetLastError() == ERROR_IO_PENDING) { 127 | //TODO: 128 | } 129 | else { 130 | return INVALID_HANDLE_VALUE; 131 | } 132 | } 133 | return f; 134 | } 135 | 136 | std::string ws2s(std::wstring ws) 137 | { 138 | const wchar_t* Source = ws.c_str(); 139 | size_t size = 2 * ws.size() + 1; 140 | char* Dest = new char[size]; 141 | memset(Dest, 0, size); 142 | size_t len = 0; 143 | wcstombs_s(&len, Dest, size, Source, size); 144 | //wcstombs_s(&len, Dest, size, Source, size); 145 | std::string result = Dest; 146 | delete Dest; 147 | 148 | return result; 149 | } 150 | 151 | // return id if ok, INFINATE else 152 | DWORD getTuntapIfId(std::wstring& netCfgInstanceId) { 153 | ULONG ifIndex; 154 | std::wstring adapterName = L"\\DEVICE\\TCPIP_" + netCfgInstanceId; 155 | LONG result; 156 | if ((result = GetAdapterIndex((LPWSTR)adapterName.c_str(), &ifIndex)) == NO_ERROR) 157 | return ifIndex; 158 | return INFINITE; 159 | } 160 | 161 | // return NO_ERROR if ok, -1 else 162 | int getNetworkName(std::wstring& netCfgInstanceId, std::wstring& networkName) { 163 | HKEY k; 164 | std::wstring path = NETWORK_KEY; 165 | path += L"\\" + netCfgInstanceId + L"\\Connection"; 166 | if (LONG result = RegOpenKeyEx(HKEY_LOCAL_MACHINE, path.c_str(), NULL, KEY_READ, &k) != ERROR_SUCCESS) return result; 167 | DWORD len = 64; 168 | DWORD type; 169 | BYTE *data = new BYTE[len]; 170 | Defer defer([data, k](){ 171 | delete data; 172 | RegCloseKey(k); 173 | }); 174 | redo0: 175 | LONG result = RegQueryValueEx(k, L"Name", NULL, &type, data, &len); 176 | switch (result) { 177 | case ERROR_SUCCESS: 178 | if (!(type == REG_SZ || type == REG_EXPAND_SZ)) 179 | return -1; 180 | networkName = (wchar_t*)data; 181 | break; 182 | case ERROR_MORE_DATA: 183 | delete data; 184 | data = new BYTE[++len]; 185 | goto redo0; 186 | default: 187 | return result; 188 | } 189 | return -1; 190 | } 191 | 192 | // return NO_ERROR if ok 193 | int setTuntapIp(std::wstring& networkName, std::wstring ip, std::wstring mask, std::wstring gateway) { 194 | std::wstring cmdLine = L" interface ip set address name=\"" + networkName + L"\" source=static addr=" + ip + L" mask=" + mask; 195 | if (gateway != L"") cmdLine += L" gateway=" + gateway; 196 | cmdLine += L" gwmetric=0"; 197 | HINSTANCE instance = ShellExecute(NULL, L"runas", L"netsh.exe", cmdLine.c_str(), L"c:\\windows\\system32", SW_HIDE); 198 | if (instance <= HINSTANCE(32)) return -1; 199 | WaitForSingleObject(instance, INFINITE); 200 | return 0; 201 | } 202 | 203 | void readTuntap(HANDLE hFile, HANDLE exitEvent, std::function readHandler, std::function errorHandler) { 204 | OVERLAPPED ol = { 0 }; 205 | HANDLE hEvent; 206 | hEvent = CreateEvent(NULL, NULL, NULL, NULL); 207 | if (hEvent == NULL) { 208 | if (errorHandler != nullptr) errorHandler(GetLastError()); 209 | return; 210 | } 211 | ol.hEvent = hEvent; 212 | BYTE buff[1500]; 213 | DWORD read; 214 | DWORD errNo; 215 | HANDLE handles[2] = { ol.hEvent, exitEvent }; 216 | for (;;) { 217 | if (ReadFile(hFile, buff, 1500, &read, &ol) != FALSE) { 218 | if (!readHandler(std::string((char*)buff, read))) break; 219 | } 220 | else if ((errNo = GetLastError()) == ERROR_IO_PENDING) { 221 | switch (WaitForMultipleObjects(2, handles, false, INFINITE)) { 222 | case WAIT_OBJECT_0: 223 | if (!readHandler(std::string((char*)buff, ol.InternalHigh))) break; 224 | break; 225 | case WAIT_OBJECT_0 + 1: 226 | return; 227 | } 228 | } 229 | else { 230 | if (errorHandler != nullptr) 231 | errorHandler(errNo); 232 | break; 233 | } 234 | } 235 | CloseHandle(ol.hEvent); 236 | } 237 | 238 | int prepareWriteTuntap(OVERLAPPED& ol) { 239 | HANDLE hEvent = CreateEvent(NULL, NULL, NULL, NULL); 240 | if (hEvent == NULL) { 241 | return -1; 242 | } 243 | ol.hEvent = hEvent; 244 | return NO_ERROR; 245 | } 246 | 247 | // return NO_ERROR if ok, error code else 248 | int writeTuntap(HANDLE hFile, OVERLAPPED& ol, void* p, int length, DWORD& done) { 249 | static std::mutex mutex; 250 | std::lock_guard lock(mutex); 251 | DWORD errNo; 252 | if (WriteFile(hFile, p, length, &done, &ol) != FALSE) { 253 | ol.Offset += length; 254 | return NO_ERROR; 255 | } 256 | else if ((errNo = GetLastError()) == ERROR_IO_PENDING) { 257 | WaitForSingleObject(ol.hEvent, INFINITE); 258 | done = ol.InternalHigh; 259 | ol.Offset += length; 260 | return NO_ERROR; 261 | } 262 | else return errNo; 263 | } 264 | 265 | void tuntapCleanup(HANDLE hFile, OVERLAPPED& ol) { 266 | CloseHandle(ol.hEvent); 267 | CloseHandle(hFile); 268 | } 269 | 270 | static std::vector backup; 271 | 272 | // ipformat: AA.BB.CC.DD: 0xDDCCBBAA 273 | // delete all others 274 | DWORD setIpForwardTable(DWORD network, DWORD mask, DWORD gateway, DWORD metric, DWORD ifIndex) { 275 | MIB_IPFORWARD_TABLE2* pIpForwardTable = NULL; 276 | MIB_IPFORWARD_ROW2* pRow = NULL; 277 | BOOL bOrder = FALSE; 278 | DWORD dwStatus = 0; 279 | unsigned int i; 280 | dwStatus = GetIpForwardTable2(AF_INET, &pIpForwardTable); 281 | Defer defer([&pIpForwardTable, &pRow](){ 282 | if (pIpForwardTable) 283 | FreeMibTable(pIpForwardTable); 284 | }); 285 | if (dwStatus != ERROR_SUCCESS) return dwStatus; 286 | DWORD prefixLength = 0; 287 | DWORD tempMask = mask; 288 | while (tempMask) { 289 | tempMask >>= 1; 290 | prefixLength++; 291 | } 292 | for (i = 0; i < pIpForwardTable->NumEntries; i++) { 293 | if (pIpForwardTable->Table[i].DestinationPrefix.Prefix.Ipv4.sin_addr.S_un.S_addr == network && 294 | pIpForwardTable->Table[i].DestinationPrefix.PrefixLength == prefixLength && pIpForwardTable->Table[i].InterfaceIndex != ifIndex) { 295 | backup.push_back(pIpForwardTable->Table[i]); //Backup: TODO avoid repeatly backup 296 | dwStatus = DeleteIpForwardEntry2(&pIpForwardTable->Table[i]); 297 | return setIpForwardTable(network, mask, gateway, metric, ifIndex); 298 | } 299 | } 300 | return -1; 301 | } 302 | 303 | void protectIpRouteTableThread(std::function callback, HANDLE exitEvent) { 304 | OVERLAPPED ol = { 0 }; 305 | HANDLE handle; 306 | ol.hEvent = CreateEvent(NULL, NULL, NULL, NULL); 307 | HANDLE waited[2] = { ol.hEvent, exitEvent }; 308 | Defer defer([handle, ol](){ 309 | // Resore ip table route 310 | for (auto row : backup) { 311 | CreateIpForwardEntry2(&row); 312 | } 313 | CloseHandle(ol.hEvent); 314 | //CloseHandle(handle); 315 | }); 316 | for (;;) { 317 | NotifyRouteChange(&handle, &ol); 318 | switch (WaitForMultipleObjects(2, waited, false, INFINITE)) { 319 | case WAIT_OBJECT_0: 320 | callback(); 321 | break; 322 | case WAIT_OBJECT_0 + 1: 323 | return; 324 | } 325 | } 326 | } 327 | 328 | int getTuntapMac(DWORD ifIndex, BYTE(&mac)[6]) { 329 | // TODO: optimize by cache the table 330 | PMIB_IF_TABLE2 pIfTable = NULL; 331 | if (GetIfTable2(&pIfTable) != NO_ERROR) return -1; 332 | Defer defer3([&pIfTable](){FreeMibTable(pIfTable); }); 333 | for (int i = 0; i < pIfTable->NumEntries; i++) { 334 | if (pIfTable->Table[i].InterfaceIndex == ifIndex) { 335 | memcpy(&mac, pIfTable->Table[i].PhysicalAddress, 6); 336 | return 0; 337 | } 338 | } 339 | return -1; 340 | } 341 | 342 | EthernetIIPacket::EthernetIIPacket() { 343 | memset(this->dstMac, 0, 6); 344 | memset(this->srcMac, 0, 6); 345 | } 346 | 347 | EthernetIIPacket::EthernetIIPacket(const char* data, int length):EthernetIIPacket() { 348 | Parse(data, length); 349 | } 350 | 351 | EthernetIIPacket::EthernetIIPacket(std::string& data):EthernetIIPacket() { 352 | Parse(data); 353 | } 354 | 355 | bool EthernetIIPacket::Parse(std::string& data) { 356 | return Parse(data.c_str(), data.size()); 357 | } 358 | 359 | bool EthernetIIPacket::Parse(const char* raw, int length) { 360 | if (length < 14) return false; 361 | memcpy(this->srcMac, raw + 6, 6); 362 | memcpy(this->dstMac, raw, 6); 363 | this->protocol = Protocol(ntohs(*(unsigned short*)(&raw[12]))); 364 | this->userDataLen = length < 1514 ? length - 14 : 1500; 365 | memcpy(this->userData, raw + 14, this->userDataLen); 366 | return true; 367 | } 368 | 369 | bool EthernetIIPacket::Encode(char* buff, int* buffsize) { 370 | int need = this->userDataLen + 14; 371 | if (*buffsize < need) { *buffsize = need; return false; } 372 | memcpy(buff, this->dstMac, 6); 373 | memcpy(buff + 6, this->srcMac, 6); 374 | USHORT protocol = htons(*(unsigned short*)(&this->protocol)); 375 | memcpy(buff + 12, &protocol, 2); 376 | memcpy(buff + 14, this->userData, this->userDataLen); 377 | return true; 378 | } 379 | 380 | IPv4Packet::IPv4Packet() { 381 | memset(this->srcIp, 0, 4); 382 | memset(this->dstIp, 0, 4); 383 | } 384 | 385 | IPv4Packet::IPv4Packet(std::string& data):IPv4Packet() { 386 | Parse(data); 387 | } 388 | 389 | IPv4Packet::IPv4Packet(const char* raw, int length):IPv4Packet() { 390 | Parse(raw, length); 391 | } 392 | 393 | bool IPv4Packet::Parse(std::string& data) { 394 | return Parse(data.c_str(), data.size()); 395 | } 396 | 397 | bool IPv4Packet::Parse(const char* raw, int length) { 398 | if (length < 20) return false; 399 | this->protocol = Protocol((BYTE)(raw[9])); 400 | memcpy(this->srcIp, raw + 12, 4); 401 | memcpy(this->dstIp, raw + 16, 4); 402 | this->userDataLen = length < 1500 ? length - 20 : 1480; 403 | memcpy(this->userData, raw + 20, this->userDataLen); 404 | return true; 405 | } 406 | 407 | IPv4ARPPacket::IPv4ARPPacket() { 408 | memset(this->senderIpAddress, 0, 4); 409 | memset(this->senderMac, 0, 6); 410 | memset(this->targetIpAddress, 0, 4); 411 | memset(this->targetMac, 0, 6); 412 | } 413 | 414 | IPv4ARPPacket::IPv4ARPPacket(std::string& data) :IPv4ARPPacket(){ 415 | Parse(data); 416 | } 417 | 418 | IPv4ARPPacket::IPv4ARPPacket(const char* data, int length) : IPv4ARPPacket(){ 419 | Parse(data, length); 420 | } 421 | 422 | bool IPv4ARPPacket::Parse(std::string& data) { 423 | return Parse(data.c_str(), data.size()); 424 | } 425 | 426 | bool IPv4ARPPacket::Parse(const char* data, int length) { 427 | if (length < 28) return false; 428 | this->opCode = data[7]; 429 | memcpy(this->senderMac, data + 8, 6); 430 | memcpy(this->senderIpAddress, data + 14, 4); 431 | memcpy(this->targetMac, data + 18, 6); 432 | memcpy(this->targetIpAddress, data + 24, 4); 433 | return true; 434 | } 435 | 436 | bool IPv4ARPPacket::Encode(char* buff, int* buffsize) { 437 | BYTE header[] = { 0x00, 0x01, 0x08, 0x00, 0x06, 0x04, 0x00 }; 438 | if (*buffsize < 28) { 439 | *buffsize = 28; 440 | return false; 441 | } 442 | memcpy(buff, header, 7); 443 | buff[7] = this->opCode; 444 | memcpy(buff + 8, this->senderMac, 6); 445 | memcpy(buff + 14, this->senderIpAddress, 4); 446 | memcpy(buff + 18, this->targetMac, 6); 447 | memcpy(buff + 24, this->targetIpAddress, 4); 448 | return true; 449 | } --------------------------------------------------------------------------------