34#pragma comment(lib, "ole32.lib")
35#pragma comment(lib, "setupapi.lib")
41 _L(PACKAGE_NAME) L
" " _L(PACKAGE_VERSION)
49 L
"tapctl <command> [<command specific options>]\n"
53 L
"create Create a new VPN network adapter\n"
54 L
"list List VPN network adapters\n"
55 L
"delete Delete specified VPN network adapter\n"
56 L
"help Display this text\n"
58 L
"Hint: Use \"tapctl help <command>\" to display help for particular command.\n"
64 L
"Creates a new VPN network adapter\n"
68 L
"tapctl create [<options>]\n"
72 L
"--name <name> Set VPN network adapter name. Should the adapter with given \n"
73 L
" name already exist, an error is returned. If this option is not \n"
74 L
" specified, an OpenVPN-specific default name is chosen. \n"
75 L
" Note: This name can also be specified as OpenVPN's --dev-node \n"
77 L
"--hwid <hwid> Adapter hardware ID. Default value is ovpn-dco, which uses \n"
78 L
" the OpenVPN Data Channel Offload driver. To work with \n"
79 L
" tap-windows6 driver, specify root\\tap0901 or tap0901. \n"
83 L
"This command prints newly created VPN network adapter's GUID, name and \n"
84 L
"hardware ID to stdout. \n"
90 L
"Lists VPN network adapters\n"
98 L
"--hwid <hwid> Adapter hardware ID. By default, root\\tap0901, tap0901 and \n"
99 L
" ovpn-dco adapters are listed. Use this switch to limit the list.\n"
103 L
"This command prints VPN network adapter GUID, name and hardware ID to stdout. \n"
109 L
"Deletes the specified VPN network adapter\n"
113 L
"tapctl delete <adapter GUID | adapter name>\n"
140 if (_wcsicmp(name, a->szName) == 0)
163 static const WCHAR class_key[] =
164 L
"SYSTEM\\CurrentControlSet\\Control\\Network\\{4d36e972-e325-11ce-bfc1-08002be10318}";
166 HKEY hClassKey = NULL;
167 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, class_key, 0, KEY_READ, &hClassKey) != ERROR_SUCCESS)
174 for (DWORD index = 0;; ++index)
176 WCHAR adapter_id[64];
177 DWORD adapter_id_len = _countof(adapter_id);
178 LONG result = RegEnumKeyEx(hClassKey, index, adapter_id, &adapter_id_len, NULL, NULL, NULL,
180 if (result == ERROR_NO_MORE_ITEMS)
184 else if (result != ERROR_SUCCESS)
189 WCHAR connection_key[512];
190 swprintf_s(connection_key, _countof(connection_key), L
"%ls\\%ls\\Connection", class_key,
193 DWORD value_size = 0;
194 LONG query = RegGetValueW(HKEY_LOCAL_MACHINE, connection_key, L
"Name",
195 RRF_RT_REG_SZ | RRF_NOEXPAND, NULL, NULL, &value_size);
196 if (query != ERROR_SUCCESS || value_size <
sizeof(WCHAR))
201 LPWSTR value = (LPWSTR)malloc(value_size);
207 query = RegGetValueW(HKEY_LOCAL_MACHINE, connection_key, L
"Name",
208 RRF_RT_REG_SZ | RRF_NOEXPAND, NULL, value, &value_size);
209 if (query == ERROR_SUCCESS && _wcsicmp(name, value) == 0)
224 RegCloseKey(hClassKey);
268 size_t length = wcslen(name);
269 if (length == 0 || length > 255)
274 static const WCHAR invalid_chars[] = L
"\\/:*?\"<>|";
276 for (
const WCHAR *p = name; *p; ++p)
283 if (wcschr(invalid_chars, ch))
309 if (requested_name && requested_name[0])
314 L
"Adapter name \"%ls\" contains invalid characters. Avoid tabs or the "
315 L
"characters \\ / : * ? \" < > | and keep the length within 255 characters.\n",
323 LPOLESTR adapter_id = NULL;
324 StringFromIID((REFIID)&conflict->
guid, &adapter_id);
326 L
"Adapter \"%ls\" already exists (GUID %"
328 conflict->
szName, adapter_id);
329 CoTaskMemFree(adapter_id);
335 fwprintf(stderr, L
"Adapter name \"%ls\" is already in use.\n", requested_name);
339 return wcsdup(requested_name);
347 LPCWSTR base_name = NULL;
348 if (_wcsicmp(hwid, L
"ovpn-dco") == 0)
350 base_name = L
"OpenVPN Data Channel Offload";
352 else if (_wcsicmp(hwid, L
"root\\" _L(TAP_WIN_COMPONENT_ID)) == 0
353 || _wcsicmp(hwid,
_L(TAP_WIN_COMPONENT_ID)) == 0)
355 base_name = L
"OpenVPN TAP-Windows6";
360 L
"Cannot auto-generate adapter name for hardware ID \"%ls\".\n", hwid);
366 return wcsdup(base_name);
369 size_t name_len = wcslen(base_name) + 10;
370 LPWSTR name = (LPWSTR)malloc(name_len *
sizeof(WCHAR));
377 for (
int i = 2; i < 100; ++i)
379 swprintf_s(name, name_len, L
"%ls #%d", base_name, i);
388 fwprintf(stderr, L
"Unable to find available adapter name based on \"%ls\".\n", base_name);
396 LPCWSTR defaultHwId = L
"ovpn-dco";
397 LPCWSTR szHwId = defaultHwId;
398 LPWSTR adapter_name = NULL;
401 LPOLESTR szAdapterId = NULL;
404 BOOL adapter_created = FALSE;
406 for (
int i = 2; i < argc; i++)
408 if (wcsicmp(
argv[i], L
"--name") == 0)
412 fwprintf(stderr, L
"--name option requires a value. Ignored.\n");
418 fwprintf(stderr, L
"--name option cannot be empty. Ignored.\n");
422 else if (wcsicmp(
argv[i], L
"--hwid") == 0)
427 L
"--hwid option requires a value. Using default \"%ls\".\n",
432 if (szHwId[0] == L
'\0')
435 L
"--hwid option cannot be empty. Using default \"%ls\".\n",
437 szHwId = defaultHwId;
443 L
"Unknown option \"%ls"
444 L
"\". Please, use \"tapctl help create\" to list supported options. Ignored.\n",
451 if (dwResult != ERROR_SUCCESS)
453 fwprintf(stderr, L
"Creating network adapter failed (error 0x%x).\n", dwResult);
456 adapter_created = TRUE;
459 if (dwResult != ERROR_SUCCESS)
461 fwprintf(stderr, L
"Enumerating adapters failed (error 0x%x).\n", dwResult);
466 if (adapter_name == NULL)
472 if (dwResult != ERROR_SUCCESS)
474 StringFromIID((REFIID)&guidAdapter, &szAdapterId);
476 L
"Renaming network adapter %ls to \"%ls\" failed (error 0x%x).\n", szAdapterId,
477 adapter_name, dwResult);
478 CoTaskMemFree(szAdapterId);
483 StringFromIID((REFIID)&guidAdapter, &szAdapterId);
484 const WCHAR *name_to_print = (adapter_name && adapter_name[0]) ? adapter_name : L
"(unnamed)";
485 const WCHAR *hwid_to_print = (szHwId && szHwId[0]) ? szHwId : L
"(unknown hwid)";
486 fwprintf(stdout, L
"%ls\t%ls\t%ls\n", szAdapterId, name_to_print, hwid_to_print);
487 CoTaskMemFree(szAdapterId);
496 if (adapter_created && iResult != 0)
507 WCHAR szzHwId[0x100] =
508 L
"root\\" _L(TAP_WIN_COMPONENT_ID) L
"\0" _L(TAP_WIN_COMPONENT_ID) L
"\0"
511 for (
int i = 2; i < argc; i++)
513 if (wcsicmp(
argv[i], L
"--hwid") == 0)
515 memset(szzHwId, 0,
sizeof(szzHwId));
518 sizeof(szzHwId) - 2 *
sizeof(WCHAR),
519 argv[i], wcslen(
argv[i]) *
sizeof(WCHAR));
524 L
"Unknown option \"%ls"
525 L
"\". Please, use \"tapctl help list\" to list supported options. Ignored.\n",
532 if (dwResult != ERROR_SUCCESS)
534 fwprintf(stderr, L
"Enumerating TUN/TAP adapters failed (error 0x%x).\n", dwResult);
540 LPOLESTR adapter_id = NULL;
541 StringFromIID((REFIID)&adapter->guid, &adapter_id);
542 const WCHAR *name = adapter->szName ? adapter->szName : L
"";
543 const WCHAR *hwid = (adapter->szzHardwareIDs && adapter->szzHardwareIDs[0])
544 ? adapter->szzHardwareIDs
546 fwprintf(stdout, L
"%ls\t%ls\t%ls\n", adapter_id, name, hwid);
547 CoTaskMemFree(adapter_id);
561 L
"Missing adapter GUID or name. Please, use \"tapctl help delete\" for usage info.\n");
566 if (FAILED(IIDFromString(
argv[2], (LPIID)&guidAdapter)))
570 if (dwResult != ERROR_SUCCESS)
572 fwprintf(stderr, L
"Enumerating TUN/TAP adapters failed (error 0x%x).\n", dwResult);
579 if (wcsicmp(
argv[2], adapter->szName) == 0)
581 memcpy(&guidAdapter, &adapter->guid,
sizeof(GUID));
591 fwprintf(stderr, L
"\"%ls\" adapter not found.\n",
argv[2]);
597 if (dwResult != ERROR_SUCCESS)
600 L
"Deleting adapter \"%ls"
601 L
"\" failed (error 0x%x).\n",
615 BOOL bRebootRequired = FALSE;
618 SetupSetNonInteractiveMode(TRUE);
625 else if (wcsicmp(
argv[1], L
"help") == 0)
632 else if (wcsicmp(
argv[2], L
"create") == 0)
636 else if (wcsicmp(
argv[2], L
"list") == 0)
640 else if (wcsicmp(
argv[2], L
"delete") == 0)
647 L
"Unknown command \"%ls"
648 L
"\". Please, use \"tapctl help\" to list supported commands.\n",
654 else if (wcsicmp(
argv[1], L
"create") == 0)
659 else if (wcsicmp(
argv[1], L
"list") == 0)
664 else if (wcsicmp(
argv[1], L
"delete") == 0)
672 L
"Unknown command \"%ls"
673 L
"\". Please, use \"tapctl help\" to list supported commands.\n",
681 fwprintf(stderr, L
"A system reboot is required.\n");
691 UNREFERENCED_PARAMETER(flags);
698x_msg_va(
const unsigned int flags,
const char *format, va_list arglist)
701 vfprintf(stderr, format, arglist);
702 fwprintf(stderr, L
"\n");
707 DWORD dwResult = GetLastError();
708 LPWSTR szErrMessage = NULL;
709 if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER
710 | FORMAT_MESSAGE_IGNORE_INSERTS,
711 0, dwResult, 0, (LPWSTR)&szErrMessage, 0, NULL)
716 for (
size_t i = 0, i_last = 0;; i++)
720 if (!iswspace(szErrMessage[i]))
727 szErrMessage[i_last] = 0;
733 fwprintf(stderr, L
"Error 0x%x: %ls\n", dwResult, szErrMessage);
735 LocalFree(szErrMessage);
739 fwprintf(stderr, L
"Error 0x%x\n", dwResult);
int __cdecl wmain(int argc, LPCWSTR argv[])
Program entry point.
static const WCHAR usage_message_delete[]
BOOL tap_is_valid_adapter_name(LPCWSTR name)
Check whether a proposed adapter name satisfies Windows connection-name rules.
static const WCHAR usage_message_list[]
bool dont_mute(unsigned int flags)
Check muting filter.
static int command_list(int argc, LPCWSTR argv[])
static BOOL tap_name_in_use(LPCWSTR name, struct tap_adapter_node *adapter_list)
Determine whether a friendly name is currently in use by an adapter or reserved in the registry.
static LPWSTR tap_resolve_adapter_name(LPCWSTR requested_name, LPCWSTR hwid, struct tap_adapter_node *adapter_list)
Resolve the adapter name we should apply:
static int command_delete(int argc, LPCWSTR argv[], BOOL *bRebootRequired)
void x_msg_va(const unsigned int flags, const char *format, va_list arglist)
static BOOL registry_name_exists(LPCWSTR name)
Check whether the registry still reserves a given network-connection name.
static int command_create(int argc, LPCWSTR argv[], BOOL *bRebootRequired)
const WCHAR title_string[]
static const WCHAR usage_message_create[]
static const WCHAR usage_message[]
static void usage(void)
Print the help message.
static struct tap_adapter_node * find_adapter_by_name(LPCWSTR name, struct tap_adapter_node *adapter_list)
Locate an adapter node by its friendly name within the enumerated list.
Network adapter list node.
struct tap_adapter_node * pNext
Pointer to next adapter.
LPWSTR szName
Adapter name.
DWORD tap_list_adapters(_In_opt_ HWND hwndParent, _In_opt_ LPCWSTR szzHwIDs, _Out_ struct tap_adapter_node **ppAdapter)
Creates a list of existing network adapters.
DWORD tap_set_adapter_name(_In_ LPCGUID pguidAdapter, _In_ LPCWSTR szName, _In_ BOOL bSilent)
Sets adapter name.
DWORD tap_create_adapter(_In_opt_ HWND hwndParent, _In_opt_ LPCWSTR szDeviceDescription, _In_ LPCWSTR szHwId, _Inout_ LPBOOL pbRebootRequired, _Out_ LPGUID pguidAdapter)
Creates a TUN/TAP adapter.
DWORD tap_delete_adapter(_In_opt_ HWND hwndParent, _In_ LPCGUID pguidAdapter, _Inout_ LPBOOL pbRebootRequired)
Deletes an adapter.
void tap_free_adapter_list(_In_ struct tap_adapter_node *pAdapterList)
Frees a list of network adapters.
static int cleanup(void **state)