NetTunnelWindows/NetTunnelSDK/wireguard.cpp

762 lines
27 KiB
C++

#include "pch.h"
#include "tunnel.h"
#include "usrerr.h"
#include <strsafe.h>
#include <tchar.h>
#include <shlwapi.h>
#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<TCHAR *>(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<DWORD>(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<TCHAR *>(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<DWORD>(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<LPSTR>(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<LPSTR>(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<DWORD>(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