/* SPDX-License-Identifier: GPL-2.0 * * Copyright (C) 2018-2021 WireGuard LLC. All Rights Reserved. */ #include #include #include #include #include #include #include #include #include #include #include #include "wireguard.h" #include "common.h" #include "tunnel.h" #include "network.h" #include #include #pragma comment(lib, "Crypt32.lib") #define MALLOC(x) HeapAlloc(GetProcessHeap(), 0, (x)) #define FREE(x) HeapFree(GetProcessHeap(), 0, (x)) static WIREGUARD_CREATE_ADAPTER_FUNC *WireGuardCreateAdapter; static WIREGUARD_OPEN_ADAPTER_FUNC *WireGuardOpenAdapter; static WIREGUARD_CLOSE_ADAPTER_FUNC *WireGuardCloseAdapter; static WIREGUARD_GET_ADAPTER_LUID_FUNC *WireGuardGetAdapterLUID; static WIREGUARD_GET_RUNNING_DRIVER_VERSION_FUNC *WireGuardGetRunningDriverVersion; static WIREGUARD_DELETE_DRIVER_FUNC *WireGuardDeleteDriver; static WIREGUARD_SET_LOGGER_FUNC *WireGuardSetLogger; static WIREGUARD_SET_ADAPTER_LOGGING_FUNC *WireGuardSetAdapterLogging; static WIREGUARD_GET_ADAPTER_STATE_FUNC *WireGuardGetAdapterState; static WIREGUARD_SET_ADAPTER_STATE_FUNC *WireGuardSetAdapterState; static WIREGUARD_GET_CONFIGURATION_FUNC *WireGuardGetConfiguration; static WIREGUARD_SET_CONFIGURATION_FUNC *WireGuardSetConfiguration; #if 0 static int InitializeWMI() { IWbemLocator* p_instance_ = nullptr; IWbemServices* p_service_ = nullptr; IEnumWbemClassObject* p_enum_ = nullptr; IWbemClassObject *p_obj_ = nullptr; IWbemClassObject *p_config = nullptr; // Step 1: Initialize COM. HRESULT hres = CoInitializeEx(nullptr, COINIT_MULTITHREADED); if (FAILED(hres)) { SPDLOG_ERROR("CoInitializeEx Error: {0}", GetLastError()); return false; } // Step 3: Obtain the initial locator to WMI hres = CoCreateInstance( CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER, IID_IWbemLocator, (LPVOID*)&p_instance_); if (FAILED(hres)) { SPDLOG_ERROR("CoCreateInstance Error: {0}", GetLastError()); return false; } // Step 4: Connect to the local root\cimv2 namespace and obtain pointer pSvc to make IWbemServices calls. hres = p_instance_->ConnectServer( _bstr_t(L"ROOT\\CIMV2"), NULL, NULL, 0, NULL, 0, 0, &p_service_ ); //ASSERT_THROW(SUCCEEDED(hres), "ConnectServer failed"); if (FAILED(hres)) { #ifdef _DEBUG cout << "ConnectServer failed: " << hres << endl; #endif return false; } // Step 5: Set security levels for the proxy hres = CoSetProxyBlanket( p_service_, // Indicates the proxy to set RPC_C_AUTHN_WINNT, // RPC_C_AUTHN_xxx RPC_C_AUTHZ_NONE, // RPC_C_AUTHZ_xxx NULL, // Server principal name RPC_C_AUTHN_LEVEL_CALL, // RPC_C_AUTHN_LEVEL_xxx RPC_C_IMP_LEVEL_IMPERSONATE, // RPC_C_IMP_LEVEL_xxx NULL, // client identity EOAC_NONE // proxy capabilities ); //ASSERT_THROW(SUCCEEDED(hres), "CoSetProxyBlanket failed"); if (FAILED(hres)) { #ifdef _DEBUG cout << "CoSetProxyBlanket failed: " << hres << endl; #endif return false; } // 通过适配器名称来找到指定的适配器对象. CComBSTR TheQuery = L"SELECT * FROM Win32_NetworkAdapterConfiguration WHERE SettingID = \""; std::wstring_convert, wchar_t> conversion; TheQuery += conversion.from_bytes(key_).c_str(); TheQuery += L"\""; // const BSTR lang = L"WQL"; hres = p_service_->ExecQuery( SysAllocString(L"WQL"), // L"WQL", TheQuery, WBEM_FLAG_RETURN_IMMEDIATELY | WBEM_FLAG_FORWARD_ONLY, NULL, &p_enum_); //ASSERT_THROW(SUCCEEDED(hres), "ExecQuery failed"); if (FAILED(hres)) { #ifdef _DEBUG cout << "ExecQuery failed: " << hres << endl; #endif return false; } // Get the adapter object. ULONG num = 0; hres = p_enum_->Next(WBEM_INFINITE, 1, &p_obj_, &num); //ASSERT_THROW(SUCCEEDED(hres), "Next failed"); if (FAILED(hres)) { #ifdef _DEBUG cout << "Next failed: " << hres << endl; #endif return false; } //ASSERT_THROW(0 < num, "Next failed"); if (num < 1) { #ifdef _DEBUG cout << "Next failed num < 1" << endl; #endif return false; } VariantInit(&path_); hres = p_obj_->Get(L"__PATH", 0, &path_, NULL, NULL); //ASSERT_THROW(SUCCEEDED(hres), "Get path failed"); if (FAILED(hres)) { #ifdef _DEBUG cout << "Get failed: " << hres << endl; #endif return false; } hres = p_service_->GetObject(_bstr_t(L"Win32_NetworkAdapterConfiguration"), 0, NULL, &p_config, NULL); //ASSERT_THROW(SUCCEEDED(hres), "GetObject Win32_NetworkAdapterConfiguration failed"); if (FAILED(hres)) { #ifdef _DEBUG cout << "GetObject failed: " << hres << endl; #endif return false; } is_init_ = true; return true; } #endif static HMODULE InitializeWireGuardNT(void) { HMODULE WireGuardDll = LoadLibraryExW(L"wireguard.dll", nullptr, LOAD_LIBRARY_SEARCH_APPLICATION_DIR | LOAD_LIBRARY_SEARCH_SYSTEM32); if (!WireGuardDll) { return nullptr; } #define X(Name) ((*(FARPROC *)&Name = GetProcAddress(WireGuardDll, #Name)) == nullptr) if (X(WireGuardCreateAdapter) || X(WireGuardOpenAdapter) || X(WireGuardCloseAdapter) || X(WireGuardGetAdapterLUID) || X(WireGuardGetRunningDriverVersion) || X(WireGuardDeleteDriver) || X(WireGuardSetLogger) || X(WireGuardSetAdapterLogging) || X(WireGuardGetAdapterState) || X(WireGuardSetAdapterState) || X(WireGuardGetConfiguration) || X(WireGuardSetConfiguration)) #undef X { DWORD LastError = GetLastError(); FreeLibrary(WireGuardDll); SetLastError(LastError); return nullptr; } return WireGuardDll; } // //static void CALLBACK ConsoleLogger(_In_ WIREGUARD_LOGGER_LEVEL Level, // _In_ DWORD64 Timestamp, // _In_z_ const WCHAR *LogLine) { // SYSTEMTIME SystemTime; // GetSystemTime(&SystemTime); // //FileTimeToSystemTime((FILETIME *)&Timestamp, &SystemTime); // WCHAR LevelMarker; // switch (Level) { // case WIREGUARD_LOG_INFO: // LevelMarker = L'+'; // break; // case WIREGUARD_LOG_WARN: // LevelMarker = L'-'; // break; // case WIREGUARD_LOG_ERR: // LevelMarker = L'!'; // break; // default: // return; // } // fwprintf(stderr, // L"%04u-%02u-%02u %02u:%02u:%02u.%04u [%c] %s\n", // SystemTime.wYear, // SystemTime.wMonth, // SystemTime.wDay, // SystemTime.wHour, // SystemTime.wMinute, // SystemTime.wSecond, // SystemTime.wMilliseconds, // LevelMarker, // LogLine); //} static DWORD64 Now() { return 0; } #if 0 static DWORD LogError(_In_z_ const WCHAR *Prefix, _In_ DWORD Error) { WCHAR tMsg[MAX_PATH]; StringCbPrintfW(tMsg, MAX_PATH, L"Error: %d", Error); ConsoleLogger(WIREGUARD_LOG_ERR, Now(), tMsg); return Error; } static DWORD LogLastError(_In_z_ const WCHAR *Prefix) { DWORD LastError = GetLastError(); LogError(Prefix, LastError); SetLastError(LastError); return LastError; } static void Log(_In_ WIREGUARD_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, Now(), LogLine); } #endif _Must_inspect_result_ _Return_type_success_(return != FALSE) static BOOL GenerateKeyPair(_Out_writes_bytes_all_(WIREGUARD_KEY_LENGTH) BYTE PublicKey[WIREGUARD_KEY_LENGTH], _Out_writes_bytes_all_(WIREGUARD_KEY_LENGTH) BYTE PrivateKey[WIREGUARD_KEY_LENGTH]) { BCRYPT_ALG_HANDLE Algorithm; BCRYPT_KEY_HANDLE Key; NTSTATUS Status; struct { BCRYPT_ECCKEY_BLOB Header; BYTE Public[32]; BYTE Unused[32]; BYTE Private[32]; } ExportedKey; ULONG Bytes; Status = BCryptOpenAlgorithmProvider(&Algorithm, BCRYPT_ECDH_ALGORITHM, nullptr, 0); if (!NT_SUCCESS(Status)) { goto out; } Status = BCryptSetProperty(Algorithm, BCRYPT_ECC_CURVE_NAME, (PUCHAR)BCRYPT_ECC_CURVE_25519, sizeof(BCRYPT_ECC_CURVE_25519), 0); if (!NT_SUCCESS(Status)) { goto cleanupProvider; } Status = BCryptGenerateKeyPair(Algorithm, &Key, 255, 0); if (!NT_SUCCESS(Status)) { goto cleanupProvider; } Status = BCryptFinalizeKeyPair(Key, 0); if (!NT_SUCCESS(Status)) { goto cleanupKey; } Status = BCryptExportKey(Key, nullptr, BCRYPT_ECCPRIVATE_BLOB, (PUCHAR)&ExportedKey, sizeof(ExportedKey), &Bytes, 0); if (!NT_SUCCESS(Status)) { goto cleanupKey; } memcpy(PublicKey, ExportedKey.Public, WIREGUARD_KEY_LENGTH); memcpy(PrivateKey, ExportedKey.Private, WIREGUARD_KEY_LENGTH); SecureZeroMemory(&ExportedKey, sizeof(ExportedKey)); cleanupKey: BCryptDestroyKey(Key); cleanupProvider: BCryptCloseAlgorithmProvider(Algorithm, 0); out: SetLastError(RtlNtStatusToDosError(Status)); return NT_SUCCESS(Status); } static HANDLE QuitEvent; //static BOOL WINAPI CtrlHandler(_In_ DWORD CtrlType) { // switch (CtrlType) { // case CTRL_C_EVENT: // case CTRL_BREAK_EVENT: // case CTRL_CLOSE_EVENT: // case CTRL_LOGOFF_EVENT: // case CTRL_SHUTDOWN_EVENT: // SPDLOG_INFO("Cleaning up and shutting down"); // SetEvent(QuitEvent); // return TRUE; // } // return FALSE; //} static BOOL GetEndPoint(const TCHAR *Input, _Out_ SOCKADDR_INET *ResolvedDemoServer) { SOCKET Socket = INVALID_SOCKET; TCHAR name[MAX_PATH]; ADDRINFOA Hints = {}; ADDRINFOA *Resolution; StringCbCopy(name, MAX_PATH, Input); TCHAR *Colon1 = strchr(name, ':'); *Colon1 = '\0'; Hints.ai_family = AF_UNSPEC; Hints.ai_socktype = SOCK_STREAM; Hints.ai_protocol = IPPROTO_TCP; if (GetAddrInfo(name, Colon1 + 1, &Hints, &Resolution)) { return FALSE; } for (const ADDRINFOA *Candidate = Resolution; Candidate; Candidate = Candidate->ai_next) { UINT16 port; if (Candidate->ai_family != AF_INET && Candidate->ai_family != AF_INET6) { continue; } memcpy(ResolvedDemoServer, Candidate->ai_addr, Candidate->ai_addrlen); port = static_cast(strtoul(Colon1 + 1, nullptr, 10)); if (ResolvedDemoServer->si_family == AF_INET) { ResolvedDemoServer->Ipv4.sin_port = htons(port); } else if (ResolvedDemoServer->si_family == AF_INET6) { ResolvedDemoServer->Ipv6.sin6_port = htons(port); } closesocket(Socket); FreeAddrInfo(Resolution); return TRUE; } closesocket(Socket); FreeAddrInfo(Resolution); return FALSE; } _Return_type_success_(return != FALSE) static BOOL TalkToDemoServer(_In_reads_bytes_(InputLength) const CHAR *Input, _In_ DWORD InputLength, _Out_writes_bytes_(*OutputLength) CHAR *Output, _Inout_ DWORD *OutputLength, _Out_ SOCKADDR_INET *ResolvedDemoServer) { SOCKET Socket = INVALID_SOCKET; ADDRINFOW Hints = {}; ADDRINFOW *Resolution; BOOL Ret = FALSE; Hints.ai_family = AF_UNSPEC; Hints.ai_socktype = SOCK_STREAM; Hints.ai_protocol = IPPROTO_TCP; if (GetAddrInfoW(L"demo.wireguard.com", L"42912", &Hints, &Resolution)) { return FALSE; } for (ADDRINFOW *Candidate = Resolution; Candidate; Candidate = Candidate->ai_next) { if (Candidate->ai_family != AF_INET && Candidate->ai_family != AF_INET6) { continue; } Socket = socket(Candidate->ai_family, Candidate->ai_socktype, Candidate->ai_protocol); if (Socket == INVALID_SOCKET) { goto cleanupResolution; } if (connect(Socket, Candidate->ai_addr, (int)Candidate->ai_addrlen) == SOCKET_ERROR) { closesocket(Socket); Socket = INVALID_SOCKET; } memcpy(ResolvedDemoServer, Candidate->ai_addr, Candidate->ai_addrlen); break; } if (Socket == INVALID_SOCKET) { goto cleanupResolution; } if (send(Socket, Input, InputLength, 0) == SOCKET_ERROR) { goto cleanupSocket; } if ((*OutputLength = recv(Socket, Output, *OutputLength, 0)) == SOCKET_ERROR) { goto cleanupSocket; } Ret = TRUE; cleanupSocket: closesocket(Socket); cleanupResolution: FreeAddrInfoW(Resolution); return Ret; } typedef struct { WIREGUARD_INTERFACE Interface; WIREGUARD_PEER RemoteServer; WIREGUARD_ALLOWED_IP AllV4; WIREGUARD_ALLOWED_IP AllV4_2; } WG_CONFIG_INFO; int main_wireguard_getinfo() { DWORD Bytes; WG_CONFIG_INFO Config {}; HMODULE WireGuard = InitializeWireGuardNT(); if (!WireGuard) { SPDLOG_ERROR("Failed to initialize WireGuardNT: {0}", GetLastError()); return -1; } /* CryptStringToBinary(TEXT("WGAlqvys3O83VmWug6Z8NzUrxGr/PNHSeOVFnKLSe2k="), 0, CRYPT_STRING_BASE64, Config.Interface.PublicKey, &Bytes, nullptr, nullptr);*/ WIREGUARD_ADAPTER_HANDLE Adapter = WireGuardOpenAdapter(L"admin"); if (!Adapter) { SPDLOG_ERROR("Failed to create adapter: {0}", GetLastError()); return -1; } Bytes = sizeof(Config); if (!WireGuardGetConfiguration(Adapter, &Config.Interface, &Bytes)) { SPDLOG_ERROR("Failed to get configuration: {0}", GetLastError()); //WireGuardCloseAdapter(Adapter); return -3; } //WireGuardCloseAdapter(Adapter); return 0; } int main_wireguard(bool isDelete) { WG_CONFIG_INFO Config {}; DWORD LastError; WSADATA WsaData; MIB_IPINTERFACE_ROW IpInterface = {}; DWORD Bytes; MIB_UNICASTIPADDRESS_ROW AddressRow; GUID ExampleGuid = { 0xdeadc001, 0xbeef, 0xbabe, {0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef} }; WIREGUARD_ADAPTER_HANDLE Adapter; DWORD Version; if (WSAStartup(MAKEWORD(2, 2), &WsaData)) { SPDLOG_ERROR("Failed to initialize Winsock: {0}", GetLastError()); return -1; } HMODULE WireGuard = InitializeWireGuardNT(); if (!WireGuard) { SPDLOG_ERROR("Failed to initialize WireGuardNT: {0}", GetLastError()); return -2; } SPDLOG_INFO("WireGuardNT library loaded"); // 配置本地隧道接口 Config.Interface.Flags = WIREGUARD_INTERFACE_HAS_PRIVATE_KEY; Config.Interface.PeersCount = 1; CryptStringToBinary(TEXT("WGAlqvys3O83VmWug6Z8NzUrxGr/PNHSeOVFnKLSe2k="), 0, CRYPT_STRING_BASE64, Config.Interface.PrivateKey, &Bytes, nullptr, nullptr); // 配置远程隧道接口 Config.RemoteServer.Flags = static_cast( WIREGUARD_PEER_HAS_PUBLIC_KEY | WIREGUARD_PEER_HAS_PERSISTENT_KEEPALIVE | WIREGUARD_PEER_HAS_ENDPOINT); Config.RemoteServer.AllowedIPsCount = 2; Config.RemoteServer.PersistentKeepalive = 30; CryptStringToBinary(TEXT("q3ep8hN2v3VpHbcru+rTmvyBt13iH0DkEsVAyT2LpVo="), 0, CRYPT_STRING_BASE64, Config.RemoteServer.PublicKey, &Bytes, nullptr, nullptr); if (!GetEndPoint(TEXT("efc.xajhuang.com:10000"), &Config.RemoteServer.Endpoint)) { SPDLOG_ERROR("Failed to talk to demo server: {0}", GetLastError()); goto cleanupWireGuard; } Config.AllV4.AddressFamily = AF_INET; Config.AllV4.Cidr = 24; InetPtonA(AF_INET, TEXT("10.10.10.0"), &Config.AllV4.Address.V4.S_un.S_addr); Config.AllV4_2.AddressFamily = AF_INET; Config.AllV4_2.Cidr = 24; InetPtonA(AF_INET, TEXT("192.168.100.0"), &Config.AllV4.Address.V4.S_un.S_addr); InitializeUnicastIpAddressEntry(&AddressRow); AddressRow.Address.Ipv4.sin_family = AF_INET; AddressRow.OnLinkPrefixLength = 24; /* This is a /24 network */ AddressRow.DadState = IpDadStatePreferred; InetPtonA(AF_INET, TEXT("10.10.10.1"), &AddressRow.Address.Ipv4.sin_addr); #if 0 Log(WIREGUARD_LOG_INFO, L"Generating keypair"); if (!GenerateKeyPair(PublicKey, Config.Interface.PrivateKey)) { LastError = LogError(L"Failed to generate keypair", GetLastError()); goto cleanupWireGuard; } Bytes = sizeof(PublicKeyString); CryptBinaryToStringA(PublicKey, sizeof(PublicKey), CRYPT_STRING_BASE64 | CRYPT_STRING_NOCR, PublicKeyString, &Bytes); Log(WIREGUARD_LOG_INFO, L"Talking to demo server"); Bytes = sizeof(ServerResponse) - 1; if (!TalkToDemoServer(PublicKeyString, (DWORD)strlen(PublicKeyString), ServerResponse, &Bytes, &Config.RemoteServer.Endpoint)) { LastError = LogError(L"Failed to talk to demo server", GetLastError()); goto cleanupWireGuard; } Colon1 = strchr(ServerResponse, ':'); Colon2 = Colon1 ? strchr(Colon1 + 1, ':') : nullptr; Colon3 = Colon2 ? strchr(Colon2 + 1, ':') : nullptr; if (!Colon1 || !Colon2 || !Colon3) { LastError = LogError(L"Failed to parse demo server response", ERROR_UNDEFINED_CHARACTER); goto cleanupWireGuard; } if (Bytes && ServerResponse[--Bytes] == '\n') { ServerResponse[Bytes] = '\0'; } *Colon1 = *Colon2 = *Colon3 = '\0'; Bytes = sizeof(Config.RemoteServer.PublicKey); if (strcmp(ServerResponse, "OK") || != 1 || !CryptStringToBinaryA(Colon1 + 1, 0, CRYPT_STRING_BASE64, Config.RemoteServer.PublicKey, &Bytes, nullptr, nullptr)) { LastError = LogError(L"Failed to parse demo server response", ERROR_UNDEFINED_CHARACTER); goto cleanupWireGuard; } if (Config.RemoteServer.Endpoint.si_family == AF_INET) { Config.RemoteServer.Endpoint.Ipv4.sin_port = htons((u_short)atoi(Colon2 + 1)); } else if (Config.RemoteServer.Endpoint.si_family == AF_INET6) { Config.RemoteServer.Endpoint.Ipv6.sin6_port = htons((u_short)atoi(Colon2 + 1)); } #endif QuitEvent = CreateEventW(nullptr, TRUE, FALSE, nullptr); if (!QuitEvent) { SPDLOG_ERROR("Failed to create event:{0}", GetLastError()); goto cleanupWireGuard; } //if (!SetConsoleCtrlHandler(CtrlHandler, TRUE)) { // SPDLOG_ERROR("Failed to set console handler: {0}", GetLastError()); // goto cleanupQuit; //} Adapter = WireGuardOpenAdapter(L"Demo"); if (isDelete) { SPDLOG_INFO("Remove adapter: {0}", "Demo"); WireGuardCloseAdapter(Adapter); return 0; } if (!Adapter) { Adapter = WireGuardCreateAdapter(L"Demo", L"Example", &ExampleGuid); if (!Adapter) { SPDLOG_ERROR("Failed to create adapter: {0}", LastError); goto cleanupQuit; } } if (!WireGuardSetAdapterLogging(Adapter, WIREGUARD_ADAPTER_LOG_ON)) { SPDLOG_ERROR("Failed to enable adapter logging: {0}", GetLastError()); } Version = WireGuardGetRunningDriverVersion(); SPDLOG_INFO("WireGuardNT v{0}.{1} loaded", (Version >> 16) & 0xff, (Version >> 0) & 0xff); WireGuardGetAdapterLUID(Adapter, &AddressRow.InterfaceLuid); SetInterfaceIpAddress("Demo", "10.10.10.1", "255.255.255.0"); #if 0 InitializeIpForwardEntry(&DefaultRoute); DefaultRoute.InterfaceLuid = AddressRow.InterfaceLuid; DefaultRoute.DestinationPrefix.Prefix.si_family = AF_INET; DefaultRoute.NextHop.si_family = AF_INET; DefaultRoute.Metric = 0; LastError = CreateIpForwardEntry2(&DefaultRoute); if (LastError != ERROR_SUCCESS && LastError != ERROR_OBJECT_ALREADY_EXISTS) { SPDLOG_ERROR("Failed to set default route: {0}", LastError); goto cleanupAdapter; } LastError = CreateUnicastIpAddressEntry(&AddressRow); if (LastError != ERROR_SUCCESS && LastError != ERROR_OBJECT_ALREADY_EXISTS) { SPDLOG_ERROR("Failed to set IP address: {0}", LastError); goto cleanupAdapter; } #endif #if 1 InitializeIpInterfaceEntry(&IpInterface); IpInterface.InterfaceLuid = AddressRow.InterfaceLuid; IpInterface.Family = AF_INET; LastError = GetIpInterfaceEntry(&IpInterface); if (LastError != ERROR_SUCCESS) { SPDLOG_ERROR("Failed to get IP interface: {0}", LastError); goto cleanupAdapter; } /*if ((LastError = AddIpAddress(IpInterface.InterfaceIndex)) != 0) { SPDLOG_ERROR("Set interface IP Error: {0}", LastError); goto cleanupAdapter; }*/ IpInterface.UseAutomaticMetric = FALSE; IpInterface.Metric = 0; IpInterface.NlMtu = 1420; IpInterface.SitePrefixLength = 0; LastError = SetIpInterfaceEntry(&IpInterface); if (LastError != ERROR_SUCCESS) { SPDLOG_ERROR("Failed to set metric and MTU: {0}", LastError); goto cleanupAdapter; } #endif SPDLOG_INFO("Setting configuration and adapter up"); if (!WireGuardSetConfiguration(Adapter, &Config.Interface, sizeof(Config)) || !WireGuardSetAdapterState(Adapter, WIREGUARD_ADAPTER_STATE_UP)) { SPDLOG_ERROR("Failed to set configuration and adapter up: {0}", GetLastError()); goto cleanupAdapter; } do { Bytes = sizeof(Config); if (!WireGuardGetConfiguration(Adapter, &Config.Interface, &Bytes) || !Config.Interface.PeersCount) { SPDLOG_ERROR("Failed to get configuration: {0}", GetLastError()); goto cleanupAdapter; } DWORD64 Timestamp = Now(); SYSTEMTIME SystemTime; FileTimeToSystemTime((FILETIME *)&Timestamp, &SystemTime); fwprintf(stderr, L"%04u-%02u-%02u %02u:%02u:%02u.%04u [#] RX: %llu, TX: %llu\r", SystemTime.wYear, SystemTime.wMonth, SystemTime.wDay, SystemTime.wHour, SystemTime.wMinute, SystemTime.wSecond, SystemTime.wMilliseconds, Config.RemoteServer.RxBytes, Config.RemoteServer.TxBytes); } while (WaitForSingleObject(QuitEvent, 1000) == WAIT_TIMEOUT); cleanupAdapter: WireGuardCloseAdapter(Adapter); cleanupQuit: //SetConsoleCtrlHandler(CtrlHandler, FALSE); CloseHandle(QuitEvent); cleanupWireGuard: FreeLibrary(WireGuard); cleanupWinsock: WSACleanup(); return 0; }