diff --git a/pkg/wyze/tutk/conn.go b/pkg/wyze/tutk/conn.go index 962f9166..f524ba9d 100644 --- a/pkg/wyze/tutk/conn.go +++ b/pkg/wyze/tutk/conn.go @@ -49,6 +49,7 @@ type Conn struct { seq uint16 seqCmd uint16 avSeq uint32 + kaSeq uint32 // DTLS main *dtls.Conn @@ -317,8 +318,6 @@ func (c *Conn) WriteAndWait(req []byte, timeout time.Duration, ok func(res []byt func (c *Conn) WriteAndWaitIOCtrl(cmd uint16, payload []byte, expectCmd uint16, timeout time.Duration) ([]byte, error) { frame := c.buildIOCtrlFrame(payload) - - // Retry send every second var t *time.Timer t = time.AfterFunc(1, func() { if _, err := c.main.Write(frame); err == nil && t != nil { @@ -588,15 +587,23 @@ func (c *Conn) reader() { } // NEW protocol (0xCC51) - if c.newProto && n >= NewHeaderSize+NewAuthSize && binary.LittleEndian.Uint16(buf[:2]) == MagicNewProto { - if binary.LittleEndian.Uint16(buf[4:]) == CmdNewDTLS { - ch := byte(binary.LittleEndian.Uint16(buf[12:]) >> 8) - dtls := buf[NewHeaderSize : n-NewAuthSize] - switch ch { - case IOTCChannelMain: - c.queue(c.mainBuf, dtls) - case IOTCChannelBack: - c.queue(c.speakBuf, dtls) + if c.newProto && n >= 12 && binary.LittleEndian.Uint16(buf[:2]) == MagicNewProto { + cmd := binary.LittleEndian.Uint16(buf[4:]) + switch cmd { + case CmdNewKeepalive: + if n >= NewKeepaliveSize { + _ = c.Write(c.buildNewKeepalive()) + } + case CmdNewDTLS: + if n >= NewHeaderSize+NewAuthSize { + ch := byte(binary.LittleEndian.Uint16(buf[12:]) >> 8) + dtls := buf[NewHeaderSize : n-NewAuthSize] + switch ch { + case IOTCChannelMain: + c.queue(c.mainBuf, dtls) + case IOTCChannelBack: + c.queue(c.speakBuf, dtls) + } } } continue @@ -696,7 +703,6 @@ func (c *Conn) buildDisco(stage byte) []byte { binary.LittleEndian.PutUint16(b[4:], OldDiscoBodySize) // body size binary.LittleEndian.PutUint16(b[8:], CmdDiscoReq) // 0x0601 binary.LittleEndian.PutUint16(b[10:], 0x0021) // flags - body := b[OldHeaderSize:] copy(body[:UIDSize], c.uid) copy(body[36:], "\x01\x01\x02\x04") // unknown @@ -720,8 +726,6 @@ func (c *Conn) buildNewDisco(seq, ticket uint16, isResponse bool) []byte { binary.LittleEndian.PutUint16(b[14:], ticket) copy(b[16:24], c.sid) copy(b[24:32], "\x00\x08\x03\x04\x1d\x00\x00\x00") // SDK 4.3.8.0 - - // HMAC-SHA1(UID+AuthKey, header) authKey := crypto.CalculateAuthKey(c.enr, c.mac) h := hmac.New(sha1.New, append([]byte(c.uid), authKey...)) h.Write(b[:32]) @@ -729,13 +733,27 @@ func (c *Conn) buildNewDisco(seq, ticket uint16, isResponse bool) []byte { return b } +func (c *Conn) buildNewKeepalive() []byte { + c.kaSeq += 2 + b := make([]byte, NewKeepaliveSize) + binary.LittleEndian.PutUint16(b[0:], MagicNewProto) // 0xCC51 + binary.LittleEndian.PutUint16(b[4:], CmdNewKeepalive) // 0x1202 + binary.LittleEndian.PutUint16(b[6:], 0x0024) // 36 bytes payload + binary.LittleEndian.PutUint32(b[16:], c.kaSeq) // counter + copy(b[20:28], c.sid) // session ID + authKey := crypto.CalculateAuthKey(c.enr, c.mac) + h := hmac.New(sha1.New, append([]byte(c.uid), authKey...)) + h.Write(b[:28]) + copy(b[28:48], h.Sum(nil)) + return b +} + func (c *Conn) buildSession() []byte { b := make([]byte, OldSessionSize) copy(b, "\x04\x02\x1a\x02") // marker + mode binary.LittleEndian.PutUint16(b[4:], OldSessionBody) // body size binary.LittleEndian.PutUint16(b[8:], CmdSessionReq) // 0x0402 binary.LittleEndian.PutUint16(b[10:], 0x0033) // flags - body := b[OldHeaderSize:] copy(body[:UIDSize], c.uid) copy(body[UIDSize:], c.rid) @@ -805,9 +823,7 @@ func (c *Conn) buildAudioFrame(payload []byte, timestampUS uint32, codec uint16, binary.LittleEndian.PutUint32(b[24:], uint32(totalPayload)) binary.LittleEndian.PutUint32(b[28:], prevFrame) binary.LittleEndian.PutUint32(b[32:], c.audioFrame) - - // Payload + FrameInfo - copy(b[36:], payload) + copy(b[36:], payload) // Payload + FrameInfo fi := b[36+len(payload):] binary.LittleEndian.PutUint16(fi, codec) fi[2] = BuildAudioFlags(sampleRate, true, channels == 2) @@ -845,8 +861,6 @@ func (c *Conn) buildNewTxData(payload []byte, channel byte) []byte { copy(b[16:24], c.sid) binary.LittleEndian.PutUint32(b[24:], 1) // const copy(b[NewHeaderSize:], payload) - - // HMAC-SHA1(UID+AuthKey, header) authKey := crypto.CalculateAuthKey(c.enr, c.mac) h := hmac.New(sha1.New, append([]byte(c.uid), authKey...)) h.Write(b[:NewHeaderSize]) diff --git a/pkg/wyze/tutk/proto.go b/pkg/wyze/tutk/proto.go index 01bd7cd5..5614d643 100644 --- a/pkg/wyze/tutk/proto.go +++ b/pkg/wyze/tutk/proto.go @@ -138,13 +138,16 @@ const ( // NEW Protocol (0xCC51) const ( - MagicNewProto uint16 = 0xCC51 - CmdNewDisco uint16 = 0x1002 - CmdNewDTLS uint16 = 0x1502 - NewPayloadSize uint16 = 0x0028 - NewPacketSize = 52 - NewHeaderSize = 28 - NewAuthSize = 20 + MagicNewProto uint16 = 0xCC51 + CmdNewDisco uint16 = 0x1002 + CmdNewKeepalive uint16 = 0x1202 + CmdNewClose uint16 = 0x1302 + CmdNewDTLS uint16 = 0x1502 + NewPayloadSize uint16 = 0x0028 + NewPacketSize = 52 + NewHeaderSize = 28 + NewAuthSize = 20 + NewKeepaliveSize = 48 ) const (