341 lines
13 KiB
C++
341 lines
13 KiB
C++
#include "pch.h"
|
|
#include "tunnel.h"
|
|
#include <spdlog/spdlog.h>
|
|
#include <objbase.h>
|
|
|
|
#include "globalcfg.h"
|
|
#include "httplib.h"
|
|
#include "misc.h"
|
|
#include "network.h"
|
|
#include "protocol.h"
|
|
#include "usrerr.h"
|
|
#include "user.h"
|
|
|
|
#include <strsafe.h>
|
|
|
|
static HANDLE g_ControlSvrThread = nullptr;
|
|
static httplib::Server g_httpServer;
|
|
static USER_SERVER_CONFIG g_UserSvrCfg;
|
|
|
|
/**
|
|
* @brief 连接到服务端控制服务
|
|
* @param pUserSvrUrl 服务端控制服务 URL 地址
|
|
*/
|
|
void ConnectServerControlService(const TCHAR *pUserSvrUrl) {
|
|
InitControlServer(pUserSvrUrl);
|
|
}
|
|
|
|
static void HttpResponseError(httplib::Response &pRes, int errCode, const TCHAR *pErrMessage) {
|
|
ProtocolResponse<ResponseStatus> rsp;
|
|
std::string json;
|
|
|
|
if (errCode != ERR_SUCCESS) {
|
|
rsp.msgContent.errCode = errCode;
|
|
}
|
|
|
|
if (pErrMessage && lstrlen(pErrMessage) > 0) {
|
|
rsp.msgContent.errMessage = pErrMessage;
|
|
} else {
|
|
if (errCode == ERR_SUCCESS) {
|
|
rsp.msgContent.errMessage = TEXT("OK");
|
|
}
|
|
}
|
|
|
|
if (aigc::JsonHelper::ObjectToJson(rsp, json)) {
|
|
pRes.set_content(json, TEXT("application/json"));
|
|
} else {
|
|
SPDLOG_ERROR(TEXT("ProtocolResponse<ResponseStatus> to json error"));
|
|
}
|
|
}
|
|
|
|
int CreateControlService(PUSER_SERVER_CONFIG pSvr) {
|
|
static TCHAR g_CliNetwork[MAX_IP_LEN] = {};
|
|
static WGSERVER_CONFIG g_curCliConfig = {};
|
|
static std::mutex g_InterfaceMutex;
|
|
DWORD dwStatus = 0;
|
|
|
|
// HTTP 服务已经运行
|
|
if (g_httpServer.is_running()) {
|
|
return ERR_SUCCESS;
|
|
}
|
|
|
|
// 线程已经运行
|
|
if (g_ControlSvrThread && GetExitCodeThread(g_ControlSvrThread, &dwStatus) && dwStatus == STILL_ACTIVE) {
|
|
return -ERR_ITEM_EXISTS;
|
|
}
|
|
|
|
if (pSvr == nullptr) {
|
|
SPDLOG_ERROR(TEXT("Input pSvr params error"));
|
|
return -ERR_INPUT_PARAMS;
|
|
}
|
|
|
|
if (pSvr->svrListenPort <= 0 || pSvr->svrListenPort >= 65535) {
|
|
SPDLOG_ERROR(TEXT("Input svrListenPort params error {0}"), pSvr->svrListenPort);
|
|
return -ERR_INPUT_PARAMS;
|
|
}
|
|
|
|
if (lstrlen(pSvr->svrPrivateKey) != lstrlen(TEXT("4PPcnW3wYewNpoXjNoY3hQuCnzTNq/E9hhfU9/U6QmY="))) {
|
|
SPDLOG_ERROR(TEXT("Input svrPrivateKey params length error {0}"), pSvr->svrPrivateKey);
|
|
return -ERR_INPUT_PARAMS;
|
|
}
|
|
|
|
if (lstrlen(pSvr->svrAddress) == 0) {
|
|
SPDLOG_ERROR(TEXT("Input svrAddress params error {0}"), pSvr->svrAddress);
|
|
return -ERR_INPUT_PARAMS;
|
|
}
|
|
|
|
// 保存参数
|
|
memcpy(&g_UserSvrCfg, pSvr, sizeof(USER_SERVER_CONFIG));
|
|
|
|
g_httpServer.set_exception_handler([](const auto &req, auto &res, std::exception_ptr ep) {
|
|
const auto fmt = TEXT("<h1>Error 500</h1><p>%s</p>");
|
|
char buf[BUFSIZ];
|
|
try {
|
|
std::rethrow_exception(ep);
|
|
}
|
|
catch (std::exception &e) {
|
|
StringCbPrintf(buf, BUFSIZ, fmt, e.what());
|
|
}
|
|
catch (...) { // See the following NOTE
|
|
StringCbPrintf(buf, BUFSIZ, fmt, TEXT("Unknown Exception"));
|
|
}
|
|
res.set_content(buf, TEXT("text/html"));
|
|
res.status = 500;
|
|
});
|
|
|
|
g_httpServer.set_error_handler([](const auto &req, auto &res) {
|
|
const auto fmt = TEXT("<p>Error Status: <span style='color:red;'>%d</span></p>");
|
|
char buf[BUFSIZ];
|
|
StringCbPrintf(buf, BUFSIZ, fmt, res.status);
|
|
res.set_content(buf, TEXT("text/html"));
|
|
});
|
|
|
|
g_httpServer.Post(SET_CLIENTHEART_PATH, [](const httplib::Request &req, httplib::Response &res) {
|
|
ProtocolResponse<RspHeartParams> rsp;
|
|
std::string json;
|
|
|
|
rsp.msgContent.errCode = ERR_SUCCESS;
|
|
rsp.msgContent.errMessage = TEXT("OK");
|
|
|
|
if (aigc::JsonHelper::ObjectToJson(rsp, json)) {
|
|
res.set_content(json, TEXT("application/json"));
|
|
} else {
|
|
SPDLOG_ERROR(TEXT("ProtocolResponse<ResponseStatus> to json error"));
|
|
}
|
|
});
|
|
|
|
g_httpServer.Post(SET_CLIENTSTART_TUNNEL, [](const httplib::Request &req, httplib::Response &res) {
|
|
ProtocolRequest<ReqStartTunnelParams> reqData;
|
|
|
|
if (aigc::JsonHelper::JsonToObject(reqData, req.body)) {
|
|
int ret;
|
|
bool isSvrStart = false;
|
|
|
|
g_InterfaceMutex.lock();
|
|
// Because of COM return CO_E_FIRST
|
|
CoInitialize(nullptr);
|
|
|
|
// 判断先前是否启动过服务
|
|
if ((ret = IsWireGuardServerRunning(GetGlobalCfgInfo()->userCfg.userName, &isSvrStart)) != ERR_SUCCESS) {
|
|
// 返回获取系统服务错误,是否未安装
|
|
HttpResponseError(res, ret, TEXT("Not found WireGuard application in system"));
|
|
SPDLOG_ERROR(TEXT("IsWireGuardServerInstalled error: {0}"), ret);
|
|
g_InterfaceMutex.unlock();
|
|
return;
|
|
}
|
|
|
|
// 当前服务状态和需要执行的操作不同
|
|
if (isSvrStart != reqData.msgContent.isStart) {
|
|
if (reqData.msgContent.isStart) {
|
|
IP_INFO cliInfo;
|
|
IP_INFO tunnelInfo;
|
|
int retry = 3;
|
|
|
|
// 启动服务
|
|
ret = WireGuardInstallDefaultServerService(true);
|
|
if (ret != ERR_SUCCESS) {
|
|
// 返回启动服务失败
|
|
SPDLOG_ERROR(TEXT("WireGuardInstallDefaultServerService error: {0}"), ret);
|
|
HttpResponseError(res, ret, TEXT("Start WireGuard Tunnel Service error."));
|
|
g_InterfaceMutex.unlock();
|
|
return;
|
|
}
|
|
// 添加路由
|
|
if ((ret = GetIpV4InfoFromCIDR(g_CliNetwork, &cliInfo)) != ERR_SUCCESS) {
|
|
// 返回启动服务失败
|
|
SPDLOG_ERROR(TEXT("GetIpV4InfoFromCIDR ({1}) error: {0}"), ret, g_CliNetwork);
|
|
HttpResponseError(res, ret, TEXT("Parse IpAddress error."));
|
|
g_InterfaceMutex.unlock();
|
|
return;
|
|
}
|
|
|
|
if ((ret = GetIpV4InfoFromCIDR(g_UserSvrCfg.svrAddress, &tunnelInfo)) != ERR_SUCCESS) {
|
|
// 返回启动服务失败
|
|
SPDLOG_ERROR(TEXT("GetIpV4InfoFromCIDR ({1}) error: {0}"), ret, g_UserSvrCfg.svrAddress);
|
|
HttpResponseError(res, ret, TEXT("Parse tunnel ip address error."));
|
|
g_InterfaceMutex.unlock();
|
|
return;
|
|
}
|
|
|
|
do {
|
|
ret = AddRouteTable(cliInfo.ip, cliInfo.netmask, tunnelInfo.ip);
|
|
Sleep(1000);
|
|
} while (ret != ERR_SUCCESS && retry--);
|
|
|
|
if (ret != ERR_SUCCESS) {
|
|
// 返回启动服务失败
|
|
SPDLOG_ERROR(TEXT("Add Route {1}/{2} gateway {3} error: {0}"),
|
|
ret,
|
|
cliInfo.ip,
|
|
cliInfo.netmask,
|
|
tunnelInfo.ip);
|
|
HttpResponseError(res, ret, TEXT("Parse tunnel ip address error."));
|
|
g_InterfaceMutex.unlock();
|
|
return;
|
|
}
|
|
} else {
|
|
if ((ret = WireGuardUnInstallServerService(GetGlobalCfgInfo()->userCfg.userName)) != ERR_SUCCESS) {
|
|
// 返回停止服务失败
|
|
HttpResponseError(res, ret, TEXT("Stop pre running WireGuard service error"));
|
|
SPDLOG_ERROR(TEXT("WireGuardUnInstallServerService error: {0}"), ret);
|
|
g_InterfaceMutex.unlock();
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
HttpResponseError(res, ERR_SUCCESS, nullptr);
|
|
g_InterfaceMutex.unlock();
|
|
}
|
|
});
|
|
|
|
g_httpServer.Post(SET_CLIENTCFG_PATH, [](const httplib::Request &req, httplib::Response &res) {
|
|
ProtocolRequest<ReqUserSetCliCfgParams> reqData;
|
|
|
|
if (aigc::JsonHelper::JsonToObject(reqData, req.body)) {
|
|
int ret;
|
|
bool isSvrStart = false;
|
|
ProtocolResponse<RspUserSetCliCfgParams> rsp;
|
|
std::string json;
|
|
|
|
g_InterfaceMutex.lock();
|
|
// Because of COM return CO_E_FIRST
|
|
CoInitialize(nullptr);
|
|
|
|
// 判断先前是否启动过服务
|
|
if ((ret = IsWireGuardServerRunning(GetGlobalCfgInfo()->userCfg.userName, &isSvrStart)) != ERR_SUCCESS) {
|
|
// 返回获取系统服务错误,是否未安装
|
|
HttpResponseError(res, ret, TEXT("Not found WireGuard application in system"));
|
|
SPDLOG_ERROR(TEXT("IsWireGuardServerInstalled error: {0}"), ret);
|
|
g_InterfaceMutex.unlock();
|
|
return;
|
|
}
|
|
|
|
if (isSvrStart) {
|
|
SPDLOG_DEBUG(TEXT("WireGuardUnInstallServerService: {0}"), GetGlobalCfgInfo()->userCfg.userName);
|
|
if ((ret = WireGuardUnInstallServerService(GetGlobalCfgInfo()->userCfg.userName)) != ERR_SUCCESS) {
|
|
// 返回停止服务失败
|
|
HttpResponseError(res, ret, TEXT("Stop pre running WireGuard service error"));
|
|
SPDLOG_ERROR(TEXT("WireGuardUnInstallServerService error: {0}"), ret);
|
|
g_InterfaceMutex.unlock();
|
|
return;
|
|
}
|
|
}
|
|
|
|
memset(&g_curCliConfig, 0, sizeof(WGSERVER_CONFIG));
|
|
g_curCliConfig.ListenPort = g_UserSvrCfg.svrListenPort - 1;
|
|
StringCbCopy(g_curCliConfig.Name, 64, GetGlobalCfgInfo()->userCfg.userName);
|
|
StringCbCopy(g_curCliConfig.Address, 32, g_UserSvrCfg.svrAddress);
|
|
StringCbCopy(g_curCliConfig.PrivateKey, 64, g_UserSvrCfg.svrPrivateKey);
|
|
StringCbCopy(g_curCliConfig.CliPubKey, 64, reqData.msgContent.cliPublicKey.c_str());
|
|
StringCbCopy(g_CliNetwork, MAX_IP_LEN, reqData.msgContent.cliNetwork.c_str());
|
|
StringCbPrintf(g_curCliConfig.AllowNet,
|
|
256,
|
|
TEXT("%s,%s"),
|
|
reqData.msgContent.cliNetwork.c_str(),
|
|
reqData.msgContent.cliTunnelAddr.c_str());
|
|
|
|
// 创建 WireGuard 配置文件
|
|
ret = WireGuardCreateServerConfig(&g_curCliConfig);
|
|
if (ret != ERR_SUCCESS) {
|
|
// 返回写入 WireGuard 配置文件错误
|
|
HttpResponseError(res, ret, TEXT("Create WireGuard service configure file error"));
|
|
SPDLOG_ERROR(TEXT("WireGuardCreateServerConfig error: {0}"), ret);
|
|
g_InterfaceMutex.unlock();
|
|
return;
|
|
}
|
|
#if 0
|
|
// 启动服务
|
|
ret = WireGuardInstallDefaultServerService(true);
|
|
if (ret != ERR_SUCCESS) {
|
|
// 返回启动服务失败
|
|
return;
|
|
}
|
|
|
|
// 设置路由表
|
|
#endif
|
|
// 返回当前隧道信息
|
|
rsp.msgContent.errCode = ERR_SUCCESS;
|
|
rsp.msgContent.errMessage = TEXT("OK");
|
|
rsp.msgContent.svrNetwork = g_UserSvrCfg.svrAddress;
|
|
|
|
if (aigc::JsonHelper::ObjectToJson(rsp, json)) {
|
|
res.set_content(json, TEXT("application/json"));
|
|
} else {
|
|
SPDLOG_ERROR(TEXT("ProtocolResponse<RspUserSetCliCfgParams> to json error"));
|
|
HttpResponseError(res, ERR_JSON_CREATE, TEXT("ProtocolResponse<RspUserSetCliCfgParams> to json error"));
|
|
}
|
|
g_InterfaceMutex.unlock();
|
|
}
|
|
});
|
|
|
|
SPDLOG_DEBUG(TEXT("Start HTTP Service at {0}"), pSvr->svrListenPort);
|
|
if (!g_httpServer.bind_to_port(TEXT("0.0.0.0"), pSvr->svrListenPort)) {
|
|
SPDLOG_ERROR(TEXT("Start HTTP Service at {0} error"), pSvr->svrListenPort);
|
|
return -ERR_SOCKET_BIND_PORT;
|
|
}
|
|
|
|
g_ControlSvrThread = CreateThread(
|
|
nullptr, // Thread attributes
|
|
0, // Stack size (0 = use default)
|
|
[](LPVOID lpParameter) {
|
|
if (!g_httpServer.listen_after_bind()) {
|
|
SPDLOG_ERROR(TEXT("Start HTTP Service at {0} error"));
|
|
}
|
|
|
|
SPDLOG_DEBUG(TEXT("Http service exit....."));
|
|
|
|
return static_cast<DWORD>(0);
|
|
}, // Thread start address
|
|
nullptr, // Parameter to pass to the thread
|
|
0, // Creation flags
|
|
nullptr); // Thread id
|
|
|
|
if (g_ControlSvrThread == nullptr) {
|
|
// Thread creation failed.
|
|
// More details can be retrieved by calling GetLastError()
|
|
return -ERR_CREATE_THREAD;
|
|
}
|
|
|
|
g_httpServer.wait_until_ready();
|
|
|
|
return ERR_SUCCESS;
|
|
}
|
|
|
|
int StopControlService() {
|
|
if (g_httpServer.is_running()) {
|
|
g_httpServer.stop();
|
|
}
|
|
|
|
if (g_ControlSvrThread) {
|
|
// Wait for thread to finish execution
|
|
if (WaitForSingleObject(g_ControlSvrThread, 10 * 1000) == WAIT_TIMEOUT) {
|
|
SPDLOG_ERROR(TEXT("Waitting HTTP Service clost timeout"));
|
|
return -ERROR_TIMEOUT;
|
|
}
|
|
CloseHandle(g_ControlSvrThread);
|
|
g_ControlSvrThread = nullptr;
|
|
}
|
|
|
|
return ERR_SUCCESS;
|
|
} |