Fix: Resolve window titles by clientID instead of peer IP

Window list (WSLIST) sub-connections carry no capability bits, so
GetClientEncoding fell back to FindHostByIP(peer IP) to locate the main
connection. Under FRP/NAT reverse proxy the sub-connection's socket peer
is 127.0.0.1 or an internal relay address, which does not match the main
connection's recorded public IP; the lookup returned NULL and the client's
UTF-8 window titles were decoded as CP936 (GBK), producing mojibake on
hosts with Chinese window titles.

Resolve the main connection by clientID first (pinned on the sub-connection
after TOKEN_CONN_AUTH via SetID), falling back to the peer-IP lookup only
for legacy clients that do not send TOKEN_CONN_AUTH.

Co-Authored-By: deepseek-v4-pro
This commit is contained in:
yuanyuanxiang
2026-08-19 11:05:35 +02:00
parent 6ba6b0289d
commit bcde74368d

View File

@@ -203,10 +203,10 @@ bool SupportsFileTransferV2(context* ctx) {
}
// 获取客户端协议字符串编码优先看自身能力位若是子连接CAPABILITIES 为空)
// 则通过 peer IP 查主连接。Linux/macOS 客户端文件系统路径与 locale 现代发行版
// 默认就是 UTF-8——即便客户端二进制是早于 CLIENT_CAP_UTF8 引入commit 0aa7588
// 之前编译的,没声明 cap 位,事实上仍发 UTF-8 字节,按 client type 兜底走 UTF-8。
// 找不到则默认 CP936。
// 则先按 clientID、再按 peer IP 查主连接。Linux/macOS 客户端文件系统路径与 locale
// 现代发行版默认就是 UTF-8——即便客户端二进制是早于 CLIENT_CAP_UTF8 引入
// commit 0aa7588之前编译的,没声明 cap 位,事实上仍发 UTF-8 字节,按 client
// type 兜底走 UTF-8。找不到则默认 CP936。
UINT GetClientEncoding(context* ctx) {
if (!ctx) return 936;
// 主连接情形CAPABILITIES 已由 LOGIN_INFOR 处理流程填好
@@ -214,9 +214,17 @@ UINT GetClientEncoding(context* ctx) {
// 客户端类型兜底LNX / MAC 默认 UTF-8兼容老二进制无 UTF-8 cap 位的情形)
CString clientType = ctx->GetAdditionalData(RES_CLIENT_TYPE);
if (clientType == "LNX" || clientType == "MAC") return CP_UTF8;
// 子连接情形CAPABILITIES 为空 -> 通过 IP 找主连接
// 子连接情形CAPABILITIES 为空 -> 找主连接
// 优先按 clientID 精确查:子连接经 TOKEN_CONN_AUTH 校验后 SetID(pkt->clientID)
// 已把 clientID 钉成主连接 IDFRP/NAT 反代下 socket peer 是 127.0.0.1/内网地址
// 也能命中,不再依赖 peer IP 反查。
if (g_2015RemoteDlg) {
context* mainCtx = g_2015RemoteDlg->FindHostByIP(ctx->GetPeerName());
context* mainCtx = g_2015RemoteDlg->FindHostByClientID(ctx->GetClientID());
if (!mainCtx) {
// 老客户端子连接不发 TOKEN_CONN_AUTHclientID 未钉,为 0
// 回退到 peer IP 反查(直连场景仍可命中)。
mainCtx = g_2015RemoteDlg->FindHostByIP(ctx->GetPeerName());
}
if (mainCtx) {
if (mainCtx->SupportsUtf8()) return CP_UTF8;
CString mainType = mainCtx->GetAdditionalData(RES_CLIENT_TYPE);