/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "windowscommons.h" #include #include #include #include #include #include #include #include #include #include #include #include "logger.h" #include "platforms/windows/windowsutils.h" constexpr const char* VPN_NAME = "AmneziaVPN"; constexpr const char* WIREGUARD_DIR = "AmneziaWG"; constexpr const char* DATA_DIR = "Data"; namespace { Logger logger("WindowsCommons"); } QString WindowsCommons::tunnelConfigFile() { QStringList paths = QStandardPaths::standardLocations(QStandardPaths::GenericDataLocation); for (const QString& path : paths) { QDir dir(path); if (!dir.exists()) { continue; } QDir vpnDir(dir.filePath(VPN_NAME)); if (!vpnDir.exists()) { continue; } QString wireguardFile(vpnDir.filePath(QString("%1.conf").arg(VPN_NAME))); if (!QFileInfo::exists(wireguardFile)) { continue; } logger.debug() << "Found the current wireguard configuration:" << wireguardFile; return wireguardFile; } for (const QString& path : paths) { QDir dir(path); QDir vpnDir(dir.filePath(VPN_NAME)); if (!vpnDir.exists() && !dir.mkdir(VPN_NAME)) { logger.debug() << "Failed to create path Amnezia under" << path; continue; } return vpnDir.filePath(QString("%1.conf").arg(VPN_NAME)); } logger.error() << "Failed to create the right paths"; return QString(); } // static QString WindowsCommons::tunnelLogFile() { static QString tunnelLogFilePath = getTunnelLogFilePath(); return tunnelLogFilePath; } // static QString WindowsCommons::getProgramFilesPath() { wchar_t* path = nullptr; if (SUCCEEDED( SHGetKnownFolderPath(FOLDERID_ProgramFiles, 0, nullptr, &path))) { auto guard = qScopeGuard([&] { CoTaskMemFree(path); }); return QString::fromWCharArray(path); } return QString(); } // static QString WindowsCommons::getTunnelLogFilePath() { // Return WireGuard's log file path, "\Program Files\WireGuard\Data\log.bin", // if the directory path exists auto programFilesPath = getProgramFilesPath(); if (!programFilesPath.isEmpty()) { QDir programFilesDir(programFilesPath); if (programFilesDir.exists()) { QDir wireGuardDir(programFilesDir.filePath(WIREGUARD_DIR)); if (wireGuardDir.exists()) { QDir wireGuardDataDir(wireGuardDir.filePath(DATA_DIR)); if (wireGuardDataDir.exists()) { return wireGuardDataDir.filePath("log.bin"); } } } } logger.debug() << "Failed to find WireGuard Tunnel log file"; return QString(); } // static int WindowsCommons::AdapterIndexTo(const QHostAddress& dst) { logger.debug() << "Getting Current Internet Adapter that routes to" << logger.sensitive(dst.toString()); quint32_be ipBigEndian; quint32 ip = dst.toIPv4Address(); qToBigEndian(ip, &ipBigEndian); _MIB_IPFORWARDROW routeInfo; auto result = GetBestRoute(ipBigEndian, 0, &routeInfo); if (result != NO_ERROR) { return -1; } auto adapter = QNetworkInterface::interfaceFromIndex(routeInfo.dwForwardIfIndex); logger.debug() << "Internet Adapter:" << adapter.name(); return routeInfo.dwForwardIfIndex; } // static int WindowsCommons::VPNAdapterIndex() { // For someReason QNetworkInterface::fromName(MozillaVPN) does not work >:( auto adapterList = QNetworkInterface::allInterfaces(); for (const auto& adapter : adapterList) { if (adapter.humanReadableName().contains("AmneziaVPN")) { return adapter.index(); } } return -1; } // Static QString WindowsCommons::getCurrentPath() { QByteArray buffer(2048, 0xFFu); auto ok = GetModuleFileNameA(NULL, buffer.data(), buffer.size()); if (ok == ERROR_INSUFFICIENT_BUFFER) { buffer.resize(buffer.size() * 2); ok = GetModuleFileNameA(NULL, buffer.data(), buffer.size()); } if (ok == 0) { WindowsUtils::windowsLog("Err fetching dos path"); return ""; } return QString::fromLocal8Bit(buffer); } // Static bool WindowsCommons::requireSoftwareRendering() { /* Qt6 appears to require Direct3D shader level 5, and can result in rendering * failures on some platforms. To workaround the issue, try to identify if * this device can reliably run the shaders, and request fallback to software * rendering if not. * * See: https://bugreports.qt.io/browse/QTBUG-100689 */ IDXGIFactory1* factory; HRESULT result; result = CreateDXGIFactory1(__uuidof(IDXGIFactory1), (void**)(&factory)); if (FAILED(result)) { logger.error() << "Failed to create DXGI Factory:" << result; return true; } auto guard = qScopeGuard([&] { factory->Release(); }); // Enumerate the graphics adapters to find the minimum D3D shader version // that we can guarantee will render successfully. UINT i = 0; IDXGIAdapter1* adapter; D3D_FEATURE_LEVEL minFeatureLevel = D3D_FEATURE_LEVEL_11_1; while (factory->EnumAdapters1(i++, &adapter) != DXGI_ERROR_NOT_FOUND) { auto adapterGuard = qScopeGuard([adapter] { adapter->Release(); }); DXGI_ADAPTER_DESC1 desc; adapter->GetDesc1(&desc); QString gpuName = QString::fromWCharArray(desc.Description); // Try creating the driver to see what D3D feature level it supports. D3D_FEATURE_LEVEL gpuFeatureLevel = D3D_FEATURE_LEVEL_9_1; result = D3D11CreateDevice(adapter, D3D_DRIVER_TYPE_UNKNOWN, nullptr, 0, nullptr, 0, D3D11_SDK_VERSION, nullptr, &gpuFeatureLevel, nullptr); if (FAILED(result)) { logger.error() << "D3D Device" << gpuName << "failed:" << QString::number((quint32)result, 16); } else { if (gpuFeatureLevel < minFeatureLevel) { minFeatureLevel = gpuFeatureLevel; } logger.debug() << "D3D Device" << gpuName << "supports D3D:" << QString::number(gpuFeatureLevel, 16); } } // D3D version 11.0 shader level 5, is required for GPU rendering. return (minFeatureLevel < D3D_FEATURE_LEVEL_11_0); }