Files
aiops/docs/rdp.md
T
LoganandClaude 76ec9387f0 feat(rdp): 新增 RDP 远程桌面/SMB/账单同步能力 + 清理编译产物
主要变更:
- RDP 远程桌面:新增 backend/pkg/rdp(RDP 引擎 + credssp/display/rle/trace)、
  backend/controller/rdp*(连接/凭证/文件/会话/实时)、frontend RDP 组件与 API
- Windows SMB 文件传输:backend/pkg/winsmb
- 云账单同步:backend/pkg/billingsync + billing_sync/aliyun_billing,前端账单详情
- Agent CLI Kubernetes 工具:kubernetes_action/get、pod_execute/logs
- 服务器导入助手:server_import_helpers、ImportCredentialSettings
- 国际化与组件重构(cloud/deploy/monitor/server/system 等多模块)
- 清理编译产物二进制:移除 backend/server、backend/agent/bin/aiops-agent-*
- .gitignore:新增 backend/agent/ 与 .cache/(避免 334MB go-build 缓存误入库)

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-04 01:50:36 +08:00

8.5 KiB
Raw Blame History

AIOps Web RDP 远程桌面

作者:Logan.Li
更新:2026-07-03
归档副本:/opt/rdp/docs/rdp.md · 变更记录:/opt/rdp/CHANGELOG.md


概述

AIOps 提供浏览器内 Windows 远程桌面(Canvas 渲染 + WebSocket)。当前已移除第三方 grdp 兜底实现,后端固定使用 AIOps 自研 RDP 协议栈。// Logan.Li

环境变量 行为
RDP_ENGINE 已不再参与引擎选择,保留环境变量不会改变行为
RDP_DEBUG=1 打开 [RDP:TRACE] 协议级日志
层级 状态 路径
X.224 / TPKT / TLS ✅ 自研灰度 backend/pkg/rdp/transport/
CredSSP / NTLMv2 (NLA) ✅ 自研灰度 backend/pkg/rdp/credssp/
MCS / GCC / 许可证 / 激活 ✅ 自研灰度 backend/pkg/rdp/mcs_probe.go、session_connect.go
FastPath 位图 / MPPC / RLE ✅ 自研灰度 bitmap_decode.go、fastpath_recv.go、mppc.go、rle/
键鼠 / 剪贴板 / auto_exec ✅ 自研灰度 input_fastpath.go
文件传输 (SMB + 暂存回退) ✅ 自研 pkg/winsmb/、pkg/rdpfilestage/
前端 Canvas + 工具面板 ✅ 自研 RdpDialog.tsx、RdpToolsPanel.tsx

自研协议栈不依赖第三方 RDP 实现,也不直接依赖控制器、数据库或 WebSocket。已删除的第三方目录备份在 /opt/rdp/third-party/grdp-aiops-backup-20260703。// Logan.Li


2026-07-03 变更记录

自研 RDP 引擎

变更项 说明
引擎入口 NewEngine() 固定返回 SessionEngine
兜底依赖 已移除 github.com/nakagami/grdp 和 backend/third_party
Dockerfile 不再复制 third_party 模块
新增模块 session_engine.go、session_connect.go、packet_io.go、fastpath_recv.go、bitmap_decode.go、input_fastpath.go、mppc.go、rle/
自研会话激活 ConfirmActive 后可选读 FontMap,发送 SuppressOutput(ALLOW_DISPLAY_UPDATES) 触发服务端推帧
自研位图输出 FastPath / SlowPath Bitmap + SurfaceCmd → PNG base64 → WebSocket type:bitmap
自研输入通道 Fast-Path Input:扫描码键鼠、Unicode 剪贴板、auto_exec(Win+R 粘贴命令)
协议日志 RDP_DEBUG=1 输出 [RDP:TRACE],定位连接、bitmap、input 阶段

仍保留的探测 API(诊断用)

函数 用途
ProbeHandshake X.224 安全协议协商
ProbeCredSSP NLA 凭据验证
ProbeMCSConnect MCS/GCC 握手探测(读完即关连接)
ProbeSessionFrames 建立会话后统计位图矩形数量

已知限制 / 待完善

  • mcs_probe.go 超 700 行红线,后续需按 MCS/GCC/PDU 拆文件
  • 未实现 cliprdr 虚拟通道双向同步、RDPGFX/H.264、动态虚拟通道
  • 部分 Windows 主机在频繁探测后可能 connection reset(目标机策略/限流,非 NLA 失败)

架构与调用链

RdpDialog.tsx
  │ WebSocket /ws/rdp?id=&width=&height=&token=
  ▼
controller/rdp.go
  │ loadRDPCredential() → engine.Run()
  ▼
pkg/rdp/engine.go → SessionEngine
  ├── session_engine.go    readLoop + handleEvent
  ├── session_connect.go   OpenSession (CredSSP + MCS + SuppressOutput)
  ├── packet_io.go         TPKT / FastPath 读写
  ├── fastpath_recv.go     服务端更新解析
  ├── bitmap_decode.go     RLE/翻转 → PNG
  ├── input_fastpath.go    键鼠 / 剪贴板 / auto_exec
  ├── mppc.go              MPPC 解压
  └── rle/                 位图 RLE 解压算法

后端文件清单

协议栈 backend/pkg/rdp/

