package TPLinkClient import ( "bytes" "encoding/binary" "fmt" ) // Most of the protocol implementation is from: // https://github.com/philippechataignon/smrt/blob/master/protocol.py func doQuery(header *PacketHeader, payload []byte) []byte { header.OpCode = Get header.SequenceID = (header.SequenceID + 1) % 1000 // Send the query packet packet := assmblePacket(*header, payload) applyKey(&packet) sendPacket(packet) // Listen for a response buf := make([]byte, 8000) len := recvPacket(&buf) if len < 1 { return []byte{} } data := make([]byte, len) copy(data, buf) applyKey(&data) return data } func assmblePacket(header PacketHeader, payload []byte) []byte { // Packet size is: 32 bytes header + length of the payload + length of the end bytes header.CheckLength = int16(32 + len(payload) + len(PACKET_END)) // Encode the header var headerBytes bytes.Buffer err := binary.Write(&headerBytes, binary.BigEndian, header) if err != nil { fmt.Println("Failed generating header bytes") } // Concatenate header, payload and end bytes return append(headerBytes.Bytes(), append(payload, PACKET_END...)...) } func buildPayload(requestType uint16, data []byte) []byte { var payload = make([]byte, 4) binary.BigEndian.PutUint16(payload[:2], requestType) copy(payload[2:4], data) return payload } func decodeHeader(data []byte) PacketHeader { var header PacketHeader // Decode header bytes to struct buf := bytes.NewBuffer(data) binary.Read(buf, binary.BigEndian, &header) return header } func decodePayload(data []byte) []PayloadItem { // Payload begins at byte 32 (after the header) payload := make([]byte, len(data)-32) copy(payload[:], data[32:]) results := make([]PayloadItem, 0) for len(payload) > len(PACKET_END) { // Decode TLV encoded datatype and length var dtype uint16 var dlen uint16 if err := binary.Read(bytes.NewReader(payload[:2]), binary.BigEndian, &dtype); err != nil { fmt.Println("Failed readling payload type") continue } if err := binary.Read(bytes.NewReader(payload[2:4]), binary.BigEndian, &dlen); err != nil { fmt.Println("Failed readling payload length") continue } // Get TLV data data := payload[4 : 4+dlen] // Try to decode the datatype payloadType := PayloadType{Id: dtype, Name: "unknown", DataType: "raw"} for _, e := range payloadTypes { if e.Id == dtype { payloadType = e } } // Append to list result := PayloadItem{ Type: payloadType, Value: data, } results = append(results, result) payload = payload[4+dlen:] } return results } func applyKey(data *[]byte) { s := make([]byte, len(KEY)) copy(s, KEY) var j byte = 0 for k := range *data { i := (k + 1) & 0xFF j = (j + s[i]) & 0xFF s[i], s[j] = s[j], s[i] // Swap elements in slice (*data)[k] ^= s[(s[i]+s[j])&0xFF] // XOR operation } }