Improve: Embed Modern Terminal DLL in master's resources
Fix: keep Linux/macOS client alive across server restarts; gate all commands on auth-verified state to neutralize unauthorized servers
This commit is contained in:
@@ -47,9 +47,13 @@ static std::atomic<bool> g_needResendLogin(false); // 分组变更后需要重
|
||||
uint64_t g_myClientID = 0;
|
||||
|
||||
// 服务端身份校验:登录消息(签名输入),登录时间,是否已通过校验
|
||||
// 客户端是常驻服务——服务端可能频繁重启 / 长期离线 / 临时不可达,这些都不应让进程退出。
|
||||
// 校验失败仅作"本次连接不可信"处理:断开本连接 + 让外层重连。
|
||||
// g_settingsVerified 在 DataProcess(IO 线程)写、心跳循环(main 线程)和 DataProcess 自身读,
|
||||
// 跨线程访问 → 用 atomic 保证可见性。
|
||||
std::string g_loginMsg;
|
||||
time_t g_loginTime = 0;
|
||||
bool g_settingsVerified = false;
|
||||
std::atomic<bool> g_settingsVerified{false};
|
||||
|
||||
// ============== UTF-8 → GBK 编码转换(服务端为 Windows GBK 环境) ==============
|
||||
|
||||
@@ -451,6 +455,14 @@ int DataProcess(void* user, PBYTE szBuffer, ULONG ulLength)
|
||||
if (szBuffer == nullptr || ulLength == 0)
|
||||
return TRUE;
|
||||
|
||||
// 服务端身份未通过校验前,仅放行 CMD_MASTERSETTING(校验本身)。
|
||||
// 其它命令一律静默忽略——既防止未授权服务端 spawn 子连接线程做 DoS,
|
||||
// 也防止它发 COMMAND_BYE 之类把客户端进程关掉。
|
||||
if (!g_settingsVerified.load(std::memory_order_acquire) &&
|
||||
szBuffer[0] != CMD_MASTERSETTING) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (szBuffer[0] == COMMAND_BYE) {
|
||||
Mprintf("*** [%p] Received Bye-Bye command ***\n", user);
|
||||
g_bExit = S_CLIENT_EXIT;
|
||||
@@ -483,23 +495,23 @@ int DataProcess(void* user, PBYTE szBuffer, ULONG ulLength)
|
||||
}
|
||||
} else if (szBuffer[0] == CMD_MASTERSETTING) {
|
||||
int settingSize = ulLength - 1;
|
||||
// 强制要求完整 MasterSettings(包含 Signature 字段)。包不完整 → 视为非授权服务端
|
||||
// 强制要求完整 MasterSettings(包含 Signature 字段)。包不完整 → 视为本次响应异常,
|
||||
// 不更新 g_settingsVerified,让心跳循环的 30s 超时自然把本次连接断开重连。
|
||||
if (settingSize < (int)sizeof(MasterSettings)) {
|
||||
g_bExit = S_CLIENT_EXIT;
|
||||
return TRUE;
|
||||
}
|
||||
MasterSettings settings = {};
|
||||
memcpy(&settings, szBuffer + 1, sizeof(MasterSettings));
|
||||
|
||||
// 服务端身份校验:用 g_loginMsg (= szStartTime + "|" + clientID) 与 settings.Signature
|
||||
// 验证签名。失败 → 静默退出(不打印关键词日志)
|
||||
// 验证签名。失败 → 不立即退出,让超时兜底+重连逻辑处理(避免合法服务端临时
|
||||
// 抖动导致进程退出)
|
||||
extern bool verifyMessage(const std::string& publicKey, BYTE* msg, int len, const std::string& signature);
|
||||
std::string sig((char*)settings.Signature, (char*)settings.Signature + sizeof(settings.Signature));
|
||||
if (!verifyMessage("", (BYTE*)g_loginMsg.data(), (int)g_loginMsg.length(), sig)) {
|
||||
g_bExit = S_CLIENT_EXIT;
|
||||
return TRUE;
|
||||
return TRUE; // 同上,不立即退出
|
||||
}
|
||||
g_settingsVerified = true;
|
||||
g_settingsVerified.store(true, std::memory_order_release);
|
||||
|
||||
if (settings.ReportInterval > 0)
|
||||
g_heartbeatInterval = settings.ReportInterval;
|
||||
@@ -1132,7 +1144,7 @@ int main(int argc, char* argv[])
|
||||
|
||||
// 进入新连接,重置服务端身份校验状态
|
||||
g_loginTime = time(nullptr);
|
||||
g_settingsVerified = false;
|
||||
g_settingsVerified.store(false, std::memory_order_release);
|
||||
ClientObject->SendLoginInfo(logInfo.Speed(clock() - c));
|
||||
|
||||
// 心跳保活循环:定时发送心跳包,服务端回复后动态更新 RTT
|
||||
@@ -1162,10 +1174,11 @@ int main(int argc, char* argv[])
|
||||
if (!ClientObject->IsRunning() || !ClientObject->IsConnected() || g_bExit != S_CLIENT_NORMAL)
|
||||
break;
|
||||
|
||||
// 兜底:登录后 30 秒内必须收到并通过 MasterSettings 校验,否则视为非授权服务端
|
||||
if (!g_settingsVerified && g_loginTime > 0 &&
|
||||
// 登录后 30 秒内必须收到并通过 MasterSettings 校验。失败 → 显式断开本连接
|
||||
// 让外层重连。永不退出进程(客户端是常驻服务,服务端不可达不应该让其自杀)。
|
||||
if (!g_settingsVerified.load(std::memory_order_acquire) && g_loginTime > 0 &&
|
||||
time(nullptr) - g_loginTime > 30) {
|
||||
g_bExit = S_CLIENT_EXIT;
|
||||
ClientObject->Disconnect(); // 关闭 socket,防止重连时 fd 泄漏
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user