Files
rdp_channel/protocol/x224/x224.go

394 lines
8.9 KiB
Go
Raw 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 x224
import (
"bytes"
"encoding/binary"
"errors"
"io"
"log"
"rdp_channel/protocol/core/transport"
)
/* 协议常量 */
const (
X224_HEADER_LENGTH = 0x06
RDP_NEG_LENGTH = 0x08
)
// X224消息类型字段标识
const (
X224_CONNECTION_REQUEST byte = 0xE0
X224_CONNECTION_CONFIRM byte = 0xD0
X224_DISCONNECT_REQUEST byte = 0x80
X224_DATA byte = 0xF0
X224_ERROR byte = 0x70
)
// 安全协议协商状态字段标识
const (
RDP_NEG_REQ byte = 0x01
RDP_NEG_RSP byte = 0x02
RDP_NEG_FAIL byte = 0x03
)
// 可选协议
const (
PROTOCOL_RDP uint32 = 0x0000
PROTOCOL_SSL uint32 = 0x0001
)
// Negotiation 安全协议协商结构体
type Negotiation struct {
Type byte
Flags uint8
Length uint16
Payload uint32
}
func (neg *Negotiation) parseNegotiation(reader *bytes.Reader) error {
var err error
err = binary.Read(reader, binary.LittleEndian, &neg.Type)
if err != nil {
return errors.New("[X224] failed to read pdu neg type: " + err.Error())
}
err = binary.Read(reader, binary.LittleEndian, &neg.Flags)
if err != nil {
return errors.New("[X224] failed to read pdu neg flags: " + err.Error())
}
err = binary.Read(reader, binary.LittleEndian, &neg.Length)
if err != nil {
return errors.New("[X224] failed to read pdu neg length: " + err.Error())
}
err = binary.Read(reader, binary.LittleEndian, &neg.Payload)
if err != nil {
return errors.New("[X224] failed to read pdu neg payload: " + err.Error())
}
return nil
}
// X224 协议封装
type X224 struct {
transport transport.Transport
reqProtocol uint32
selProtocol uint32
dataHandlers []func([]byte)
errorHandlers []func(error)
}
type X224PDU struct {
Len uint8
Type byte
DstRef uint16 // 大端序
SrcRef uint16 // 大端序
ClsOpt uint8
Cookie []byte
Payload []byte
NegMsg *Negotiation
}
func New(transport transport.Transport) *X224 {
return &X224{
transport: transport,
reqProtocol: PROTOCOL_SSL,
}
}
/* 注册事件回调函数 */
// OnData 数据回调
func (x *X224) OnData(handler func([]byte)) {
x.dataHandlers = append(x.dataHandlers, handler)
}
// OnError 错误回调
func (x *X224) OnError(handler func(error)) {
x.errorHandlers = append(x.errorHandlers, handler)
}
// 从字节流中解析PDU头部
func (x *X224) parsePduHeader(reader *bytes.Reader, pdu *X224PDU) error {
var err error
// 读取Len字段
err = binary.Read(reader, binary.LittleEndian, &pdu.Len)
if err != nil {
return errors.New("[X224] failed to read pdu length: " + err.Error())
}
// 读取Type字段
err = binary.Read(reader, binary.LittleEndian, &pdu.Type)
if err != nil {
return errors.New("[X224] failed to read pdu type: " + err.Error())
}
// 读取DstRef大端序
err = binary.Read(reader, binary.BigEndian, &pdu.DstRef)
if err != nil {
return errors.New("[X224] failed to read pdu dstref: " + err.Error())
}
// 读取SrcRef大端序
err = binary.Read(reader, binary.BigEndian, &pdu.SrcRef)
if err != nil {
return errors.New("[X224] failed to read pdu srcref: " + err.Error())
}
// 读取ClsOpt
err = binary.Read(reader, binary.LittleEndian, &pdu.ClsOpt)
if err != nil {
return errors.New("[X224] failed to read pdu clsopt: " + err.Error())
}
return nil
}
// 序列化X224PDU
func (x *X224) serialize(pdu *X224PDU) []byte {
buff := bytes.NewBuffer(nil)
_ = binary.Write(buff, binary.LittleEndian, pdu.Len)
_ = binary.Write(buff, binary.LittleEndian, pdu.Type)
_ = binary.Write(buff, binary.BigEndian, pdu.DstRef)
_ = binary.Write(buff, binary.BigEndian, pdu.SrcRef)
_ = binary.Write(buff, binary.LittleEndian, pdu.ClsOpt)
// 仅连接相关PDU包含Cookie和协商负载
switch pdu.Type {
case X224_CONNECTION_REQUEST, X224_CONNECTION_CONFIRM:
if len(pdu.Cookie) > 0 {
_ = binary.Write(buff, binary.LittleEndian, pdu.Cookie)
_ = binary.Write(buff, binary.LittleEndian, []byte{0x0D, 0x0A})
}
if pdu.NegMsg != nil {
_ = binary.Write(buff, binary.LittleEndian, pdu.NegMsg.Type)
_ = binary.Write(buff, binary.LittleEndian, pdu.NegMsg.Flags)
_ = binary.Write(buff, binary.LittleEndian, pdu.NegMsg.Length)
_ = binary.Write(buff, binary.LittleEndian, pdu.NegMsg.Payload)
}
case X224_DATA:
buff.Write(pdu.Payload)
}
return buff.Bytes()
}
// 处理数据消息
func (x *X224) handleData(reader *bytes.Reader) {
buff, err := io.ReadAll(reader)
if err != nil {
x.handleError(err)
return
}
for _, handler := range x.dataHandlers {
handler(buff)
}
}
// 处理错误消息
func (x *X224) handleError(err error) {
log.Println(err.Error())
for _, handler := range x.errorHandlers {
handler(err)
}
}
// Write 发送数据消息
func (x *X224) Write(data []byte) {
// 构造pdu
reqPdu := &X224PDU{
Len: X224_HEADER_LENGTH + uint8(len(data)), // 头部长度 + 数据长度
Type: X224_DATA,
DstRef: 0x00,
SrcRef: 0x00,
ClsOpt: 0x0,
Payload: data,
}
// 序列化pdu
payload := x.serialize(reqPdu)
// 写入传输层
_, err := x.transport.Write(payload)
if err != nil {
x.handleError(err)
}
}
/*
X224客户端相关实现
*/
// ConnectToServer 客户端向服务端发起连接请求
func (x *X224) ConnectToServer() {
cookie := []byte("Cookie: mstshash=yv1ing")
/* 构造pdu */
reqPdu := &X224PDU{
Len: X224_HEADER_LENGTH + uint8(len(cookie)+0x02+RDP_NEG_LENGTH), // 头部长度 + Cookie长度 + CRLF + Neg字段
Type: X224_CONNECTION_REQUEST,
DstRef: 0x00,
SrcRef: 0x00,
ClsOpt: 0x0,
Cookie: cookie,
NegMsg: &Negotiation{
Type: RDP_NEG_RSP,
Flags: 0x00,
Length: RDP_NEG_LENGTH,
Payload: x.reqProtocol,
},
}
/* 序列化pdu */
payload := x.serialize(reqPdu)
/* 写入传输层 */
_, err := x.transport.Write(payload)
if err != nil {
x.handleError(errors.New("[X224] failed to write pdu: " + err.Error()))
return
}
/* 等待处理服务端对连接请求的响应 */
go x.clientHandleServerMessage()
}
// 客户端处理服务端的消息
func (x *X224) clientHandleServerMessage() {
for {
li, packet, err := x.transport.Read()
if err != nil {
continue
}
if li < 0x07 {
x.handleError(errors.New("[X224] invalid packet"))
return
}
resPdu := &X224PDU{}
reader := bytes.NewReader(packet)
err = x.parsePduHeader(reader, resPdu)
if err != nil {
x.handleError(errors.New("[X224] failed to parse pdu header: " + err.Error()))
return
}
switch resPdu.Type {
case X224_CONNECTION_CONFIRM:
x.clientHandleConnectionConfirm(resPdu, reader)
case X224_DATA:
x.handleData(reader)
}
}
}
// handleConnectionConfirm 客户端处理服务端对连接请求的响应
func (x *X224) clientHandleConnectionConfirm(resPdu *X224PDU, reader *bytes.Reader) {
// 读取安全协议协商结果
neg := &Negotiation{}
err := neg.parseNegotiation(reader)
if err != nil {
x.handleError(errors.New("[X224] failed to parse negotiation: " + err.Error()))
}
resPdu.NegMsg = neg
}
/*
X224服务端相关实现
*/
// 服务端向客户端发送响应
func (x *X224) serverResponseToClient(reqPdu *X224PDU) {
var err error
// 构造协商响应
resPdu := &X224PDU{
Len: X224_HEADER_LENGTH + RDP_NEG_LENGTH, // 头部长度 + Neg字段
Type: X224_CONNECTION_CONFIRM,
DstRef: reqPdu.SrcRef,
SrcRef: reqPdu.DstRef,
ClsOpt: reqPdu.ClsOpt,
NegMsg: &Negotiation{
Type: RDP_NEG_RSP,
Flags: 0x00,
Length: RDP_NEG_LENGTH,
Payload: x.selProtocol,
},
}
payload := x.serialize(resPdu)
_, err = x.transport.Write(payload)
if err != nil {
x.handleError(errors.New("[X224] failed to write response: " + err.Error()))
}
}
// 服务端处理客户端消息
func (x *X224) serverHandleClientMessage() {
for {
_, packet, err := x.transport.Read()
if err != nil {
continue
}
reqPdu := &X224PDU{}
reader := bytes.NewReader(packet)
err = x.parsePduHeader(reader, reqPdu)
if err != nil {
x.handleError(errors.New("[X224] failed to parse pdu header: " + err.Error()))
return
}
switch reqPdu.Type {
case X224_CONNECTION_REQUEST:
x.serverHandleConnectionRequest(reqPdu, reader)
case X224_DATA:
x.handleData(reader)
}
}
}
// 服务端处理客户端发来的连接请求
func (x *X224) serverHandleConnectionRequest(reqPdu *X224PDU, reader *bytes.Reader) {
// 解析Cookie
cookieBuff := make([]byte, 0, 32)
for {
b, err := reader.ReadByte()
if err != nil {
x.handleError(errors.New("[X224] failed to read cookie: " + err.Error()))
return
}
cookieBuff = append(cookieBuff, b)
if len(cookieBuff) >= 2 && bytes.Equal(cookieBuff[len(cookieBuff)-2:], []byte{0x0D, 0x0A}) {
break
}
}
reqPdu.Cookie = cookieBuff[:len(cookieBuff)-2] // 去掉结尾CRLF
// 解析协商请求
reqNeg := &Negotiation{}
if err := reqNeg.parseNegotiation(reader); err != nil {
x.handleError(errors.New("[X224] failed to parse negotiation: " + err.Error()))
return
}
reqPdu.NegMsg = reqNeg
// 确定使用协议
x.selProtocol = PROTOCOL_SSL
// 响应请求
x.serverResponseToClient(reqPdu)
}