--- /dev/null
+/*
+ * OpenConnect (SSL + DTLS) VPN client
+ *
+ * Copyright © 2019 David Woodhouse
+ * Copyright © 2024 Marios Paouris
+ *
+ * Authors: David Woodhouse <dwmw2@infradead.org>
+ * Marios Paouris <mspaourh@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * version 2.1, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ */
+
+#include <config.h>
+
+#include <stdint.h>
+#include <stdio.h>
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
+#define __OPENCONNECT_INTERNAL_H__
+
+#define PRG_ERR 0
+#define PRG_INFO 1
+#define PRG_DEBUG 2
+#define PRG_TRACE 3
+
+#define vpn_progress(v, d, ...) do { \
+ if ( d < PRG_TRACE) { \
+ printf(__VA_ARGS__); \
+ } \
+} while (0);
+
+#define _(x) x
+
+struct openconnect_info {
+ char *ifname;
+};
+
+/* don't link linkopenconnect in this test, just for this function
+ * it won't get loaded under wine when cross compiling anyway */
+#define openconnect__win32_strerror(err) "(Actual error text not present in tests)"
+
+#define OPEN_TUN_SOFTFAIL 0
+#define OPEN_TUN_HARDFAIL -1
+
+#define WINTUN_TUNNEL_TYPE L"OpenConnect"
+
+#define VALID_WINTUN_HANDLE 7782
+#define __LIST_TAPS__
+
+#include "../tun-win32.c"
+#include "../wintun.h"
+
+static WINTUN_CREATE_ADAPTER_FUNC *WintunCreateAdapter;
+static WINTUN_CLOSE_ADAPTER_FUNC *WintunCloseAdapter;
+static WINTUN_OPEN_ADAPTER_FUNC *WintunOpenAdapter;
+static WINTUN_GET_ADAPTER_LUID_FUNC *WintunGetAdapterLUID;
+static WINTUN_GET_RUNNING_DRIVER_VERSION_FUNC *WintunGetRunningDriverVersion;
+static WINTUN_DELETE_DRIVER_FUNC *WintunDeleteDriver;
+static WINTUN_SET_LOGGER_FUNC *WintunSetLogger;
+static WINTUN_START_SESSION_FUNC *WintunStartSession;
+static WINTUN_END_SESSION_FUNC *WintunEndSession;
+static WINTUN_GET_READ_WAIT_EVENT_FUNC *WintunGetReadWaitEvent;
+static WINTUN_RECEIVE_PACKET_FUNC *WintunReceivePacket;
+static WINTUN_RELEASE_RECEIVE_PACKET_FUNC *WintunReleaseReceivePacket;
+static WINTUN_ALLOCATE_SEND_PACKET_FUNC *WintunAllocateSendPacket;
+static WINTUN_SEND_PACKET_FUNC *WintunSendPacket;
+
+static HMODULE
+InitializeWintun(void)
+{
+ HMODULE Wintun =
+ LoadLibraryExW(L"wintun.dll", NULL, LOAD_LIBRARY_SEARCH_APPLICATION_DIR | LOAD_LIBRARY_SEARCH_SYSTEM32);
+ if (!Wintun)
+ return NULL;
+#define X(Name) ((*(FARPROC *)&Name = GetProcAddress(Wintun, #Name)) == NULL)
+ if (X(WintunCreateAdapter) || X(WintunCloseAdapter) || X(WintunOpenAdapter) || X(WintunGetAdapterLUID) ||
+ X(WintunGetRunningDriverVersion) || X(WintunDeleteDriver) || X(WintunSetLogger) || X(WintunStartSession) ||
+ X(WintunEndSession) || X(WintunGetReadWaitEvent) || X(WintunReceivePacket) || X(WintunReleaseReceivePacket) ||
+ X(WintunAllocateSendPacket) || X(WintunSendPacket))
+#undef X
+ {
+ DWORD LastError = GetLastError();
+ FreeLibrary(Wintun);
+ SetLastError(LastError);
+ return NULL;
+ }
+ return Wintun;
+}
+
+static void CALLBACK
+ConsoleLogger(_In_ WINTUN_LOGGER_LEVEL Level, _In_ DWORD64 Timestamp, _In_z_ const WCHAR *LogLine)
+{
+ WCHAR LevelMarker;
+ switch (Level)
+ {
+ case WINTUN_LOG_INFO:
+ LevelMarker = L'+';
+ break;
+ case WINTUN_LOG_WARN:
+ LevelMarker = L'-';
+ break;
+ case WINTUN_LOG_ERR:
+ LevelMarker = L'!';
+ break;
+ default:
+ return;
+ }
+ fwprintf(
+ stdout,
+ L"[%c] %ls\n",
+ LevelMarker,
+ LogLine);
+}
+
+static void
+Log(_In_ WINTUN_LOGGER_LEVEL Level, _In_z_ const WCHAR *Format, ...)
+{
+ WCHAR LogLine[0x200];
+ va_list args;
+ va_start(args, Format);
+ _vsnwprintf_s(LogLine, _countof(LogLine), _TRUNCATE, Format, args);
+ va_end(args);
+ ConsoleLogger(Level, (DWORD64) 0, LogLine);
+}
+
+WINTUN_ADAPTER_HANDLE create_wintun_adapter(PWSTR adapterName)
+{
+ DWORD LastError;
+
+ GUID ExampleGuid = { 0xdeadbeef, 0xbaad, 0xcafe, { 0x77, 0x82, 0x07, 0x07, 0x82, 0xab, 0xcd, 0xef } };
+ WINTUN_ADAPTER_HANDLE Adapter = WintunCreateAdapter(adapterName, WINTUN_TUNNEL_TYPE, &ExampleGuid);
+ if (!Adapter)
+ {
+ LastError = GetLastError();
+ Log(WINTUN_LOG_ERR, L"Failed to create adapter (%lu)", LastError);
+ goto cleanupWintun;
+ }
+
+ DWORD Version = WintunGetRunningDriverVersion();
+
+ NETIO_STATUS ret;
+ NET_LUID luid;
+ MIB_IF_ROW2 row;
+ memset(&row, 0, sizeof(MIB_IF_ROW2));
+
+ WintunGetAdapterLUID(Adapter, &luid);
+
+ row.InterfaceLuid = luid;
+
+ ret = GetIfEntry2(&row);
+
+ if (ret == 0) {
+ Log(WINTUN_LOG_INFO, L"Adapter Alias is: %ls", row.Alias);
+ }
+
+ WINTUN_SESSION_HANDLE Session = WintunStartSession(Adapter, 0x400000);
+
+ if (!Session)
+ {
+ LastError = GetLastError();
+ Log(WINTUN_LOG_ERR, L"Failed to create session (%lu)", LastError);
+ goto cleanupAdapter;
+ }
+ else {
+ ; /*Log(WINTUN_LOG_INFO, L"Wintun session started");*/
+ }
+
+ LastError = ERROR_SUCCESS;
+
+ WintunEndSession(Session);
+ /*Log(WINTUN_LOG_INFO, L"Wintun session ended");*/
+ return Adapter;
+
+cleanupAdapter:
+ WintunCloseAdapter(Adapter);
+ /*Log(WINTUN_LOG_INFO, L"Wintun adapter closed");*/
+cleanupWintun:
+ return NULL;
+}
+
+wchar_t * currentAdapterName;
+
+static intptr_t check_tun(struct openconnect_info *vpninfo, int type, char *guid, wchar_t *wname)
+{
+ if (currentAdapterName != 0) {
+ if ( ! wcscmp(currentAdapterName, wname) ) {
+ printf("Found %s device '%S' guid %s\n",
+ type ? "Wintun" : "Tap", wname, guid);
+ return VALID_WINTUN_HANDLE;
+ }
+ }
+ return 0;
+}
+
+int main(void)
+{
+ HMODULE Wintun = InitializeWintun();
+ if (!Wintun) {
+ DWORD LastError = GetLastError();
+ Log(WINTUN_LOG_ERR, L"Failed to initialize Wintun (%lu)", LastError);
+ return LastError;
+ }
+
+ WintunSetLogger(ConsoleLogger);
+ Log(WINTUN_LOG_INFO, L"Wintun library loaded");
+
+ Log(WINTUN_LOG_INFO, L"MAX_ADAPTER_NAME is: %d", MAX_ADAPTER_NAME);
+
+ DWORD ret = 0;
+ WINTUN_ADAPTER_HANDLE adapter;
+ WCHAR adapterName[MAX_ADAPTER_NAME];
+
+ memset(adapterName, 0, sizeof(adapterName));
+
+ wsprintfW(adapterName, L"testAdapterNameForRunningLoops_");
+ int add = 0;
+ int len = 0;
+
+ do {
+ wsprintfW(adapterName, L"%s%d", adapterName, add);
+ add = (add+1)%10;
+ len = wcslen(adapterName);
+ Log(WINTUN_LOG_INFO, L"len=%3d name=%ls", len, adapterName);
+ adapter = create_wintun_adapter(adapterName);
+
+ if (adapter == NULL)
+ ret = OPEN_TUN_HARDFAIL;
+ else {
+ currentAdapterName = adapterName;
+ ret = search_taps(NULL, check_tun);
+ WintunCloseAdapter(adapter);
+ Log(WINTUN_LOG_INFO, L"Wintun adapter closed");
+ }
+ } while ( (len < (MAX_ADAPTER_NAME - 1)) && (ret == VALID_WINTUN_HANDLE) );
+
+ FreeLibrary(Wintun);
+
+ if (ret == VALID_WINTUN_HANDLE) /* last test was succesful*/
+ return 0;
+
+ return 1;
+}
status = RegQueryValueExA(hkey, "ComponentId", NULL, &type,
(unsigned char *)buf, &len);
if (status || type != REG_SZ) {
- vpn_progress(vpninfo, PRG_TRACE,
- _("Cannot read %s\\%s or is not string\n"),
- keyname, "ComponentId");
+ if (status == ERROR_FILE_NOT_FOUND) {
+ vpn_progress(vpninfo, PRG_TRACE,
+ _("Cannot read registry key %s\\%s: value not found\n"),
+ keyname, "ComponentId");
+ }
+ else if (type != REG_SZ) {
+ vpn_progress(vpninfo, PRG_TRACE,
+ _("Cannot read registry key %s\\%s: value is not a string (%ld)\n"),
+ keyname, "ComponentId", type);
+ }
+ else {
+ vpn_progress(vpninfo, PRG_TRACE,
+ _("Cannot read registry key %s\\%s or is not string: %s (%ld)\n"),
+ keyname, "ComponentId", openconnect__win32_strerror(status), status);
+ }
RegCloseKey(hkey);
continue;
}
(unsigned char *)name, &len);
RegCloseKey(hkey);
if (status || type != REG_SZ) {
- vpn_progress(vpninfo, PRG_INFO,
- _("Cannot read registry key %s\\%s or is not string\n"),
- keyname, "Name");
+ if (status == ERROR_FILE_NOT_FOUND) {
+ vpn_progress(vpninfo, PRG_INFO,
+ _("Cannot read registry key %s\\%s: value not found\n"),
+ keyname, "Name");
+ }
+ else if (status == ERROR_MORE_DATA) {
+ vpn_progress(vpninfo, PRG_INFO,
+ _("Cannot read registry key %s\\%s: character buffer too small: %llu chars required\n"),
+ keyname, "Name", (long long unsigned int)(len / sizeof(wchar_t)));
+ }
+ else if (type != REG_SZ) {
+ vpn_progress(vpninfo, PRG_INFO,
+ _("Cannot read registry key %s\\%s: value is not a string (%ld)\n"),
+ keyname, "Name", type);
+ }
+ else {
+ vpn_progress(vpninfo, PRG_INFO,
+ _("Cannot read registry key %s\\%s: %s (%ld)\n"),
+ keyname, "Name", openconnect__win32_strerror(status), status);
+ }
continue;
}