xlog_package.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405
  1. package xlog
  2. import (
  3. "bytes"
  4. "encoding/binary"
  5. "errors"
  6. "fmt"
  7. "fwh-toolbox-server/logger"
  8. "strings"
  9. )
  10. const (
  11. // Magic word
  12. _MAGIC_XLOG_SYSTEM_ uint32 = 0x99A3B417 // ARM的日志发送给PC
  13. // CmdType 命令类型 mainCmd(8bit) + subCmd(8bit)
  14. // mainCmd
  15. _XLOG_CMD_LOG_TO_PC_ uint8 = 0 // 心跳内容, 内容为"[x]\n"
  16. _XLOG_CMD_REPORT_BASICINFO_ uint8 = 1 // 上报sn + mac, 结构为 XlogSiteBaseInfo
  17. _XLOG_CMD_REPLY_BASICINFO_ uint8 = 2 // 回复sn + mac,暂不回复
  18. _XLOG_P2P_EXEC_BASH_CMD_ uint8 = 64 // pc -> SERNAME_UB_SERVER -> xlogv3, 执行远程命令
  19. _XLOG_P2P_BASH_CMD_RESULT_ uint8 = 65 // xlogv3-> SERNAME_UB_SERVER -> pc 返回远程命令执行结果
  20. )
  21. // xlog1.0相关配置
  22. const (
  23. // Magic word
  24. _MAGIC_XLOG_1_0_SYSTEM_ uint32 = 0xAA3355BB
  25. // CmdType 命令类型
  26. _XLOG_1_0_CMD_LOG_TO_PC_ uint32 = 0 // 心跳内容, 内容为"[x]\n"
  27. _XLOG_1_0_CMD_EXEC_BASH_CMD_ uint32 = 1 // pc -> SERNAME_UB_SERVER -> xlog 发送命令给ARM执行
  28. _XLOG_1_0_CMD_BASH_CMD_RESULT_ uint32 = 2 // xlog -> SERNAME_UB_SERVER -> pc 返回远程命令执行结果
  29. )
  30. func NewXlogPackageParser(ctx *ConnectContext) *XlogPackageParser {
  31. return &XlogPackageParser{
  32. crypt: NewXlogEncrypt(),
  33. ctx: ctx,
  34. cmdResultStr: "",
  35. Handshake: false,
  36. Buffer: make([]byte, 0),
  37. IsOldProtocol: true,
  38. }
  39. }
  40. // 判断协议版本,是否是xlog1.0
  41. func (parser *XlogPackageParser) ParseXlogCheckVersionIsOld(raw []byte) (bool, error) {
  42. reader := bytes.NewReader(raw)
  43. // 数据长度校验
  44. if len(raw) < 4 {
  45. return false, fmt.Errorf("invalid packet: data length error, expected > 4, got %d", len(raw))
  46. }
  47. var magicWord uint32
  48. err := binary.Read(reader, binary.LittleEndian, &magicWord)
  49. if err != nil {
  50. return false, err
  51. }
  52. return magicWord == _MAGIC_XLOG_1_0_SYSTEM_, nil
  53. }
  54. // 预解析xlog1.0数据包,数据提取,提取一个完整数据包
  55. func (parser *XlogPackageParser) PreparserXlog10Package(raw []byte) {
  56. // 累积数据
  57. parser.Buffer = append(parser.Buffer, raw...)
  58. buffer := parser.Buffer
  59. for {
  60. // 不够一个包头和长度字段,继续收
  61. if len(buffer) < 12 {
  62. return
  63. }
  64. // 查找合法包头
  65. header := binary.LittleEndian.Uint32(buffer[:4])
  66. if header != _MAGIC_XLOG_1_0_SYSTEM_ {
  67. // 丢掉 1 字节,继续找包头
  68. buffer = buffer[1:]
  69. continue
  70. }
  71. // 读取命令类型
  72. // cmdType := binary.LittleEndian.Uint32(buffer[4:8])
  73. // 读取长度
  74. totalLen := binary.LittleEndian.Uint32(buffer[8:12])
  75. // 数据是否完整
  76. if len(buffer) < int(totalLen) {
  77. break
  78. }
  79. // 提取完整包
  80. packet := buffer[:totalLen]
  81. // 异步处理
  82. go parser.ParseXlog10Package(packet)
  83. // 移除已处理的数据
  84. parser.Buffer = buffer[totalLen:]
  85. buffer = parser.Buffer
  86. }
  87. }
  88. // 解析xlog1.0设备数据包
  89. func (parser *XlogPackageParser) ParseXlog10Package(raw []byte) {
  90. // 数据长度校验
  91. headerPackageSize := binary.Size(Xlog10PackageHeader{})
  92. if len(raw) < headerPackageSize {
  93. logger.Std.Printf("invalid packet: data length error, expected >= %d, got %d\n", headerPackageSize, len(raw))
  94. return
  95. }
  96. headerRaw := raw[:headerPackageSize]
  97. headerReader := bytes.NewReader(headerRaw)
  98. // 解析头部
  99. var h Xlog10PackageHeader
  100. if err := binary.Read(headerReader, binary.LittleEndian, &h); err != nil {
  101. logger.Std.Printf("Xlog1.0Package header parsing error: %s\n", err.Error())
  102. return
  103. }
  104. if len(raw) > headerPackageSize {
  105. payloadRaw := raw[headerPackageSize:] // payload数据
  106. // 判断包类型
  107. switch h.CmdType {
  108. case _XLOG_1_0_CMD_LOG_TO_PC_:
  109. parser.handleHeartbeat(payloadRaw)
  110. case _XLOG_1_0_CMD_BASH_CMD_RESULT_:
  111. parser.handleCmdResult(payloadRaw)
  112. }
  113. }
  114. }
  115. // 创建xlog1.0发送命令数据包
  116. func (parser XlogPackageParser) CreateXlog10CmdPackage(payload []byte) ([]byte, error) {
  117. h := Xlog10PackageHeader{
  118. MagicWord: _MAGIC_XLOG_1_0_SYSTEM_,
  119. CmdType: _XLOG_1_0_CMD_EXEC_BASH_CMD_,
  120. CmdLen: uint32(12 + len(payload)),
  121. }
  122. p := Xlog10Package{
  123. Header: h,
  124. Payload: payload,
  125. }
  126. buf := new(bytes.Buffer)
  127. // 按小端序写入,先写头部
  128. if err := binary.Write(buf, binary.LittleEndian, p.Header); err != nil {
  129. return nil, fmt.Errorf("failed to write Xlog10Package header: %w", err)
  130. }
  131. // 再写 payload
  132. if _, err := buf.Write(p.Payload); err != nil {
  133. return nil, fmt.Errorf("failed to write Xlog10Package payload: %w", err)
  134. }
  135. return buf.Bytes(), nil
  136. }
  137. // 解析设备握手包
  138. func (parser *XlogPackageParser) ParseXlogHandshakePackage(raw []byte) (*XlogHandshakePackageData, error) {
  139. reader := bytes.NewReader(raw)
  140. // 数据长度校验
  141. if len(raw) != 72 {
  142. return nil, fmt.Errorf("invalid handshake packet: data length error, expected 72, got %d", len(raw))
  143. }
  144. // 解析数据结构
  145. var p XlogHandshakePackage
  146. if err := binary.Read(reader, binary.LittleEndian, &p); err != nil {
  147. return nil, err
  148. }
  149. // 校验数据头
  150. if p.MagicWord != _MAGIC_XLOG_SYSTEM_ {
  151. return nil, errors.New("invalid magic")
  152. }
  153. if p.CmdLen != uint32(len(raw)-8) {
  154. return nil, fmt.Errorf("invalid handshake packet: data length error, CmdLen: %d", p.CmdLen)
  155. }
  156. // 解密数据
  157. handshakeData, err := parser.crypt.DecryptData(p.EncryptData[:])
  158. if err != nil {
  159. return nil, err
  160. }
  161. // 数据长度校验
  162. if len(handshakeData) != (16 + 36) {
  163. return nil, fmt.Errorf("invalid handshake packet: data length error, expected 52, got %d", len(handshakeData))
  164. }
  165. // 解析握手数据结构
  166. var h XlogHandshakePackageData
  167. reader = bytes.NewReader(handshakeData)
  168. if err := binary.Read(reader, binary.LittleEndian, &h); err != nil {
  169. return nil, err
  170. }
  171. // 更新IV
  172. if err := parser.crypt.SetNewIv(h.NewIv[:]); err != nil {
  173. return nil, err
  174. }
  175. return &h, nil
  176. }
  177. // 预解析数据包,数据提取,提取一个完整数据包
  178. func (parser *XlogPackageParser) PreparserXlogPackage(raw []byte) {
  179. // 累积数据
  180. parser.Buffer = append(parser.Buffer, raw...)
  181. buffer := parser.Buffer
  182. for {
  183. // 不够一个包头和长度字段,继续收
  184. if len(buffer) < 8 {
  185. return
  186. }
  187. // 查找合法包头
  188. header := binary.LittleEndian.Uint32(buffer[:4])
  189. if header != _MAGIC_XLOG_SYSTEM_ {
  190. // 丢掉 1 字节,继续找包头
  191. buffer = buffer[1:]
  192. continue
  193. }
  194. // 读取长度
  195. length := binary.LittleEndian.Uint32(buffer[4:8])
  196. totalLen := 8 + int(length)
  197. // 数据是否完整
  198. if len(buffer) < totalLen {
  199. break
  200. }
  201. // 提取完整包
  202. packet := buffer[:totalLen]
  203. // 异步处理
  204. go parser.ParseXlogPackage(packet)
  205. // 移除已处理的数据
  206. parser.Buffer = buffer[totalLen:]
  207. buffer = parser.Buffer
  208. }
  209. }
  210. // 处理设备心跳信息
  211. func (parser XlogPackageParser) handleHeartbeat(raw []byte) {
  212. // logger.Std.Printf("%s - 接收到心跳:%s", parser.ctx.UUID, string(raw))
  213. }
  214. // 处理设备基本信息
  215. func (parser XlogPackageParser) handleSiteBaseInfo(raw []byte) {
  216. // 解析基本信息
  217. infoReader := bytes.NewReader(raw)
  218. var info XlogSiteBaseInfo
  219. if err := binary.Read(infoReader, binary.LittleEndian, &info); err != nil {
  220. logger.Std.Printf("handleSiteBaseInfo failed: %s\n", err)
  221. return
  222. }
  223. // 更新SN
  224. parser.ctx.SN = string(bytes.TrimRight(info.SN[:], "\x00"))
  225. logger.Std.Printf("update SN: %s\n", parser.ctx.SN)
  226. logger.Std.Println("握手成功")
  227. }
  228. // 处理命令执行结果
  229. func (parser *XlogPackageParser) handleCmdResult(raw []byte) {
  230. resStr := string(raw[:])
  231. if strings.HasPrefix(resStr, "\n***above is result of:") {
  232. parser.cmdResultStr = parser.cmdResultStr + resStr
  233. select {
  234. case parser.ctx.DoneChan <- parser.cmdResultStr:
  235. // 成功写入结果
  236. logger.Std.Printf("%s - 回传结果:%s\n", parser.ctx.UUID, parser.cmdResultStr)
  237. default:
  238. // channel 已经满(说明调用方可能已经超时退出了)
  239. logger.Std.Printf("%s - DoneChan已满或超时。\n", parser.ctx.UUID)
  240. }
  241. } else {
  242. parser.cmdResultStr = resStr
  243. }
  244. }
  245. // 解析设备数据包
  246. func (parser *XlogPackageParser) ParseXlogPackage(raw []byte) {
  247. // 数据长度校验
  248. headerPackageSize := binary.Size(XlogPackageHeader{})
  249. if len(raw) < headerPackageSize {
  250. logger.Std.Printf("invalid packet: data length error, expected >= %d, got %d\n", headerPackageSize, len(raw))
  251. return
  252. }
  253. headerRaw := raw[:headerPackageSize] // 非加密头部
  254. headerReader := bytes.NewReader(headerRaw)
  255. // 解析头部
  256. var h XlogPackageHeader
  257. if err := binary.Read(headerReader, binary.LittleEndian, &h); err != nil {
  258. logger.Std.Printf("XlogPackage header parsing error: %s\n", err.Error())
  259. return
  260. }
  261. if len(raw) > headerPackageSize {
  262. encryptRaw := raw[headerPackageSize:] // 加密数据
  263. // 解密Payload
  264. bodyRaw, err := parser.crypt.DecryptData(encryptRaw)
  265. if err != nil {
  266. logger.Std.Println("DecryptData error: " + err.Error())
  267. return
  268. }
  269. // 判断包类型
  270. switch h.MainCmd {
  271. case _XLOG_CMD_LOG_TO_PC_:
  272. parser.handleHeartbeat(bodyRaw)
  273. case _XLOG_CMD_REPORT_BASICINFO_:
  274. parser.handleSiteBaseInfo(bodyRaw)
  275. case _XLOG_P2P_BASH_CMD_RESULT_:
  276. parser.handleCmdResult(bodyRaw)
  277. }
  278. }
  279. }
  280. // 创建握手响应包
  281. func (parser XlogPackageParser) CreateXlogHandshakePackage() ([]byte, error) {
  282. encryptData, err := parser.crypt.EncryptData([]byte("0123456789abcdef"))
  283. if err != nil {
  284. return nil, err
  285. }
  286. buf := new(bytes.Buffer)
  287. // 按小端序写入,先写头部
  288. if err := binary.Write(buf, binary.LittleEndian, _MAGIC_XLOG_SYSTEM_); err != nil {
  289. return nil, fmt.Errorf("failed to write XlogHandshakeResponsePackage magic word: %w", err)
  290. }
  291. if err := binary.Write(buf, binary.LittleEndian, uint32(32)); err != nil {
  292. return nil, fmt.Errorf("failed to write XlogHandshakeResponsePackage magic word: %w", err)
  293. }
  294. // 再写 EncryptData
  295. if _, err := buf.Write(encryptData); err != nil {
  296. return nil, fmt.Errorf("failed to write XlogHandshakeResponsePackage EncryptData: %w", err)
  297. }
  298. return buf.Bytes(), nil
  299. }
  300. // 创建发送命令数据包
  301. func (parser XlogPackageParser) CreateXlogCmdPackage(payload []byte) ([]byte, error) {
  302. var dstServiceName [12]byte
  303. copy(dstServiceName[:], "Xlog")
  304. h := XlogPackageHeader{
  305. MagicWord: _MAGIC_XLOG_SYSTEM_,
  306. CmdLen: 0,
  307. MainCmd: _XLOG_P2P_EXEC_BASH_CMD_,
  308. SubCmd: 0,
  309. ControlBitData: 0,
  310. DstServiceName: dstServiceName,
  311. ToBeSendLen: 0,
  312. IgnoredLen: 0,
  313. UpTime: 0,
  314. }
  315. encryptData := []byte{}
  316. if len(payload) > 0 {
  317. encrypted, err := parser.crypt.EncryptData(payload)
  318. if err != nil {
  319. return nil, err
  320. }
  321. encryptData = encrypted
  322. }
  323. // 36是XlogPackageHeader字节数,8是MagicWord + CmdLen字节数
  324. h.CmdLen = uint32(36 + len(encryptData) - 8)
  325. p := XlogPackage{
  326. Header: h,
  327. EncryptPayload: encryptData,
  328. }
  329. buf := new(bytes.Buffer)
  330. // 按小端序写入,先写头部
  331. if err := binary.Write(buf, binary.LittleEndian, p.Header); err != nil {
  332. return nil, fmt.Errorf("failed to write XlogPackage header: %w", err)
  333. }
  334. // 再写 payload
  335. if _, err := buf.Write(p.EncryptPayload); err != nil {
  336. return nil, fmt.Errorf("failed to write XlogPackage payload: %w", err)
  337. }
  338. return buf.Bytes(), nil
  339. }