| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274 |
- package utils
- import (
- "bytes"
- "encoding/binary"
- "errors"
- "fmt"
- "strings"
- )
- const (
- // Magic word
- _MAGIC_XLOG_SYSTEM_ uint32 = 0x99A3B417 // ARM的日志发送给PC
- // CmdType 命令类型 mainCmd(8bit) + subCmd(8bit)
- // mainCmd
- _XLOG_CMD_LOG_TO_PC_ uint8 = 0 // 心跳内容, 内容为"[x]\n"
- _XLOG_CMD_REPORT_BASICINFO_ uint8 = 1 // 上报sn + mac, 结构为 XlogSiteBaseInfo
- _XLOG_CMD_REPLY_BASICINFO_ uint8 = 2 // 回复sn + mac,暂不回复
- _XLOG_P2P_EXEC_BASH_CMD_ uint8 = 64 // pc -> SERNAME_UB_SERVER -> xlogv3, 执行远程命令
- _XLOG_P2P_BASH_CMD_RESULT_ uint8 = 65 // xlogv3-> SERNAME_UB_SERVER -> pc 返回远程命令执行结果
- )
- func NewXlogPackageParser(ctx *ConnectContext) *XlogPackageParser {
- return &XlogPackageParser{
- crypt: NewXlogEncrypt(),
- ctx: ctx,
- cmdResultStr: "",
- Handshake: false,
- Buffer: make([]byte, 0),
- }
- }
- // 解析设备握手包
- func (parser *XlogPackageParser) ParseXlogHandshakePackage(raw []byte) (*XlogHandshakePackageData, error) {
- reader := bytes.NewReader(raw)
- // 数据长度校验
- if len(raw) != 72 {
- return nil, fmt.Errorf("invalid handshake packet: data length error, expected 72, got %d", len(raw))
- }
- // 解析数据结构
- var p XlogHandshakePackage
- if err := binary.Read(reader, binary.LittleEndian, &p); err != nil {
- return nil, err
- }
- // 校验数据头
- if p.MagicWord != _MAGIC_XLOG_SYSTEM_ {
- return nil, errors.New("invalid magic")
- }
- if p.CmdLen != uint32(len(raw)-8) {
- return nil, fmt.Errorf("invalid handshake packet: data length error, CmdLen: %d", p.CmdLen)
- }
- // 解密数据
- handshakeData, err := parser.crypt.DecryptData(p.EncryptData[:])
- if err != nil {
- return nil, err
- }
- // 数据长度校验
- if len(handshakeData) != (16 + 36) {
- return nil, fmt.Errorf("invalid handshake packet: data length error, expected 52, got %d", len(handshakeData))
- }
- // 解析握手数据结构
- var h XlogHandshakePackageData
- reader = bytes.NewReader(handshakeData)
- if err := binary.Read(reader, binary.LittleEndian, &h); err != nil {
- return nil, err
- }
- fmt.Println(string(bytes.TrimRight(h.DevUuid[:], "\x00")))
- // 更新IV
- if err := parser.crypt.SetNewIv(h.NewIv[:]); err != nil {
- return nil, err
- }
- return &h, nil
- }
- // 预解析数据包,数据提取,提取一个完整数据包
- func (parser *XlogPackageParser) PreparserXlogPackage(raw []byte) {
- // 累积数据
- parser.Buffer = append(parser.Buffer, raw...)
- buffer := parser.Buffer
- for {
- // 不够一个包头和长度字段,继续收
- if len(buffer) < 8 {
- return
- }
- // 查找合法包头
- header := binary.LittleEndian.Uint32(buffer[:4])
- if header != _MAGIC_XLOG_SYSTEM_ {
- // 丢掉 1 字节,继续找包头
- buffer = buffer[1:]
- continue
- }
- // 读取长度
- length := binary.LittleEndian.Uint32(buffer[4:8])
- totalLen := 8 + int(length)
- // 数据是否完整
- if len(buffer) < totalLen {
- break
- }
- // 提取完整包
- packet := buffer[:totalLen]
- // 异步处理
- go parser.ParseXlogPackage(packet)
- // 移除已处理的数据
- parser.Buffer = buffer[totalLen:]
- buffer = parser.Buffer
- }
- }
- // 处理设备心跳信息
- func (parser XlogPackageParser) handleHeartbeat(raw []byte) {
- fmt.Printf("%s - 接收到心跳:%s", parser.ctx.UUID, string(raw))
- }
- // 处理设备基本信息
- func (parser XlogPackageParser) handleSiteBaseInfo(raw []byte) {
- // 解析基本信息
- infoReader := bytes.NewReader(raw)
- var info XlogSiteBaseInfo
- if err := binary.Read(infoReader, binary.LittleEndian, &info); err != nil {
- fmt.Printf("handleSiteBaseInfo failed: %s\n", err)
- return
- }
- // 更新SN
- parser.ctx.SN = string(bytes.TrimRight(info.SN[:], "\x00"))
- fmt.Printf("update SN: %s\n", parser.ctx.SN)
- fmt.Println("握手成功")
- }
- // 处理命令执行结果
- func (parser *XlogPackageParser) handleCmdResult(raw []byte) {
- resStr := string(raw[:])
- if strings.HasPrefix(resStr, "\n***above is result of:") {
- parser.cmdResultStr = parser.cmdResultStr + resStr
- select {
- case parser.ctx.DoneChan <- parser.cmdResultStr:
- // 成功写入结果
- fmt.Printf("%s - 回传结果:%s\n", parser.ctx.UUID, parser.cmdResultStr)
- default:
- // channel 已经满(说明调用方可能已经超时退出了)
- fmt.Printf("%s - DoneChan已满或超时。\n", parser.ctx.UUID)
- }
- } else {
- parser.cmdResultStr = resStr
- }
- }
- // 解析设备数据包
- func (parser *XlogPackageParser) ParseXlogPackage(raw []byte) {
- // 数据长度校验
- headerPackageSize := binary.Size(XlogPackageHeader{})
- if len(raw) < headerPackageSize {
- fmt.Printf("invalid packet: data length error, expected >= %d, got %d\n", headerPackageSize, len(raw))
- return
- }
- headerRaw := raw[:headerPackageSize] // 非加密头部
- headerReader := bytes.NewReader(headerRaw)
- // 解析头部
- var h XlogPackageHeader
- if err := binary.Read(headerReader, binary.LittleEndian, &h); err != nil {
- fmt.Printf("XlogPackage header parsing error: %s\n", err.Error())
- return
- }
- if len(raw) > headerPackageSize {
- encryptRaw := raw[headerPackageSize:] // 加密数据
- // 解密Payload
- bodyRaw, err := parser.crypt.DecryptData(encryptRaw)
- if err != nil {
- fmt.Println("DecryptData error: " + err.Error())
- return
- }
- // 判断包类型
- switch h.MainCmd {
- case _XLOG_CMD_LOG_TO_PC_:
- parser.handleHeartbeat(bodyRaw)
- case _XLOG_CMD_REPORT_BASICINFO_:
- parser.handleSiteBaseInfo(bodyRaw)
- case _XLOG_P2P_BASH_CMD_RESULT_:
- parser.handleCmdResult(bodyRaw)
- }
- }
- }
- // 创建握手响应包
- func (parser XlogPackageParser) CreateXlogHandshakePackage() ([]byte, error) {
- encryptData, err := parser.crypt.EncryptData([]byte("0123456789abcdef"))
- if err != nil {
- return nil, err
- }
- buf := new(bytes.Buffer)
- // 按小端序写入,先写头部
- if err := binary.Write(buf, binary.LittleEndian, _MAGIC_XLOG_SYSTEM_); err != nil {
- return nil, fmt.Errorf("failed to write XlogHandshakeResponsePackage magic word: %w", err)
- }
- if err := binary.Write(buf, binary.LittleEndian, uint32(32)); err != nil {
- return nil, fmt.Errorf("failed to write XlogHandshakeResponsePackage magic word: %w", err)
- }
- // 再写 EncryptData
- if _, err := buf.Write(encryptData); err != nil {
- return nil, fmt.Errorf("failed to write XlogHandshakeResponsePackage EncryptData: %w", err)
- }
- return buf.Bytes(), nil
- }
- // 创建发送命令数据包
- func (parser XlogPackageParser) CreateXlogCmdPackage(payload []byte) ([]byte, error) {
- var dstServiceName [12]byte
- copy(dstServiceName[:], "Xlog")
- h := XlogPackageHeader{
- MagicWord: _MAGIC_XLOG_SYSTEM_,
- CmdLen: 0,
- MainCmd: _XLOG_P2P_EXEC_BASH_CMD_,
- SubCmd: 0,
- ControlBitData: 0,
- DstServiceName: dstServiceName,
- ToBeSendLen: 0,
- IgnoredLen: 0,
- UpTime: 0,
- }
- encryptData := []byte{}
- if len(payload) > 0 {
- encrypted, err := parser.crypt.EncryptData(payload)
- if err != nil {
- return nil, err
- }
- encryptData = encrypted
- }
- // 36是XlogPackageHeader字节数,8是MagicWord + CmdLen字节数
- h.CmdLen = uint32(36 + len(encryptData) - 8)
- p := XlogPackage{
- Header: h,
- EncryptPayload: encryptData,
- }
- buf := new(bytes.Buffer)
- // 按小端序写入,先写头部
- if err := binary.Write(buf, binary.LittleEndian, p.Header); err != nil {
- return nil, fmt.Errorf("failed to write XlogPackage header: %w", err)
- }
- // 再写 payload
- if _, err := buf.Write(p.EncryptPayload); err != nil {
- return nil, fmt.Errorf("failed to write XlogPackage payload: %w", err)
- }
- return buf.Bytes(), nil
- }
|