wintap.c 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372
  1. #ifndef _CRT_SECURE_NO_WARNINGS
  2. #define _CRT_SECURE_NO_WARNINGS
  3. #endif
  4. #ifndef CONFIG
  5. #define CONFIG "config.h"
  6. #endif // CONFIG
  7. #include CONFIG
  8. #include "helpers.h"
  9. #include "wintap.h"
  10. #ifndef NO_TAP
  11. #include "types.h"
  12. #include "endian.h"
  13. #include "output.h"
  14. #include "tap-windows.h"
  15. #include <iphlpapi.h>
  16. #if !_WIN32
  17. #include <arpa/inet.h>
  18. #endif // !_WIN32
  19. static char* szIpAddress = "10.10.10.9";
  20. static char* szMask = "30";
  21. static char* szTapName;
  22. static char *ActiveTapName, *AdapterClass;
  23. static char* szLeaseDuration = "1d";
  24. static uint32_t IpAddress, Mask, Network, Broadcast, DhcpServer; // These are host-endian (=little-endian) for easier calculations
  25. static uint32_t Mtu;
  26. static uint_fast8_t Cidr;
  27. static HANDLE TapHandle;
  28. static TapDriverVersion_t DriverVersion;
  29. static IpPacket_t* IpPacket;
  30. static uint32_t DhcpLeaseDuration;
  31. static BOOL isAddressAssigned()
  32. {
  33. PMIB_IPADDRTABLE pIPAddrTable;
  34. DWORD dwSize = 0;
  35. BOOL result = FALSE;
  36. pIPAddrTable = (PMIB_IPADDRTABLE)vlmcsd_malloc(sizeof(MIB_IPADDRTABLE));
  37. DWORD status = GetIpAddrTable(pIPAddrTable, &dwSize, 0);
  38. free(pIPAddrTable);
  39. if (status != ERROR_INSUFFICIENT_BUFFER) return FALSE;
  40. pIPAddrTable = (MIB_IPADDRTABLE *)vlmcsd_malloc(dwSize);
  41. if (GetIpAddrTable(pIPAddrTable, &dwSize, 0))
  42. {
  43. free(pIPAddrTable);
  44. return FALSE;
  45. }
  46. PMIB_IPADDRROW row;
  47. for (row = pIPAddrTable->table; row < pIPAddrTable->table + pIPAddrTable->dwNumEntries; row++)
  48. {
  49. if (
  50. row->dwAddr == BE32(IpAddress) &&
  51. !(row->wType & (MIB_IPADDR_DELETED | MIB_IPADDR_DISCONNECTED | MIB_IPADDR_TRANSIENT))
  52. )
  53. {
  54. result = TRUE;
  55. break;
  56. }
  57. }
  58. free(pIPAddrTable);
  59. return result;
  60. }
  61. static void parseTapArgument(char* argument)
  62. {
  63. char* equalsignPosition = strchr(argument, (int)'=');
  64. char* slashPosition = strchr(argument, (int)'/');
  65. char* colonPosition = strchr(argument, (int)':');
  66. szTapName = argument;
  67. if (equalsignPosition)
  68. {
  69. *equalsignPosition = 0;
  70. szIpAddress = equalsignPosition + 1;
  71. }
  72. if (slashPosition)
  73. {
  74. *slashPosition = 0;
  75. szMask = slashPosition + 1;
  76. }
  77. if (colonPosition)
  78. {
  79. *colonPosition = 0;
  80. szLeaseDuration = colonPosition + 1;
  81. }
  82. IpAddress = BE32(inet_addr(szIpAddress));
  83. if (IpAddress == BE32(INADDR_NONE))
  84. {
  85. printerrorf("Fatal: %s is not a valid IPv4 address\n", szIpAddress);
  86. exit(VLMCSD_EINVAL);
  87. }
  88. char* next;
  89. Cidr = (uint8_t)strtol(szMask, &next, 10);
  90. if (*next || Cidr < 8 || Cidr > 30)
  91. {
  92. printerrorf("Fatal: /%s is not a valid CIDR mask between /8 and /30\n", szMask);
  93. exit(VLMCSD_EINVAL);
  94. }
  95. if (!((DhcpLeaseDuration = timeSpanString2Seconds(szLeaseDuration))))
  96. {
  97. printerrorf("Fatal: No valid time span specified in option -%c.\n", 'O');
  98. exit(VLMCSD_EINVAL);
  99. }
  100. Mask = (uint32_t)~(0xffffffff >> Cidr);
  101. Network = IpAddress & Mask;
  102. Broadcast = IpAddress | ~Mask;
  103. DhcpServer = IpAddress + 1;
  104. if (IpAddress <= Network || IpAddress + 1 >= Broadcast)
  105. {
  106. uint32_t lowerIpBE = BE32(Network + 1);
  107. uint32_t upperIpBE = BE32(Broadcast - 2);
  108. const char* szLower = vlmcsd_strdup(inet_ntoa(*(struct in_addr*)&lowerIpBE));
  109. const char* szUpper = vlmcsd_strdup(inet_ntoa(*(struct in_addr*)&upperIpBE));
  110. printerrorf("Fatal: For this subnet the IPv4 address must be ");
  111. if (lowerIpBE == upperIpBE)
  112. {
  113. printerrorf("%s\n", szLower);
  114. }
  115. else
  116. {
  117. printerrorf("between %s and %s\n", szLower, szUpper);
  118. }
  119. exit(VLMCSD_EINVAL);
  120. }
  121. }
  122. __noreturn static void WinErrorExit(DWORD error)
  123. {
  124. printerrorf("Registry read error: %s\n", win_strerror((int)error));
  125. exit(error);
  126. }
  127. static HANDLE OpenTapHandle()
  128. {
  129. HANDLE handle = INVALID_HANDLE_VALUE;
  130. HKEY regAdapterKey;
  131. DWORD regResult;
  132. if ((regResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, ADAPTER_KEY, 0, KEY_READ | KEY_WOW64_64KEY, &regAdapterKey)) != ERROR_SUCCESS)
  133. {
  134. WinErrorExit(regResult);
  135. }
  136. char subkeyName[TAP_REGISTRY_DATA_SIZE];
  137. DWORD i, subKeySize = sizeof(subkeyName);
  138. for (i = 0; (regResult = RegEnumKeyEx(regAdapterKey, i, subkeyName, &subKeySize, NULL, NULL, NULL, NULL)) != ERROR_NO_MORE_ITEMS; i++)
  139. {
  140. HKEY regSubKey;
  141. DWORD type, regDataSize;
  142. char regData[TAP_REGISTRY_DATA_SIZE];
  143. if (regResult) WinErrorExit(regResult);
  144. if ((regResult = RegOpenKeyEx(regAdapterKey, subkeyName, 0, KEY_READ | KEY_WOW64_64KEY, &regSubKey)) == ERROR_SUCCESS)
  145. {
  146. regDataSize = sizeof(regData);
  147. if (RegQueryValueEx(regSubKey, "ComponentId", NULL, &type, (LPBYTE)regData, &regDataSize) == ERROR_SUCCESS)
  148. {
  149. if (
  150. type == REG_SZ &&
  151. (
  152. !strncmp(regData, "tap0801", sizeof(regData)) ||
  153. !strncmp(regData, "tap0901", sizeof(regData)) ||
  154. !strncmp(regData, "TEAMVIEWERVPN", sizeof(regData))
  155. )
  156. )
  157. {
  158. AdapterClass = vlmcsd_strdup(regData);
  159. regDataSize = sizeof(regData);
  160. if (RegQueryValueEx(regSubKey, "NetCfgInstanceId", NULL, &type, (LPBYTE)regData, &regDataSize) == ERROR_SUCCESS && type == REG_SZ)
  161. {
  162. HKEY connectionKey;
  163. char connectionKeyName[TAP_REGISTRY_DATA_SIZE];
  164. strncpy(connectionKeyName, NETWORK_CONNECTIONS_KEY "\\", sizeof(connectionKeyName));
  165. strncat(connectionKeyName, regData, sizeof(connectionKeyName));
  166. strncat(connectionKeyName, "\\Connection", sizeof(connectionKeyName));
  167. if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, connectionKeyName, 0, KEY_READ | KEY_WOW64_64KEY, &connectionKey) == ERROR_SUCCESS)
  168. {
  169. char deviceName[TAP_REGISTRY_DATA_SIZE];
  170. regDataSize = sizeof(deviceName);
  171. if (RegQueryValueEx(connectionKey, "Name", NULL, &type, (LPBYTE)deviceName, &regDataSize) == ERROR_SUCCESS && type == REG_SZ)
  172. {
  173. if (!strcmp(szTapName, ".") || !strncasecmp(szTapName, deviceName, sizeof(deviceName)))
  174. {
  175. ActiveTapName = vlmcsd_strdup(deviceName);
  176. strncpy(deviceName, USERMODEDEVICEDIR, sizeof(deviceName));
  177. strncat(deviceName, regData, sizeof(deviceName));
  178. strncat(deviceName, strcmp(AdapterClass, "TEAMVIEWERVPN") ? TAP_WIN_SUFFIX : ".dgt", sizeof(deviceName));
  179. handle = CreateFile(deviceName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM, NULL);
  180. }
  181. }
  182. }
  183. RegCloseKey(connectionKey);
  184. }
  185. if (handle == INVALID_HANDLE_VALUE) free(AdapterClass);
  186. }
  187. }
  188. }
  189. RegCloseKey(regSubKey);
  190. subKeySize = sizeof(subkeyName);
  191. if (handle != INVALID_HANDLE_VALUE) break;
  192. }
  193. RegCloseKey(regAdapterKey);
  194. if (handle == INVALID_HANDLE_VALUE)
  195. {
  196. printerrorf("Fatal: No compatible VPN adapter");
  197. if (!strcmp(szTapName, "."))
  198. {
  199. printerrorf("s");
  200. }
  201. else
  202. {
  203. printerrorf(" with name \"%s\"", szTapName);
  204. }
  205. printerrorf(" available for use\n");
  206. exit(ERROR_DEVICE_NOT_AVAILABLE);
  207. }
  208. return handle;
  209. }
  210. static int DevCtl(DWORD code, void* data, DWORD len)
  211. {
  212. if (!DeviceIoControl(TapHandle, code, data, len, data, len, &len, NULL))
  213. {
  214. DWORD error = GetLastError();
  215. printerrorf("Fatal: VPN adapter error: %s\n", win_strerror(error));
  216. exit(error);
  217. }
  218. return len;
  219. }
  220. static DWORD WINAPI TapMirror(LPVOID data_unused)
  221. {
  222. while (TRUE)
  223. {
  224. DWORD bytesRead, bytesWritten;
  225. if (!ReadFile(TapHandle, IpPacket, Mtu, &bytesRead, NULL)) break;
  226. uint32_t temp = IpPacket->ip_src;
  227. IpPacket->ip_src = IpPacket->ip_dst;
  228. IpPacket->ip_dst = temp;
  229. if (!WriteFile(TapHandle, IpPacket, bytesRead, &bytesWritten, NULL)) break;
  230. # if !defined(NO_LOG) && defined(_PEDANTIC)
  231. if (bytesRead != bytesWritten) logger("Warning: VPN device \"%s\": %u bytes could not be written\n", ActiveTapName, bytesRead - bytesWritten);
  232. # endif // !defined(NO_LOG) && defined(_PEDANTIC)
  233. }
  234. DWORD error = GetLastError();
  235. # ifndef NO_LOG
  236. logger("Warning: VPN thread for device \"%s\" exiting: %s\n", ActiveTapName, win_strerror(error));
  237. # endif // NO_LOG
  238. free(ActiveTapName);
  239. CloseHandle(TapHandle);
  240. exitOnWarningLevel(1);
  241. return error;
  242. }
  243. void startTap(char* const argument)
  244. {
  245. if (!strcmp(argument, "-")) return;
  246. parseTapArgument(argument);
  247. TapHandle = OpenTapHandle();
  248. // Get MTU and driver version
  249. DevCtl(TAP_WIN_IOCTL_GET_MTU, &Mtu, sizeof(Mtu));
  250. DevCtl(TAP_WIN_IOCTL_GET_VERSION, &DriverVersion, sizeof(DriverVersion));
  251. // Configure TUN mode
  252. TapConfigTun_t tapTunCfg;
  253. tapTunCfg.Address.s_addr = BE32(IpAddress);
  254. tapTunCfg.Network.s_addr = BE32(Network);
  255. tapTunCfg.Mask.s_addr = BE32(Mask);
  256. DevCtl(TAP_WIN_IOCTL_CONFIG_TUN, &tapTunCfg, sizeof(tapTunCfg));
  257. // Setup the drivers internal DHCP server
  258. TapConfigDhcp_t tapDhcpCfg;
  259. tapDhcpCfg.Address.s_addr = BE32(IpAddress);
  260. tapDhcpCfg.Mask.s_addr = BE32(Mask);
  261. tapDhcpCfg.DhcpServer.s_addr = BE32(IpAddress + 1);
  262. tapDhcpCfg.LeaseDuration = DhcpLeaseDuration;
  263. DevCtl(TAP_WIN_IOCTL_CONFIG_DHCP_MASQ, &tapDhcpCfg, sizeof(tapDhcpCfg));
  264. // Connect the virtual network cable
  265. BOOL isCableConnected = TRUE;
  266. DevCtl(TAP_WIN_IOCTL_SET_MEDIA_STATUS, &isCableConnected, sizeof(isCableConnected));
  267. // Allocate buffer and start mirror thread
  268. IpPacket = (IpPacket_t*)vlmcsd_malloc(Mtu);
  269. HANDLE threadHandle = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)TapMirror, NULL, 0, NULL);
  270. if (!threadHandle)
  271. {
  272. DWORD error = GetLastError();
  273. printerrorf("Fatal: Unable to start VPN thread: %s\n", win_strerror(error));
  274. exit(error);
  275. }
  276. CloseHandle(threadHandle);
  277. # ifndef NO_LOG
  278. logger("%s %u.%u.%u device \"%s\" started\n", AdapterClass, DriverVersion.Major, DriverVersion.Minor, DriverVersion.Build, ActiveTapName);
  279. # endif // NO_LOG
  280. DWORD i;
  281. BOOL isAssigned;
  282. // Wait up to 4 seconds until the IP address is up and running
  283. // so vlmcsd can actually bind to and listen on it
  284. for (i = 0; !((isAssigned = isAddressAssigned())) && i < 20; i++) Sleep(200);
  285. if (!isAssigned)
  286. {
  287. printerrorf("Warning: IPv4 address %s not assigned\n", szIpAddress);
  288. }
  289. else
  290. {
  291. # ifndef NO_LOG
  292. logger("IPv4 address %s assigned\n", szIpAddress);
  293. # endif // NO_LOG
  294. }
  295. }
  296. #endif // NO_TAP