TAPDevice.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
  1. /* vim: set expandtab ts=4 sw=4: */
  2. /*
  3. * You may redistribute this program and/or modify it under the terms of
  4. * the GNU General Public License as published by the Free Software Foundation,
  5. * either version 3 of the License, or (at your option) any later version.
  6. *
  7. * This program is distributed in the hope that it will be useful,
  8. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. * GNU General Public License for more details.
  11. *
  12. * You should have received a copy of the GNU General Public License
  13. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  14. */
  15. #include <stdbool.h>
  16. #include "util/Bits.h"
  17. #include "exception/Er.h"
  18. #include "exception/WinEr.h"
  19. #include "memory/Allocator.h"
  20. #include "interface/tuntap/windows/TAPDevice.h"
  21. #include "util/CString.h"
  22. /*
  23. * Portions of this code are copied from QEMU project which is licensed
  24. * under GPLv2 or greater, further contributions are licensed under GPLv3
  25. * or greater.
  26. */
  27. /*
  28. * TAP-Win32 -- A kernel driver to provide virtual tap device functionality
  29. * on win32. Originally derived from the CIPE-Win32
  30. * project by Damion K. Wilson, with extensive modifications by
  31. * James Yonan.
  32. *
  33. * All source code which derives from the CIPE-Win32 project is
  34. * Copyright (C) Damion K. Wilson, 2003, and is released under the
  35. * GPL version 2 (see below).
  36. *
  37. * All other source code is Copyright (C) James Yonan, 2003-2004,
  38. * and is released under the GPL version 2 (see below).
  39. *
  40. * This program is free software; you can redistribute it and/or modify
  41. * it under the terms of the GNU General Public License as published by
  42. * the Free Software Foundation; either version 2 of the License, or
  43. * (at your option) any later version.
  44. *
  45. * This program is distributed in the hope that it will be useful,
  46. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  47. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  48. * GNU General Public License for more details.
  49. *
  50. * You should have received a copy of the GNU General Public License
  51. * along with this program (see the file COPYING included with this
  52. * distribution); if not, write to the Free Software Foundation, Inc.,
  53. * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  54. */
  55. #include "util/CString.h"
  56. #include <stdio.h>
  57. #include <windows.h>
  58. #define NETWORK_ADAPTER_GUID "{4D36E972-E325-11CE-BFC1-08002BE10318}"
  59. #define ADAPTER_KEY \
  60. "SYSTEM\\CurrentControlSet\\Control\\Class\\" NETWORK_ADAPTER_GUID
  61. #define NETWORK_CONNECTIONS_KEY \
  62. "SYSTEM\\CurrentControlSet\\Control\\Network\\" NETWORK_ADAPTER_GUID
  63. #define USERMODEDEVICEDIR "\\\\.\\Global\\"
  64. #define TAPSUFFIX ".tap"
  65. #define BUFF_SZ 0x100
  66. struct Taps
  67. {
  68. char guid[BUFF_SZ];
  69. char name[BUFF_SZ];
  70. struct Taps* next;
  71. };
  72. static int is_tap_win32_dev(const char *guid)
  73. {
  74. HKEY netcard_key;
  75. LONG status;
  76. DWORD len;
  77. int i = 0;
  78. status = RegOpenKeyEx(
  79. HKEY_LOCAL_MACHINE,
  80. ADAPTER_KEY,
  81. 0,
  82. KEY_READ,
  83. &netcard_key);
  84. if (status != ERROR_SUCCESS) {
  85. return FALSE;
  86. }
  87. for (;;) {
  88. char enum_name[256];
  89. char unit_string[256];
  90. HKEY unit_key;
  91. char component_id_string[] = "ComponentId";
  92. char component_id[256];
  93. char net_cfg_instance_id_string[] = "NetCfgInstanceId";
  94. char net_cfg_instance_id[256];
  95. DWORD data_type;
  96. len = sizeof (enum_name);
  97. status = RegEnumKeyEx(
  98. netcard_key,
  99. i,
  100. enum_name,
  101. &len,
  102. NULL,
  103. NULL,
  104. NULL,
  105. NULL);
  106. if (status == ERROR_NO_MORE_ITEMS) {
  107. break;
  108. } else if (status != ERROR_SUCCESS) {
  109. return FALSE;
  110. }
  111. snprintf (unit_string, sizeof(unit_string), "%s\\%s",
  112. ADAPTER_KEY, enum_name);
  113. status = RegOpenKeyEx(
  114. HKEY_LOCAL_MACHINE,
  115. unit_string,
  116. 0,
  117. KEY_READ,
  118. &unit_key);
  119. if (status != ERROR_SUCCESS) {
  120. return FALSE;
  121. } else {
  122. len = sizeof (component_id);
  123. status = RegQueryValueEx(
  124. unit_key,
  125. component_id_string,
  126. NULL,
  127. &data_type,
  128. (uint8_t*)component_id,
  129. &len);
  130. if (!(status != ERROR_SUCCESS || data_type != REG_SZ)) {
  131. len = sizeof (net_cfg_instance_id);
  132. status = RegQueryValueEx(
  133. unit_key,
  134. net_cfg_instance_id_string,
  135. NULL,
  136. &data_type,
  137. (uint8_t*)net_cfg_instance_id,
  138. &len);
  139. if (status == ERROR_SUCCESS && data_type == REG_SZ) {
  140. if (!Bits_memcmp(component_id, "tap", CString_strlen("tap")) &&
  141. !strcmp (net_cfg_instance_id, guid)) {
  142. RegCloseKey (unit_key);
  143. RegCloseKey (netcard_key);
  144. return TRUE;
  145. }
  146. }
  147. }
  148. RegCloseKey (unit_key);
  149. }
  150. ++i;
  151. }
  152. RegCloseKey (netcard_key);
  153. return FALSE;
  154. }
  155. static Er_DEFUN(struct Taps* get_all_taps(struct Allocator* alloc))
  156. {
  157. LONG status;
  158. HKEY control_net_key;
  159. DWORD len;
  160. struct Taps* taps = NULL;
  161. struct Taps* tail = NULL;
  162. WinEr_check(alloc, (
  163. RegOpenKeyEx(HKEY_LOCAL_MACHINE, NETWORK_CONNECTIONS_KEY, 0, KEY_READ, &control_net_key)
  164. ));
  165. int i = 0;
  166. char enum_name[BUFF_SZ];
  167. char connection_string[BUFF_SZ];
  168. char name_data[BUFF_SZ];
  169. const char name_string[] = "Name";
  170. while (true) {
  171. HKEY connKey;
  172. DWORD name_type;
  173. Bits_memset(enum_name, 0, sizeof(enum_name));
  174. Bits_memset(connection_string, 0, sizeof(connection_string));
  175. Bits_memset(name_data, 0, sizeof(name_data));
  176. len = sizeof (enum_name);
  177. status = RegEnumKeyEx(control_net_key, i, enum_name, &len, NULL, NULL, NULL, NULL);
  178. if (status == ERROR_NO_MORE_ITEMS) {
  179. break;
  180. } else if (status != ERROR_SUCCESS) {
  181. WinEr_fail(alloc, "RegEnumKeyEx() failed", status);
  182. }
  183. if (len != CString_strlen(NETWORK_ADAPTER_GUID)) {
  184. // extranious directory, eg: "Descriptions"
  185. ++i;
  186. continue;
  187. }
  188. snprintf(connection_string,
  189. sizeof(connection_string),
  190. "%s\\%s\\Connection",
  191. NETWORK_CONNECTIONS_KEY, enum_name);
  192. WinEr_check(alloc, (
  193. RegOpenKeyEx(HKEY_LOCAL_MACHINE, connection_string, 0, KEY_READ, &connKey)
  194. ));
  195. // In Windows 10, some interface keys don't have names. We should keep
  196. // going and treat those interfaces as having empty string names.
  197. len = sizeof (name_data);
  198. status = RegQueryValueEx(connKey, name_string, NULL, &name_type,
  199. (uint8_t*)name_data, &len);
  200. if (status == ERROR_FILE_NOT_FOUND) {
  201. // The interface has no name.
  202. CString_safeStrncpy(name_data, "", sizeof (name_data));
  203. } else if (status != ERROR_SUCCESS) {
  204. WinEr_fail(alloc, "RegQueryValueEx() for interface name failed", status);
  205. } else {
  206. if (name_type != REG_SZ) {
  207. // Someone named an interface with a non-string
  208. WinEr_fail(alloc, "RegQueryValueEx() name_type != REG_SZ", status);
  209. }
  210. }
  211. if (is_tap_win32_dev(enum_name)) {
  212. struct Taps* tap = Allocator_calloc(alloc, sizeof(struct Taps), 1);
  213. Bits_memcpy(tap->guid, enum_name, sizeof(enum_name));
  214. Bits_memcpy(tap->name, name_data, sizeof(name_data));
  215. if (!taps) {
  216. taps = tap;
  217. taps->next = NULL;
  218. }
  219. if (tail) {
  220. tail->next = tap;
  221. }
  222. tail = tap;
  223. }
  224. RegCloseKey(connKey);
  225. ++i;
  226. }
  227. RegCloseKey (control_net_key);
  228. Er_ret(taps);
  229. }
  230. static Er_DEFUN(int get_device_guid(char *name,
  231. int name_size,
  232. char *actual_name,
  233. int actual_name_size,
  234. struct Allocator* alloc))
  235. {
  236. char buff[BUFF_SZ] = {0};
  237. HANDLE handle;
  238. struct Taps* taps = Er(get_all_taps(alloc));
  239. while (taps) {
  240. if (actual_name && CString_strcmp(actual_name, "") != 0) {
  241. if (CString_strcmp(taps->name, actual_name) != 0) {
  242. taps = taps->next;
  243. continue;
  244. }
  245. }
  246. snprintf(buff, sizeof(buff), USERMODEDEVICEDIR "%s" TAPSUFFIX, taps->guid);
  247. handle = CreateFile(buff,
  248. GENERIC_READ | GENERIC_WRITE,
  249. 0,
  250. 0,
  251. OPEN_EXISTING,
  252. FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED,
  253. 0);
  254. if (handle != INVALID_HANDLE_VALUE) {
  255. snprintf(name, name_size, "%s", taps->guid);
  256. if (actual_name && CString_strcmp(actual_name, "") == 0) {
  257. snprintf(actual_name, actual_name_size, "%s", taps->name);
  258. }
  259. CloseHandle(handle);
  260. Er_ret(0);
  261. }
  262. taps = taps->next;
  263. }
  264. Er_ret(-1);
  265. }
  266. Er_DEFUN(struct TAPDevice* TAPDevice_find(const char* preferredName,
  267. struct Allocator* alloc))
  268. {
  269. char guid[BUFF_SZ] = {0};
  270. char buff[BUFF_SZ] = {0};
  271. if (preferredName != NULL) {
  272. snprintf(buff, sizeof(buff), "%s", preferredName);
  273. }
  274. int ret = Er(get_device_guid(guid, sizeof(guid), buff, sizeof(buff), alloc));
  275. if (ret) {
  276. Er_ret(NULL);
  277. }
  278. struct TAPDevice* out = Allocator_malloc(alloc, sizeof(struct TAPDevice));
  279. out->name = Allocator_malloc(alloc, CString_strlen(buff)+1);
  280. Bits_memcpy(out->name, buff, CString_strlen(buff)+1);
  281. snprintf(buff, sizeof(buff), USERMODEDEVICEDIR "%s" TAPSUFFIX, guid);
  282. out->path = Allocator_malloc(alloc, CString_strlen(buff)+1);
  283. Bits_memcpy(out->path, buff, CString_strlen(buff)+1);
  284. Er_ret(out);
  285. }