Files
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

120 lines
3.5 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package transport
import (
"encoding/binary"
"fmt"
"io"
)
const (
x224TypeConnectionRequest = 0xE0
x224TypeConnectionConfirm = 0xD0
x224TypeData = 0xF0
negTypeRequest = 0x01
negTypeResponse = 0x02
negTypeFailure = 0x03
protocolSSL = 0x00000001
protocolCredSSP = 0x00000002
)
const (
ProtocolStandard uint32 = 0
ProtocolTLS uint32 = protocolSSL
ProtocolCredSSP uint32 = protocolCredSSP
)
// NegotiationResult 是 X.224 阶段的 RDP 安全协议协商结果 // Logan.Li
type NegotiationResult struct {
SelectedProtocol uint32
FailureCode uint32
}
func (r NegotiationResult) ProtocolName() string {
switch r.SelectedProtocol {
case ProtocolCredSSP:
return "CredSSP/NLA"
case ProtocolTLS:
return "TLS"
case ProtocolStandard:
return "Standard RDP"
default:
return fmt.Sprintf("unknown(0x%x)", r.SelectedProtocol)
}
}
// BuildConnectionRequest 构造 X.224 Connection Request,并请求 NLA/TLS 协商 // Logan.Li
func BuildConnectionRequest() []byte {
return BuildConnectionRequestWithCookie("aiops")
}
// BuildConnectionRequestWithCookie 按 MS-RDPBCGR 2.2.1.1.1 构造包含 mstshash 的请求 // Logan.Li
func BuildConnectionRequestWithCookie(username string) []byte {
if username == "" {
username = "aiops"
}
if len(username) > 9 {
username = username[:9]
}
cookie := []byte("Cookie: mstshash=" + username + "\r\n")
neg := make([]byte, 8)
neg[0] = negTypeRequest
neg[1] = 0
binary.LittleEndian.PutUint16(neg[2:4], uint16(len(neg)))
binary.LittleEndian.PutUint32(neg[4:8], protocolSSL|protocolCredSSP)
length := 7 + len(cookie) + len(neg)
pdu := make([]byte, 0, length)
pdu = append(pdu, byte(length-1))
pdu = append(pdu, x224TypeConnectionRequest)
pdu = append(pdu, 0x00, 0x00) // dst-ref // Logan.Li
pdu = append(pdu, 0x00, 0x00) // src-ref // Logan.Li
pdu = append(pdu, 0x00) // class/options // Logan.Li
pdu = append(pdu, cookie...)
pdu = append(pdu, neg...)
return pdu
}
// ParseConnectionConfirm 解析 X.224 Connection Confirm 与 RDP Negotiation Response // Logan.Li
func ParseConnectionConfirm(payload []byte) (NegotiationResult, error) {
if len(payload) < 7 {
return NegotiationResult{}, fmt.Errorf("short X.224 confirm: %d", len(payload))
}
if payload[1] != x224TypeConnectionConfirm {
return NegotiationResult{}, fmt.Errorf("unexpected X.224 pdu type: 0x%x", payload[1])
}
for i := 7; i+8 <= len(payload); i++ {
switch payload[i] {
case negTypeResponse:
return NegotiationResult{SelectedProtocol: binary.LittleEndian.Uint32(payload[i+4 : i+8])}, nil
case negTypeFailure:
return NegotiationResult{FailureCode: binary.LittleEndian.Uint32(payload[i+4 : i+8])}, fmt.Errorf("RDP negotiation failure: 0x%x", binary.LittleEndian.Uint32(payload[i+4:i+8]))
}
}
return NegotiationResult{SelectedProtocol: 0}, nil
}
// WriteX224Data 写入 X.224 Data TPDU,NLA 后的 MCS/GCC 数据仍经由该层承载 // Logan.Li
func WriteX224Data(w io.Writer, payload []byte) error {
data := make([]byte, 0, len(payload)+3)
data = append(data, 0x02, x224TypeData, 0x80)
data = append(data, payload...)
return WriteTPKT(w, data)
}
// ReadX224Data 读取并剥离 X.224 Data TPDU 头,返回上层 MCS 负载 // Logan.Li
func ReadX224Data(r io.Reader) ([]byte, error) {
payload, err := ReadTPKT(r)
if err != nil {
return nil, err
}
if len(payload) < 3 {
return nil, fmt.Errorf("X.224 data too short: %d", len(payload))
}
if payload[1] != x224TypeData {
return nil, fmt.Errorf("unexpected X.224 type: 0x%x", payload[1])
}
return payload[3:], nil
}