#include "pch.h" #include "tunnel.h" #include "usrerr.h" #include #include #include #include "globalcfg.h" #include "misc.h" #include "network.h" #pragma comment(lib, "Shlwapi.lib") #pragma comment(lib, "Winmm.lib") static NET_SHARE_MODE g_CurShareMode = ICS_SHARE_MODE; NET_SHARE_MODE GetCurrentNetShareMode() { return g_CurShareMode; } void SetCurrentNetShareMode(NET_SHARE_MODE shareMode) { g_CurShareMode = shareMode; } int GetWireGuardWorkMode(bool *pIsWorkServer) { if (pIsWorkServer == nullptr) { SPDLOG_ERROR(TEXT("Input pIsWorkServer params error")); return -ERR_INPUT_PARAMS; } *pIsWorkServer = GetGlobalCfgInfo()->isWorkServer; return ERR_SUCCESS; } int WireGuardInstallDefaultServerService(bool bInstall) { TCHAR cfgVal[MAX_PATH]; GetPrivateProfileString(CFG_WIREGUARD_SECTION, CFG_WGCFG_PATH, TEXT(""), cfgVal, MAX_PATH, GetGlobalCfgInfo()->cfgPath); if (lstrlen(cfgVal) > 0) { if (PathFileExists(cfgVal)) { int ret; TCHAR svrName[MAX_PATH]; StringCbCopy(svrName, MAX_PATH, cfgVal); PathStripPath(svrName); PathRemoveExtension(svrName); if (bInstall) { ret = WireGuardInstallServerService(cfgVal); //CreateWireGuardService(svrName, cfgVal); } else { ret = RemoveGuardService(svrName, true); } if (bInstall && ret == ERR_SUCCESS) { int retry = 10; do { ret = WaitNetAdapterConnected(svrName, 1000); } while (ret != ERR_SUCCESS && retry--); } return ret; } else { SPDLOG_ERROR(TEXT("WireGuard configure file [{0}] not found"), cfgVal); return -ERR_FILE_NOT_EXISTS; } } else { SPDLOG_ERROR(TEXT("Configure [{0}] = {1} not found"), CFG_WGCFG_PATH, cfgVal); return -ERR_ITEM_UNEXISTS; } } int WireGuardInstallServerService(const TCHAR *pTunnelCfgPath) { // 卸载服务 TCHAR svrName[MAX_PATH]; int ret; StringCbCopy(svrName, MAX_PATH, pTunnelCfgPath); PathStripPath(svrName); PathRemoveExtension(svrName); if (pTunnelCfgPath == nullptr || lstrlen(pTunnelCfgPath) == 0) { SPDLOG_ERROR(TEXT("Input pTunnelCfgPath params error")); return -ERR_INPUT_PARAMS; } if (!PathFileExists(pTunnelCfgPath)) { SPDLOG_ERROR(TEXT("WireGuard configure file {0} unexists."), pTunnelCfgPath); return -ERR_ITEM_UNEXISTS; } if ((ret = CreateWireGuardService(svrName, pTunnelCfgPath)) != ERR_SUCCESS) { SPDLOG_ERROR(TEXT("Create WireGuard Service Error({0}): {1}, {2} "), ret, svrName, pTunnelCfgPath); return ret; } return ERR_SUCCESS; } int WireGuardUnInstallServerService(const TCHAR *pTunnelName) { // 卸载服务 int ret; if (pTunnelName == nullptr || lstrlen(pTunnelName) == 0) { SPDLOG_ERROR(TEXT("Input pTunnelName params error")); return -ERR_INPUT_PARAMS; } if ((ret = RemoveGuardService(pTunnelName, true)) != ERR_SUCCESS) { SPDLOG_ERROR(TEXT("Stop WireGuard Service Error: {0}"), ret); return ret; } return ERR_SUCCESS; } int IsWireGuardServerInstalled(bool *pIsInstalled) { DWORD dwStatus; int ret; if (pIsInstalled == nullptr) { SPDLOG_ERROR(TEXT("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; } int IsWireGuardServerRunning(const TCHAR *pIfName, bool *pIsRunning) { return GetWireGuardServiceStatus(pIfName, pIsRunning); } 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(TEXT("WireGuard Name error: {0}"), pWgConfig->Name); return -ERR_INPUT_PARAMS; } if (FAILED(StringCbLength(pWgConfig->Address, 32, &length)) || 0 == length) { SPDLOG_ERROR(TEXT("WireGuard Address error: {0}"), pWgConfig->Address); return -ERR_INPUT_PARAMS; } if (FAILED(StringCbLength(pWgConfig->PrivateKey, 64, &length)) || 0 == length) { SPDLOG_ERROR(TEXT("WireGuard Private key error: {0}"), pWgConfig->PrivateKey); return -ERR_INPUT_PARAMS; } if (FAILED(StringCbLength(pWgConfig->SvrPubKey, 64, &length)) || 0 == length) { SPDLOG_ERROR(TEXT("WireGuard Server Public key error: {0}"), pWgConfig->SvrPubKey); return -ERR_INPUT_PARAMS; } if (FAILED(StringCbLength(pWgConfig->AllowNet, 256, &length)) || 0 == length) { SPDLOG_ERROR(TEXT("WireGuard Allow Client Network error: {0}"), pWgConfig->AllowNet); return -ERR_INPUT_PARAMS; } if (FAILED(StringCbLength(pWgConfig->ServerURL, 256, &length)) || 0 == length) { SPDLOG_ERROR(TEXT("WireGuard Server Network error: {0}"), pWgConfig->ServerURL); return -ERR_INPUT_PARAMS; } #pragma endregion 参数检查 pBuf = static_cast(malloc(bufSize)); if (pBuf == nullptr) { SPDLOG_ERROR(TEXT("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(TEXT("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(TEXT("Format string error: {0}"), GetLastError()); free(pBuf); ::CloseHandle(hFile); return -ERR_MEMORY_STR; } if (FAILED(StringCbLength(pBuf, bufSize, &length))) { SPDLOG_ERROR(TEXT("Get string \'{0}\' length error: {1}"), pBuf, GetLastError()); free(pBuf); ::CloseHandle(hFile); return -ERR_MEMORY_STR; } SPDLOG_DEBUG(TEXT("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(TEXT("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; } 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(TEXT("WireGuard Name error: {0}"), pWgConfig->Name); return -ERR_INPUT_PARAMS; } if (FAILED(StringCbLength(pWgConfig->Address, 32, &length)) || 0 == length) { SPDLOG_ERROR(TEXT("WireGuard Address error: {0}"), pWgConfig->Address); return -ERR_INPUT_PARAMS; } if (FAILED(StringCbLength(pWgConfig->PrivateKey, 64, &length)) || 0 == length) { SPDLOG_ERROR(TEXT("WireGuard Private key error: {0}"), pWgConfig->PrivateKey); return -ERR_INPUT_PARAMS; } if (pWgConfig->ListenPort <= 1024 || pWgConfig->ListenPort >= 65535) { SPDLOG_ERROR(TEXT("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(TEXT("WireGuard Client Public key error: {0}"), pWgConfig->CliPubKey); return -ERR_INPUT_PARAMS; } if (FAILED(StringCbLength(pWgConfig->AllowNet, 256, &length)) || 0 == length) { SPDLOG_ERROR(TEXT("WireGuard Allow Client Network error: {0}"), pWgConfig->AllowNet); return -ERR_INPUT_PARAMS; } #pragma endregion 参数检查 pBuf = static_cast(malloc(bufSize)); if (pBuf == nullptr) { SPDLOG_ERROR(TEXT("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(TEXT("CreatFile [{0}] error: {1}"), cfgPath, GetLastError()); free(pBuf); return -ERR_OPEN_FILE; } // 清空文件 SetFilePointer(hFile, 0, nullptr, FILE_BEGIN); SetEndOfFile(hFile); 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(TEXT("Format string error: {0}"), GetLastError()); free(pBuf); ::CloseHandle(hFile); return -ERR_MEMORY_STR; } if (FAILED(StringCbLength(pBuf, bufSize, &length))) { SPDLOG_ERROR(TEXT("Get string \'{0}\' length error: {1}"), pBuf, GetLastError()); free(pBuf); ::CloseHandle(hFile); return -ERR_MEMORY_STR; } SPDLOG_DEBUG(TEXT("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(TEXT("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; } #if 0 /** * @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(TEXT("Run command [{0}] error: {1}"), cmdBuffer, ret); return -ERR_CALL_SHELL; } SPDLOG_DEBUG(TEXT("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(TEXT("Run command [{0}] error: {1}"), cmdBuffer, ret); return -ERR_CALL_SHELL; } StringCbCopy(pPubKey, pubkeySize, cmdResult); SPDLOG_DEBUG(TEXT("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; } /** * @brief 安装 Windows NAT 自定义 PowerShell 命令 * @return 0: 成功, 小于0 失败 @see USER_ERRNO * - -ERR_INPUT_PARAMS 输入参数错误 * - -ERR_OPEN_FILE 打开文件失败 * - -ERR_MEMORY_STR 字符串处理 * - -ERR_ITEM_UNEXISTS 资源不存在 * - -ERR_CALL_SHELL 调用系统命令行失败 * - ERR_SUCCESS 成功 */ 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