TAPDevice.c 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  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 <http://www.gnu.org/licenses/>.
  14. */
  15. #include "util/Bits.h"
  16. #include "exception/Except.h"
  17. #include "exception/WinFail.h"
  18. #include "memory/Allocator.h"
  19. #include "interface/tuntap/windows/TAPDevice.h"
  20. #include "util/CString.h"
  21. /*
  22. * Portions of this code are copied from QEMU project which is licensed
  23. * under GPLv2 or greater, further contributions are licensed under GPLv3
  24. * or greater.
  25. */
  26. /*
  27. * TAP-Win32 -- A kernel driver to provide virtual tap device functionality
  28. * on win32. Originally derived from the CIPE-Win32
  29. * project by Damion K. Wilson, with extensive modifications by
  30. * James Yonan.
  31. *
  32. * All source code which derives from the CIPE-Win32 project is
  33. * Copyright (C) Damion K. Wilson, 2003, and is released under the
  34. * GPL version 2 (see below).
  35. *
  36. * All other source code is Copyright (C) James Yonan, 2003-2004,
  37. * and is released under the GPL version 2 (see below).
  38. *
  39. * This program is free software; you can redistribute it and/or modify
  40. * it under the terms of the GNU General Public License as published by
  41. * the Free Software Foundation; either version 2 of the License, or
  42. * (at your option) any later version.
  43. *
  44. * This program is distributed in the hope that it will be useful,
  45. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  46. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  47. * GNU General Public License for more details.
  48. *
  49. * You should have received a copy of the GNU General Public License
  50. * along with this program (see the file COPYING included with this
  51. * distribution); if not, write to the Free Software Foundation, Inc.,
  52. * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  53. */
  54. #include <stdio.h>
  55. #include <windows.h>
  56. #define NETWORK_ADAPTER_GUID "{4D36E972-E325-11CE-BFC1-08002BE10318}"
  57. #define ADAPTER_KEY \
  58. "SYSTEM\\CurrentControlSet\\Control\\Class\\" NETWORK_ADAPTER_GUID
  59. #define NETWORK_CONNECTIONS_KEY \
  60. "SYSTEM\\CurrentControlSet\\Control\\Network\\" NETWORK_ADAPTER_GUID
  61. #define USERMODEDEVICEDIR "\\\\.\\Global\\"
  62. #define TAPSUFFIX ".tap"
  63. static int is_tap_win32_dev(const char *guid)
  64. {
  65. HKEY netcard_key;
  66. LONG status;
  67. DWORD len;
  68. int i = 0;
  69. status = RegOpenKeyEx(
  70. HKEY_LOCAL_MACHINE,
  71. ADAPTER_KEY,
  72. 0,
  73. KEY_READ,
  74. &netcard_key);
  75. if (status != ERROR_SUCCESS) {
  76. return FALSE;
  77. }
  78. for (;;) {
  79. char enum_name[256];
  80. char unit_string[256];
  81. HKEY unit_key;
  82. char component_id_string[] = "ComponentId";
  83. char component_id[256];
  84. char net_cfg_instance_id_string[] = "NetCfgInstanceId";
  85. char net_cfg_instance_id[256];
  86. DWORD data_type;
  87. len = sizeof (enum_name);
  88. status = RegEnumKeyEx(
  89. netcard_key,
  90. i,
  91. enum_name,
  92. &len,
  93. NULL,
  94. NULL,
  95. NULL,
  96. NULL);
  97. if (status == ERROR_NO_MORE_ITEMS) {
  98. break;
  99. } else if (status != ERROR_SUCCESS) {
  100. return FALSE;
  101. }
  102. snprintf (unit_string, sizeof(unit_string), "%s\\%s",
  103. ADAPTER_KEY, enum_name);
  104. status = RegOpenKeyEx(
  105. HKEY_LOCAL_MACHINE,
  106. unit_string,
  107. 0,
  108. KEY_READ,
  109. &unit_key);
  110. if (status != ERROR_SUCCESS) {
  111. return FALSE;
  112. } else {
  113. len = sizeof (component_id);
  114. status = RegQueryValueEx(
  115. unit_key,
  116. component_id_string,
  117. NULL,
  118. &data_type,
  119. (uint8_t*)component_id,
  120. &len);
  121. if (!(status != ERROR_SUCCESS || data_type != REG_SZ)) {
  122. len = sizeof (net_cfg_instance_id);
  123. status = RegQueryValueEx(
  124. unit_key,
  125. net_cfg_instance_id_string,
  126. NULL,
  127. &data_type,
  128. (uint8_t*)net_cfg_instance_id,
  129. &len);
  130. if (status == ERROR_SUCCESS && data_type == REG_SZ) {
  131. if (!Bits_memcmp(component_id, "tap", CString_strlen("tap")) &&
  132. !strcmp (net_cfg_instance_id, guid)) {
  133. RegCloseKey (unit_key);
  134. RegCloseKey (netcard_key);
  135. return TRUE;
  136. }
  137. }
  138. }
  139. RegCloseKey (unit_key);
  140. }
  141. ++i;
  142. }
  143. RegCloseKey (netcard_key);
  144. return FALSE;
  145. }
  146. static int get_device_guid(
  147. char *name,
  148. int name_size,
  149. char *actual_name,
  150. int actual_name_size,
  151. struct Except* eh)
  152. {
  153. LONG status;
  154. HKEY control_net_key;
  155. DWORD len;
  156. WinFail_check(eh, (
  157. RegOpenKeyEx(HKEY_LOCAL_MACHINE, NETWORK_CONNECTIONS_KEY, 0, KEY_READ, &control_net_key)
  158. ));
  159. int stop = 0;
  160. for (int i = 0; !stop; i++) {
  161. char enum_name[256];
  162. char connection_string[256];
  163. HKEY connKey;
  164. char name_data[256];
  165. DWORD name_type;
  166. const char name_string[] = "Name";
  167. len = sizeof (enum_name);
  168. status = RegEnumKeyEx(control_net_key, i, enum_name, &len, NULL, NULL, NULL, NULL);
  169. if (status == ERROR_NO_MORE_ITEMS) {
  170. break;
  171. } else if (status != ERROR_SUCCESS) {
  172. WinFail_fail(eh, "RegEnumKeyEx() failed", status);
  173. }
  174. if (len != CString_strlen(NETWORK_ADAPTER_GUID)) {
  175. // extranious directory, eg: "Descriptions"
  176. continue;
  177. }
  178. snprintf(connection_string,
  179. sizeof(connection_string),
  180. "%s\\%s\\Connection",
  181. NETWORK_CONNECTIONS_KEY, enum_name);
  182. WinFail_check(eh, (
  183. RegOpenKeyEx(HKEY_LOCAL_MACHINE, connection_string, 0, KEY_READ, &connKey)
  184. ));
  185. len = sizeof (name_data);
  186. WinFail_check(eh, (
  187. RegQueryValueEx(connKey, name_string, NULL, &name_type, (uint8_t*)name_data, &len)
  188. ));
  189. if (name_type != REG_SZ) {
  190. WinFail_fail(eh, "RegQueryValueEx() name_type != REG_SZ", status);
  191. }
  192. if (is_tap_win32_dev(enum_name)) {
  193. snprintf(name, name_size, "%s", enum_name);
  194. if (actual_name) {
  195. if (CString_strcmp(actual_name, "") != 0) {
  196. if (CString_strcmp(name_data, actual_name) != 0) {
  197. RegCloseKey (connKey);
  198. ++i;
  199. continue;
  200. }
  201. }
  202. else {
  203. snprintf(actual_name, actual_name_size, "%s", name_data);
  204. }
  205. }
  206. stop = 1;
  207. }
  208. RegCloseKey(connKey);
  209. }
  210. RegCloseKey (control_net_key);
  211. if (stop == 0) {
  212. return -1;
  213. }
  214. return 0;
  215. }
  216. struct TAPDevice* TAPDevice_find(const char* preferredName,
  217. struct Except* eh,
  218. struct Allocator* alloc)
  219. {
  220. #define BUFF_SZ 0x100
  221. char guid[BUFF_SZ] = {0};
  222. char buff[BUFF_SZ] = {0};
  223. if (preferredName != NULL) {
  224. snprintf(buff, sizeof(buff), "%s", preferredName);
  225. }
  226. if (get_device_guid(guid, sizeof(guid), buff, sizeof(buff), eh)) {
  227. return NULL;
  228. }
  229. struct TAPDevice* out = Allocator_malloc(alloc, sizeof(struct TAPDevice));
  230. out->name = Allocator_malloc(alloc, CString_strlen(buff)+1);
  231. Bits_memcpy(out->name, buff, CString_strlen(buff)+1);
  232. snprintf(buff, sizeof(buff), USERMODEDEVICEDIR "%s" TAPSUFFIX, guid);
  233. out->path = Allocator_malloc(alloc, CString_strlen(buff)+1);
  234. Bits_memcpy(out->path, buff, CString_strlen(buff)+1);
  235. return out;
  236. }