// client_auth_state.h // Linux/macOS 客户端服务端身份校验状态 + helper(Layer 1 防护)。 // // 行为模型: // - g_loginMsg:startTime + "|" + clientID,启动时填一次,跨重连不变 // - g_loginTime:每次新连接重置为当前时刻 // - g_settingsVerified:服务端 CMD_MASTERSETTING 通过签名校验后置 true, // 重连时重置为 false // // 客户端是常驻服务——服务端可能频繁重启 / 长期离线 / 临时不可达,这些都不应 // 让进程退出。校验失败仅作"本次连接不可信"处理:断开本连接 + 让外层重连。 // 功能侧的安全由子连接 auth(TOKEN_CONN_AUTH)兜底——没通过校验的服务端无法 // 触发任何 sub-connection 功能。 // // 跨线程访问: // - g_settingsVerified 在 DataProcess(IO 线程)写、心跳循环(main 线程)读 // - 用 std::atomic + acquire/release 内存序保证可见性 // // C++17 inline 变量保证多翻译单元共享同一实例,无 ODR 冲突。 #pragma once #include #include #include #include #include "common/commands.h" // 全局 namespace 中的 verifyMessage:由 client/sign_shim_unix.cpp(Linux/macOS)或 // 私有 .lib(Windows)提供。必须在任何 namespace 之外声明,否则会被解析成 // ClientAuth::verifyMessage 导致链接失败。 extern bool verifyMessage(const std::string& publicKey, BYTE* msg, int len, const std::string& signature); namespace ClientAuth { // ============== 跨重连保留的状态 ============== inline std::string g_loginMsg; inline time_t g_loginTime = 0; inline std::atomic g_settingsVerified{false}; // ============== Helpers ============== // 进入新连接前调用:g_loginTime = now,verified = false inline void OnNewConnection() { g_loginTime = time(nullptr); g_settingsVerified.store(false, std::memory_order_release); } // DataProcess 开头的 gate:未通过校验前仅放行 CMD_MASTERSETTING(校验本身)。 // 其它命令一律静默忽略——既防止未授权服务端 spawn 子连接线程做 DoS, // 也防止它发 COMMAND_BYE 之类把客户端进程关掉。 inline bool IsCommandAllowed(unsigned char cmd) { return g_settingsVerified.load(std::memory_order_acquire) || cmd == CMD_MASTERSETTING; } // 处理 CMD_MASTERSETTING(payload = szBuffer + 1,payloadLen = ulLength - 1): // 强制要求完整 MasterSettings(包含 Signature 字段);不完整 / 签名失败 → 不更新 // g_settingsVerified,让心跳循环 30s 超时自然把本次连接断开重连。 // // 返回 true:校验通过(已 store(true)),通过 outReportInterval / outSettingsCopy // 返回 settings 内容供调用方继续应用(更新心跳间隔、密码哈希等) // 返回 false:本次响应异常,调用方应直接 return(不要继续处理) // // 注意:参数采用 unsigned char* 而非 BYTE* 避免依赖 Windows typedef; // BYTE 在 commands.h 已 typedef 为 unsigned char,等价。 inline bool HandleMasterSettings(const unsigned char* payload, int payloadLen, MasterSettings* outSettings) { if (payloadLen < (int)sizeof(MasterSettings)) { return false; } MasterSettings settings = {}; std::memcpy(&settings, payload, sizeof(MasterSettings)); // 服务端身份校验:用 g_loginMsg (= szStartTime + "|" + clientID) 与 settings.Signature // 验证签名。失败 → 不立即退出,让超时兜底+重连逻辑处理。 // 注意 ::verifyMessage 在全局 namespace(见本头部 extern 声明),不能省略 :: 前缀, // 否则会被解析为 ClientAuth::verifyMessage,链接失败。 std::string sig((char*)settings.Signature, (char*)settings.Signature + sizeof(settings.Signature)); if (!::verifyMessage("", (BYTE*)g_loginMsg.data(), (int)g_loginMsg.length(), sig)) { return false; } g_settingsVerified.store(true, std::memory_order_release); if (outSettings) *outSettings = settings; return true; } // 心跳循环里检查 30s 超时:登录后 30 秒内必须收到并通过 MasterSettings 校验, // 失败 → 调用方应显式断开本连接让外层重连。永不退出进程。 inline bool IsTimedOut() { return !g_settingsVerified.load(std::memory_order_acquire) && g_loginTime > 0 && time(nullptr) - g_loginTime > 30; } } // namespace ClientAuth