文件 说明
engine.go Engine 接口、RDP_ENGINE 引擎选择
client.go ProbeHandshake / ProbeTLSHandshake / ProbeCredSSP
session_engine.go 图形会话主循环、帧推送、输入分发
session_connect.go OpenSession、SuppressOutput 激活
mcs_probe.go MCS Connect、GCC、ClientInfo、ConfirmActive 构建与探测
packet_io.go ReadWirePacket、WriteFastPathInput
fastpath_recv.go FastPath 更新、MPPC、SurfaceCmd 解析
bitmap_decode.go 位图解码与 PNG 编码
input_fastpath.go Fast-Path Input 事件编码
mppc.go MPPC-64K 解压器
keymap.go 浏览器 KeyboardEvent.code → RDP 扫描码
transport/ TPKT、X.224、TLS
credssp/ CredSSP + NTLMv2 + ASN.1
rle/ RLE 位图解压(DecompressInto)

控制器 / 模型

文件 说明
controller/rdp.go WebSocket 会话、审计录制
controller/rdp_session.go 会话列表 / 回放 / 终止 API
controller/rdp_file.go 文件 list/upload/download/stage
controller/rdp_cred.go 凭据加载辅助
model/rdp_session.go RDPSession 表

文件传输

文件 说明
pkg/winsmb/ SMB 管理共享直传 C:\Users\Public\AIOpsShare\Download
pkg/rdpfilestage/ 服务端暂存 + 一次性 token
frontend/.../RdpToolsPanel.tsx 工具面板(通用命令 / 文件 Tab)
frontend/.../rdpConstants.ts 虚拟 Download 盘路径常量

前端

文件 说明
RdpDialog.tsx Canvas 渲染、WebSocket、键鼠捕获、工具栏
RdpToolsPanel.tsx 剪贴板同步、文件上传下载、auto_exec 回退
api/server/rdp-files.ts 文件传输 REST
api/audit/rdp.ts 会话审计 API

WebSocket 帧协议

服务端 → 浏览器

{ "type": "session",  "message": "123", "width": 1280, "height": 800 }
{ "type": "status",   "message": "正在连接 RDP ..." }
{ "type": "error",    "message": "..." }
{ "type": "bitmap",   "x": 0, "y": 0, "width": 64, "height": 64, "image": "data:image/png;base64,..." }
{ "type": "clipboard","text": "远端剪贴板内容" }

浏览器 → 服务端

{ "type": "mouse_move", "x": 100, "y": 200 }
{ "type": "mouse_down", "x": 100, "y": 200, "button": 0 }
{ "type": "mouse_up",   "x": 100, "y": 200, "button": 0 }
{ "type": "wheel",      "x": 100, "y": 200, "delta_y": -120 }
{ "type": "key",        "code": "KeyA", "key": "a", "down": true }
{ "type": "clipboard",  "text": "本地剪贴板" }
{ "type": "auto_exec",  "text": "C:\\Users\\Public\\AIOpsShare\\Download\\setup.exe" }

CredSSP 多策略重试

每条策略使用新建 TCP 连接(client.go):

  1. v6 + binding(默认)
  2. v6 + binding + UseCBT
  3. v6 + binding + ForceMIC
  4. v2 + raw(兼容旧服务端)

关键修复:credssp.subjectPublicKey() 使用证书 SubjectPublicKey 原始 ASN.1,而非 PKIX SPKI。


外部项目借鉴边界

项目 可借鉴点 不直接采用原因
FreeRDP 协议完整性、通道、编解码、客户端能力矩阵 C 生态和体量过大,不适合直接嵌入
Apache Guacamole Web 网关、协议代理、录制与前端桥接分层 依赖 guacd/C,不符合单 Go 后端目标
IronRDP 现代模块化、状态机测试、安全边界 Rust 生态,适合作为测试和分层参考
Teleport 身份、RBAC、审计、Desktop Gateway 架构 产品目标偏堡垒机,不是轻量 RDP client
tomatome/grdp / nakagami/grdp Go 协议状态机、能力集、bitmap/input 参考 第三方实现已移除,仅保留 /opt 备份用于协议对照

第三方代码归档与文档

归档与变更记录目录:

/opt/rdp/
├── CHANGELOG.md            # 变更记录
├── README.md               # 索引
├── docs/rdp.md             # 完整说明(与本文档同步)
└── third-party/
    ├── nakagami-grdp-v0.8.7/
    ├── rdp-web-refs/
    └── grdpprobe/

第三方源码只能作为协议行为和工程分层参考;涉及 GPL 的项目不得直接搬运实现。// Logan.Li


验证命令

# 编译
cd backend && CGO_ENABLED=1 go build -o aiops .

# NLA 探测
go run /tmp/rdp_cred_probe.go   # ProbeCredSSP

# 会话位图统计(需可达的 Windows:3389)
go run /tmp/rdp_session_probe_main.go

# Docker 端到端
./run.sh docker up
# 浏览器:服务器管理 → Windows 主机 → RDP 连接

相关路由

路径 说明
GET /ws/rdp WebSocket 图形会话
GET /api/v1/rdp-sessions 会话审计列表
GET /api/v1/servers/:id/rdp-files 远端文件列表
POST /api/v1/servers/:id/rdp-files/upload 上传
GET /api/v1/servers/:id/rdp-files/download 下载