Files
2024-05-03 16:44:08 +02:00

114 lines
2.8 KiB
Go

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
}
}