#include "pch.h" #include "tunnel.h" #include "usrerr.h" #include #include #include #include "globalcfg.h" #include "misc.h" //#include "resource.h" #pragma comment(lib, "Shlwapi.lib") //#define PSCMD_RES_ID (IDR_TXT1) constexpr auto WINENVBUF_SIZE = (4096); /** * @brief 判断当前网络服务工作模式 客户端/服务端 * @param[out] pIsWorkServer 工作模式 * - TRUE 服务端 * - FALSE 客户端 * @return 函数执行结果 0: 成功, 小于0 失败 @see USER_ERRNO * - -ERR_INPUT_PARAMS 输入参数错误 * - ERR_SUCCESS 成功 */ int GetWireGuardWorkMode(bool *pIsWorkServer) { if (pIsWorkServer == nullptr) { SPDLOG_ERROR("Input pIsWorkServer params error"); return -ERR_INPUT_PARAMS; } *pIsWorkServer = GetGlobalCfgInfo()->isWorkServer; return ERR_SUCCESS; } /** * @brief 安装/卸载 WireGuard 服务 * @param[in] bInstall TRUE 安装服务, FALSE 卸载服务 * @return 函数执行结果 0: 成功, 小于0 失败 @see USER_ERRNO */ int WireGuardInstallServerService(bool bInstall) { TCHAR cfgVal[MAX_PATH]; DWORD retCode; GetPrivateProfileString(CFG_WIREGUARD_SECTION, CFG_WGCFG_PATH, TEXT(""), cfgVal, MAX_PATH, GetGlobalCfgInfo()->cfgPath); if (lstrlen(cfgVal) > 0) { if (PathFileExists(cfgVal)) { TCHAR cmdBuf[MAX_PATH]; int ret; if (bInstall) { // 安装服务 StringCbPrintf(cmdBuf, MAX_PATH, TEXT("\"%s\" /installtunnelservice \"%s\""), GetGlobalCfgInfo()->wireguardCfg.wireguardPath, cfgVal); } else { // 卸载服务 TCHAR svrName[MAX_PATH]; StringCbCopy(svrName, MAX_PATH, cfgVal); PathStripPath(svrName); PathRemoveExtension(svrName); StringCbPrintf(cmdBuf, MAX_PATH, TEXT("\"%s\" /uninstalltunnelservice %s"), GetGlobalCfgInfo()->wireguardCfg.wireguardPath, svrName); } if ((ret = RunCommand(cmdBuf, nullptr, 0, &retCode)) != ERR_SUCCESS) { SPDLOG_ERROR("Run command [{0}] error: {1}", cmdBuf, ret); return -ERR_CALL_SHELL; } SPDLOG_DEBUG("Run command [{0}]", cmdBuf); return ERR_SUCCESS; } else { SPDLOG_ERROR("WireGuard configure file [{0}] not found", cfgVal); return -ERR_FILE_NOT_EXISTS; } } else { SPDLOG_ERROR("Configure [{0}] not found", CFG_WGCFG_PATH); return -ERR_ITEM_UNEXISTS; } } /** * @brief 获取当前 WireGuard 服务是否安装 * @param[out] pIsInstalled WireGuard 服务安装状态 * - TRUE 已经安装 * - FALSE 未安装 * @return 0: 成功, 小于0 失败 @see USER_ERRNO * - -ERR_INPUT_PARAMS 输入参数错误 * - -ERR_OPEN_SCM, 打开服务管理器设备 * - -ERR_OPEN_SERVICE, 打开服务失败 * - -ERR_GET_SERVICESSTATUS, 获取服务状态失败 * - ERR_SUCCESS 成功 */ int IsWireGuardServerInstalled(bool *pIsInstalled) { DWORD dwStatus; int ret; if (pIsInstalled == nullptr) { SPDLOG_ERROR("Input pIsInstalled params error"); return -ERR_INPUT_PARAMS; } *pIsInstalled = false; ret = GetWindowsServiceStatus(TEXT("WireGuard"), &dwStatus); if (ret == ERR_SUCCESS) { switch (dwStatus) { case SERVICE_CONTINUE_PENDING: case SERVICE_RUNNING: case SERVICE_START_PENDING: *pIsInstalled = true; break; default: *pIsInstalled = false; break; } } return ret; } /** * @brief 创建 WireGuard 客户端配置文件 * @param[in] pWgConfig 配置文件相关配置项 @see WGCLIENT_CONFIG * @return 函数执行结果 0: 成功, 小于0 失败 @see USER_ERRNO * - -ERR_INPUT_PARAMS 输入参数错误 * - -ERR_MALLOC_MEMORY 分配内存失败 * - -ERR_OPEN_FILE 打开文件失败 * - -ERR_MEMORY_STR 字符串处理失败 * - ERR_SUCCESS 成功 */ int WireGuardCreateClientConfig(const PWGCLIENT_CONFIG pWgConfig) { const size_t bufSize = 4096 * sizeof(TCHAR); const TCHAR cfgFormat[] = TEXT( "[Interface]\nPrivateKey = %s\nAddress = %s\n\n[Peer]\nPublicKey = %s\nAllowedIPs = %s\nEndpoint = " "%s\nPersistentKeepalive = 30\n"); TCHAR cfgPath[MAX_PATH]; size_t length; HANDLE hFile; TCHAR *pBuf; #pragma region if (pWgConfig == nullptr) { return -ERR_INPUT_PARAMS; } if (FAILED(StringCbLength(pWgConfig->Name, 64, &length)) || 0 == length) { SPDLOG_ERROR("WireGuard Name error: {0}", pWgConfig->Name); return -ERR_INPUT_PARAMS; } if (FAILED(StringCbLength(pWgConfig->Address, 32, &length)) || 0 == length) { SPDLOG_ERROR("WireGuard Address error: {0}", pWgConfig->Address); return -ERR_INPUT_PARAMS; } if (FAILED(StringCbLength(pWgConfig->PrivateKey, 64, &length)) || 0 == length) { SPDLOG_ERROR("WireGuard Private key error: {0}", pWgConfig->PrivateKey); return -ERR_INPUT_PARAMS; } if (FAILED(StringCbLength(pWgConfig->SvrPubKey, 64, &length)) || 0 == length) { SPDLOG_ERROR("WireGuard Server Public key error: {0}", pWgConfig->SvrPubKey); return -ERR_INPUT_PARAMS; } if (FAILED(StringCbLength(pWgConfig->AllowNet, 256, &length)) || 0 == length) { SPDLOG_ERROR("WireGuard Allow Client Network error: {0}", pWgConfig->AllowNet); return -ERR_INPUT_PARAMS; } if (FAILED(StringCbLength(pWgConfig->ServerURL, 256, &length)) || 0 == length) { SPDLOG_ERROR("WireGuard Server Network error: {0}", pWgConfig->ServerURL); return -ERR_INPUT_PARAMS; } #pragma endregion 参数检查 pBuf = static_cast(malloc(bufSize)); if (pBuf == nullptr) { SPDLOG_ERROR("Malloc {1} bytes memory error: {0}", GetLastError(), bufSize); return -ERR_MALLOC_MEMORY; } memset(pBuf, 0, bufSize); StringCbPrintf(cfgPath, MAX_PATH, "%s\\%s", GetGlobalCfgInfo()->configDirectory, GetGlobalCfgInfo()->userCfg.userName); // 如果当前用户配置目录不存在则自动创建 if (!PathFileExists(cfgPath)) { if (!CreateDirectory(cfgPath, nullptr)) { SPDLOG_ERROR(TEXT("Create configure directory '{0}' error."), cfgPath); return -ERR_CREATE_FILE; } } StringCbPrintf(cfgPath, MAX_PATH, "%s\\%s\\%s.conf", GetGlobalCfgInfo()->workDirectory, GetGlobalCfgInfo()->userCfg.userName, pWgConfig->Name); hFile = CreateFile(cfgPath, // name of the write GENERIC_WRITE | GENERIC_READ, // open for writing FILE_SHARE_READ, // do not share nullptr, // default security CREATE_ALWAYS, // create new file only FILE_ATTRIBUTE_NORMAL, // normal file nullptr); // no attr. template if (hFile == INVALID_HANDLE_VALUE) { SPDLOG_ERROR("CreatFile [{0}] error: {1}", cfgPath, GetLastError()); free(pBuf); return -ERR_OPEN_FILE; } // 保存到配置文件中 WritePrivateProfileString(CFG_WIREGUARD_SECTION, CFG_WGCFG_PATH, cfgPath, GetGlobalCfgInfo()->cfgPath); if (FAILED(StringCbPrintf(pBuf, bufSize, cfgFormat, pWgConfig->PrivateKey, pWgConfig->Address, pWgConfig->SvrPubKey, pWgConfig->AllowNet, pWgConfig->ServerURL))) { SPDLOG_ERROR("Format string error: {0}", GetLastError()); free(pBuf); ::CloseHandle(hFile); return -ERR_MEMORY_STR; } if (FAILED(StringCbLength(pBuf, bufSize, &length))) { SPDLOG_ERROR("Get string \'{0}\' length error: {1}", pBuf, GetLastError()); free(pBuf); ::CloseHandle(hFile); return -ERR_MEMORY_STR; } SPDLOG_DEBUG("WG Client Configure:\n{0}", pBuf); if (!WriteFile(hFile, // open file handle pBuf, // start of data to write static_cast(length), // number of bytes to write nullptr, // number of bytes that were written nullptr)) { SPDLOG_ERROR("WriteFile [{0}] error: {1}", cfgPath, GetLastError()); free(pBuf); ::CloseHandle(hFile); return -ERR_OPEN_FILE; } StringCbCopy(GetGlobalCfgInfo()->wgClientCfg.wgName, 260, pWgConfig->Name); StringCbCopy(GetGlobalCfgInfo()->wgClientCfg.wgIpaddr, MAX_IP_LEN, pWgConfig->Address); StringCbCopy(GetGlobalCfgInfo()->wgClientCfg.wgCfgPath, MAX_PATH, cfgPath); ::CloseHandle(hFile); return ERR_SUCCESS; } /** * @brief 创建 WireGuard 服务端配置文件 * @param[in] pWgConfig 配置文件相关配置项 @see WGSERVER_CONFIG * @return 函数执行结果 0: 成功, 小于0 失败 @see USER_ERRNO * - -ERR_INPUT_PARAMS 输入参数错误 * - -ERR_MALLOC_MEMORY 分配内存失败 * - -ERR_OPEN_FILE 打开文件失败 * - -ERR_MEMORY_STR 字符串处理失败 * - ERR_SUCCESS 成功 */ int WireGuardCreateServerConfig(const PWGSERVER_CONFIG pWgConfig) { const size_t bufSize = 4096 * sizeof(TCHAR); const TCHAR cfgFormat[] = TEXT( "[Interface]\nAddress = %s\nListenPort = %d\nPrivateKey = %s\n\n[Peer]\nPublicKey = %s\nAllowedIPs = %s\n"); TCHAR cfgPath[MAX_PATH]; size_t length; HANDLE hFile; TCHAR *pBuf; #pragma region if (pWgConfig == nullptr) { return -ERR_INPUT_PARAMS; } if (FAILED(StringCbLength(pWgConfig->Name, 64, &length)) || 0 == length) { SPDLOG_ERROR("WireGuard Name error: {0}", pWgConfig->Name); return -ERR_INPUT_PARAMS; } if (FAILED(StringCbLength(pWgConfig->Address, 32, &length)) || 0 == length) { SPDLOG_ERROR("WireGuard Address error: {0}", pWgConfig->Address); return -ERR_INPUT_PARAMS; } if (FAILED(StringCbLength(pWgConfig->PrivateKey, 64, &length)) || 0 == length) { SPDLOG_ERROR("WireGuard Private key error: {0}", pWgConfig->PrivateKey); return -ERR_INPUT_PARAMS; } if (pWgConfig->ListenPort <= 1024 || pWgConfig->ListenPort >= 65535) { SPDLOG_ERROR("WireGuard Listen port error: {0}, should be in arrange (1024, 65535)", pWgConfig->ListenPort); return -ERR_INPUT_PARAMS; } if (FAILED(StringCbLength(pWgConfig->CliPubKey, 64, &length)) || 0 == length) { SPDLOG_ERROR("WireGuard Client Public key error: {0}", pWgConfig->CliPubKey); return -ERR_INPUT_PARAMS; } if (FAILED(StringCbLength(pWgConfig->AllowNet, 256, &length)) || 0 == length) { SPDLOG_ERROR("WireGuard Allow Client Network error: {0}", pWgConfig->AllowNet); return -ERR_INPUT_PARAMS; } #pragma endregion 参数检查 pBuf = static_cast(malloc(bufSize)); if (pBuf == nullptr) { SPDLOG_ERROR("Malloc {1} bytes memory error: {0}", GetLastError(), bufSize); return -ERR_MALLOC_MEMORY; } memset(pBuf, 0, bufSize); StringCbPrintf(cfgPath, MAX_PATH, "%s\\%s", GetGlobalCfgInfo()->configDirectory, GetGlobalCfgInfo()->userCfg.userName); // 如果当前用户配置目录不存在则自动创建 if (!PathFileExists(cfgPath)) { if (!CreateDirectory(cfgPath, nullptr)) { SPDLOG_ERROR(TEXT("Create configure directory '{0}' error."), cfgPath); return -ERR_CREATE_FILE; } } StringCbPrintf(cfgPath, MAX_PATH, "%s\\%s\\%s.conf", GetGlobalCfgInfo()->configDirectory, GetGlobalCfgInfo()->userCfg.userName, pWgConfig->Name); hFile = CreateFile(cfgPath, // name of the write GENERIC_WRITE | GENERIC_READ, // open for writing FILE_SHARE_READ, // do not share nullptr, // default security CREATE_ALWAYS, // create new file only FILE_ATTRIBUTE_NORMAL, // normal file nullptr); // no attr. template if (hFile == INVALID_HANDLE_VALUE) { SPDLOG_ERROR("CreatFile [{0}] error: {1}", cfgPath, GetLastError()); free(pBuf); return -ERR_OPEN_FILE; } WritePrivateProfileString(CFG_WIREGUARD_SECTION, CFG_WGCFG_PATH, cfgPath, GetGlobalCfgInfo()->cfgPath); if (FAILED(StringCbPrintf(pBuf, bufSize, cfgFormat, pWgConfig->Address, pWgConfig->ListenPort, pWgConfig->PrivateKey, pWgConfig->CliPubKey, pWgConfig->AllowNet))) { SPDLOG_ERROR("Format string error: {0}", GetLastError()); free(pBuf); ::CloseHandle(hFile); return -ERR_MEMORY_STR; } if (FAILED(StringCbLength(pBuf, bufSize, &length))) { SPDLOG_ERROR("Get string \'{0}\' length error: {1}", pBuf, GetLastError()); free(pBuf); ::CloseHandle(hFile); return -ERR_MEMORY_STR; } SPDLOG_DEBUG("WG Server Configure:\n{0}", pBuf); if (FALSE == WriteFile(hFile, // open file handle pBuf, // start of data to write static_cast(length), // number of bytes to write nullptr, // number of bytes that were written nullptr)) // no overlapped structure) { SPDLOG_ERROR("WriteFile [{0}] error: {1}", cfgPath, GetLastError()); free(pBuf); ::CloseHandle(hFile); return -ERR_OPEN_FILE; } ::CloseHandle(hFile); StringCbCopy(GetGlobalCfgInfo()->wgServerCfg.wgName, 260, pWgConfig->Name); StringCbCopy(GetGlobalCfgInfo()->wgServerCfg.wgIpaddr, MAX_IP_LEN, pWgConfig->Address); StringCbCopy(GetGlobalCfgInfo()->wgServerCfg.wgCfgPath, MAX_PATH, cfgPath); return ERR_SUCCESS; } /** * @brief 创建 WireGuard 密钥对 * @param[out] pPubKey 公钥缓冲区 * @param[in] pubkeySize 公钥缓冲区大小(字节数) * @param[out] pPrivKey 私钥缓冲区 * @param[in] privKeySize 私钥缓冲区大小(字节数) * @return 函数执行结果 0: 成功, 小于0 失败 @see USER_ERRNO * - -ERR_ITEM_UNEXISTS WireGuard 未配置或未安装 * - -ERR_CALL_SHELL 调用操作系统命令行工具失败 * - ERR_SUCCESS 成功 */ int GenerateWireguardKeyPairs(TCHAR *pPubKey, int pubkeySize, TCHAR *pPrivKey, int privKeySize) { int ret; DWORD retCode; TCHAR cmdBuffer[MAX_PATH]; TCHAR cmdResult[MAX_PATH]; PSDK_CONFIG pCfg = GetGlobalCfgInfo(); // WireGuard 不存在或者未配置目录 if (!pCfg->wireguardCfg.wgExists || !pCfg->wireguardCfg.wireguardExists) { return -ERR_ITEM_UNEXISTS; } memset(cmdBuffer, 0, MAX_PATH); memset(cmdResult, 0, MAX_PATH); StringCbPrintf(cmdBuffer, MAX_PATH, TEXT("cmd.exe /C \"%s\" genkey"), pCfg->wireguardCfg.wgPath); if ((ret = RunCommand(cmdBuffer, cmdResult, MAX_PATH, &retCode)) != ERR_SUCCESS) { SPDLOG_ERROR("Run command [{0}] error: {1}", cmdBuffer, ret); return -ERR_CALL_SHELL; } SPDLOG_DEBUG("Run command [{0}] resutl \'{1}\'", cmdBuffer, cmdResult); StringCbCopy(pPrivKey, privKeySize, cmdResult); memset(cmdBuffer, 0, MAX_PATH); StringCbPrintf(cmdBuffer, MAX_PATH, TEXT("cmd.exe /C echo %s | \"%s\" pubkey"), cmdResult, pCfg->wireguardCfg.wgPath); memset(cmdResult, 0, MAX_PATH); if ((ret = RunCommand(cmdBuffer, cmdResult, MAX_PATH, &retCode)) != ERR_SUCCESS) { SPDLOG_ERROR("Run command [{0}] error: {1}", cmdBuffer, ret); return -ERR_CALL_SHELL; } StringCbCopy(pPubKey, pubkeySize, cmdResult); SPDLOG_DEBUG("Run command [{0}] resutl \'{1}\'", cmdBuffer, cmdResult); return ERR_SUCCESS; } /** * @brief 设置 wireguard.exe 程序路径 * @param[in] pPath wireguard.exe 程序路径 * @return 函数执行结果 0: 成功, 小于0 失败 @see USER_ERRNO * - -ERR_INPUT_PARAMS 输入参数错误 * - -ERR_ITEM_UNEXISTS 文件不存在 * - ERR_SUCCESS 成功 */ int SetWireguardPath(const TCHAR *pPath) { if (pPath == nullptr) { return -ERR_INPUT_PARAMS; } if (PathFileExists(pPath)) { TCHAR wgPath[MAX_PATH]; SPDLOG_DEBUG(TEXT("Used configure file:{0}"), GetGlobalCfgInfo()->cfgPath); WritePrivateProfileString(CFG_WIREGUARD_SECTION, CFG_WIREGUARD_PATH, pPath, GetGlobalCfgInfo()->cfgPath); SPDLOG_DEBUG(TEXT("Save configure: {1} --> {0}"), pPath, CFG_WIREGUARD_PATH); StringCbCopy(wgPath, MAX_PATH, pPath); if (TCHAR *pIndex = _tcsrchr(wgPath, '\\')) { *pIndex = 0; StringCbCat(wgPath, MAX_PATH, "\\wg.exe"); WritePrivateProfileString(CFG_WIREGUARD_SECTION, CFG_WG_PATH, wgPath, GetGlobalCfgInfo()->cfgPath); SPDLOG_DEBUG(TEXT("Save configure: {1} --> {0}"), wgPath, CFG_WG_PATH); } return ERR_SUCCESS; } else { SPDLOG_ERROR(TEXT("WireGuard not found: {0}"), pPath); return -ERR_ITEM_UNEXISTS; } } /** * @brief 查找 WireGuard 运行环境 * @param[out] pFullPath wireguard.exe 程序路径 * @param[in] maxSize pFullPath 缓冲区最大字节数 * @return 函数执行结果 0: 成功, 小于0 失败 @see USER_ERRNO * - -ERR_INPUT_PARAMS 输入参数错误 * - -ERR_MALLOC_MEMORY 分配内存失败 * - -ERR_FILE_NOT_EXISTS 文件不存在 * - ERR_SUCCESS 成功 */ int FindWireguardExe(TCHAR *pFullPath, int maxSize) { TCHAR path[MAX_PATH]; TCHAR wireguardPath[MAX_PATH]; DWORD dwRet; LPSTR pEnvBuf; TCHAR *token, *p = nullptr; GetPrivateProfileString(CFG_WIREGUARD_SECTION, CFG_WIREGUARD_PATH, TEXT(""), wireguardPath, MAX_PATH, GetGlobalCfgInfo()->cfgPath); if (PathFileExists(wireguardPath)) { if (pFullPath && maxSize > 0) { StringCbCopy(pFullPath, maxSize, wireguardPath); } StringCbCopy(GetGlobalCfgInfo()->wireguardCfg.wireguardPath, MAX_PATH, wireguardPath); GetGlobalCfgInfo()->wireguardCfg.wireguardExists = TRUE; SPDLOG_DEBUG(TEXT("Ini found WireGuard at: {0}"), wireguardPath); GetPrivateProfileString(CFG_WIREGUARD_SECTION, CFG_WG_PATH, TEXT(""), wireguardPath, MAX_PATH, GetGlobalCfgInfo()->cfgPath); if (PathFileExists(wireguardPath)) { StringCbCopy(GetGlobalCfgInfo()->wireguardCfg.wgPath, MAX_PATH, wireguardPath); GetGlobalCfgInfo()->wireguardCfg.wgExists = TRUE; SPDLOG_DEBUG(TEXT("Ini found WireGuard Tools at: {0}"), wireguardPath); } return ERR_SUCCESS; } StringCbCopy(wireguardPath, MAX_PATH, GetGlobalCfgInfo()->systemDirectory); PathStripToRoot(wireguardPath); StringCbCat(wireguardPath, MAX_PATH, TEXT("Program Files\\WireGuard\\wireguard.exe")); if (PathFileExists(wireguardPath)) { // 保存路径到配置文件 SetWireguardPath(wireguardPath); GetGlobalCfgInfo()->wireguardCfg.wireguardExists = TRUE; PathRemoveFileSpec(wireguardPath); StringCbCat(wireguardPath, MAX_PATH, TEXT("\\wg.exe")); if (PathFileExists(wireguardPath)) { GetGlobalCfgInfo()->wireguardCfg.wgExists = TRUE; } return ERR_SUCCESS; } // 从环境变量中查找 pEnvBuf = static_cast(malloc(WINENVBUF_SIZE)); if (nullptr == pEnvBuf) { SPDLOG_ERROR(TEXT("Malloc {0} bytes memory error"), WINENVBUF_SIZE); return -ERR_MALLOC_MEMORY; } dwRet = GetEnvironmentVariable(TEXT("path"), pEnvBuf, WINENVBUF_SIZE); if (0 == dwRet) { DWORD dwErr; dwErr = GetLastError(); if (ERROR_ENVVAR_NOT_FOUND == dwErr) { SPDLOG_DEBUG(TEXT("Environment variable path does not exist.")); free(pEnvBuf); return -ERR_FILE_NOT_EXISTS; } } else if (WINENVBUF_SIZE < dwRet) { const auto pBuf = static_cast(realloc(pEnvBuf, dwRet * sizeof(CHAR))); if (nullptr == pBuf) { SPDLOG_ERROR(TEXT("Malloc {0} bytes memory error"), dwRet * sizeof(CHAR)); free(pEnvBuf); return -ERR_MALLOC_MEMORY; } pEnvBuf = pBuf; dwRet = GetEnvironmentVariable("path", pEnvBuf, dwRet); if (!dwRet) { SPDLOG_ERROR(TEXT("GetEnvironmentVariable failed (%d)"), GetLastError()); free(pEnvBuf); return -ERR_FILE_NOT_EXISTS; } } token = strtok_s(pEnvBuf, TEXT(";"), &p); while (token != nullptr) { memset(path, 0, MAX_PATH); StringCbPrintfA(path, MAX_PATH, TEXT("%s\\wireguard.exe"), token); if (PathFileExists(path)) { if (pFullPath && maxSize > 0) { StringCbCopy(pFullPath, maxSize, path); } // 保存路径到配置文件 SetWireguardPath(path); SPDLOG_DEBUG(TEXT("Path Environment found WireGuard at: {0}"), path); StringCbCopy(GetGlobalCfgInfo()->wireguardCfg.wireguardPath, MAX_PATH, wireguardPath); GetGlobalCfgInfo()->wireguardCfg.wireguardExists = TRUE; memset(path, 0, MAX_PATH); StringCbPrintf(path, MAX_PATH, TEXT("%s\\wg.exe"), token); SPDLOG_DEBUG(TEXT("Find WireGuard tools at: {0}"), path); if (PathFileExists(path)) { StringCbCopy(GetGlobalCfgInfo()->wireguardCfg.wgPath, MAX_PATH, path); GetGlobalCfgInfo()->wireguardCfg.wgExists = TRUE; SPDLOG_DEBUG(TEXT("Path Environment found WireGuard tools at: {0}"), path); } //TODO: throw exception by C# call, why?????? //CloseHandle(hFind); free(pEnvBuf); return ERR_SUCCESS; } token = strtok_s(nullptr, TEXT(";"), &p); } free(pEnvBuf); return -ERR_FILE_NOT_EXISTS; } #if 0 int InstallWindowsNATCommand() { TCHAR psCmdPath[MAX_PATH]; // 如果已经安装则退出 if (IsCustomNatPSCmdInstalled()) { return ERR_SUCCESS; } StringCbPrintf(psCmdPath, MAX_PATH, TEXT("%s\\system32\\WindowsPowerShell\\v1.0\\Modules\\wireguard\\wireguard.psm1"), GetGlobalCfgInfo()->systemDirectory); const HANDLE hFile = CreateFile(psCmdPath, GENERIC_WRITE | GENERIC_READ, FILE_SHARE_READ, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr); if (hFile == INVALID_HANDLE_VALUE) { SPDLOG_ERROR("CreatFile [{0}] error: {1}", psCmdPath, GetLastError()); return -ERR_OPEN_FILE; } const HMODULE hMod = GetModuleHandle(TEXT("NetTunnelSDK.dll")); if (nullptr == hMod) { SPDLOG_ERROR(TEXT("Load NetTunnelSDK.dll module error")); ::CloseHandle(hFile); return -ERR_ITEM_UNEXISTS; } const HRSRC hRsrc = FindResource(hMod, MAKEINTRESOURCE(PSCMD_RES_ID), TEXT("TXT")); if (nullptr == hRsrc) { SPDLOG_ERROR(TEXT("Donot found resource {0} of type {1}"), PSCMD_RES_ID, TEXT("TXT")); ::CloseHandle(hFile); return -ERR_ITEM_UNEXISTS; } const DWORD resSize = SizeofResource(hMod, hRsrc); if (resSize == 0) { SPDLOG_ERROR(TEXT("Resource {0} of type {1} is empty"), PSCMD_RES_ID, TEXT("TXT")); ::CloseHandle(hFile); return -ERR_ITEM_UNEXISTS; } const HGLOBAL hGlobal = LoadResource(hMod, hRsrc); if (hGlobal == hRsrc) { SPDLOG_ERROR(TEXT("Load resource {0} of type {1} error"), PSCMD_RES_ID, TEXT("TXT")); ::CloseHandle(hFile); return -ERR_ITEM_UNEXISTS; } if (const LPVOID pBuffer = LockResource(hGlobal)) { if (!WriteFile(hFile, // open file handle pBuffer, // start of data to write static_cast(resSize), // number of bytes to write nullptr, // number of bytes that were written nullptr)) { SPDLOG_ERROR("WriteFile [{0}] error: {1}", psCmdPath, GetLastError()); GlobalUnlock(hGlobal); ::CloseHandle(hFile); return -ERR_OPEN_FILE; } } GlobalUnlock(hGlobal); ::CloseHandle(hFile); return ERR_SUCCESS; } int WireGuardNetConnectionSharingEnable() { int ret; DWORD retCode; TCHAR cmdResult[MAX_PATH] = {}; TCHAR cmdBuf[] = TEXT("PowerShell -NoProfile -NonInteractive -WindowStyle Hidden -ExecutionPolicy Bypass Invoke-Command -ArgumentList 'wg_cli' -ScriptBlock {param($IFNAME);$netShare = New-Object -ComObject HNetCfg.HNetShare;" "$privateConnection = $netShare.EnumEveryConnection |? { $netShare.NetConnectionProps.Invoke($_).Name -eq 'wg_cli' };" "$privateConfig = $netShare.INetSharingConfigurationForINetConnection.Invoke($privateConnection);" "Write-Output $privateConfig}"); if ((ret = RunCommand(cmdBuf, cmdResult, MAX_PATH, &retCode)) != ERR_SUCCESS) { SPDLOG_ERROR("Run command [{0}] error: {1}", cmdBuf, ret); return -ERR_CALL_SHELL; } SPDLOG_DEBUG("Run command [{0}] resutl \'{1}\' return {2}", cmdBuf, cmdResult, retCode); return ERR_SUCCESS; } #endif