forked from piki/kasa
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathkasa.c
107 lines (93 loc) · 2.62 KB
/
kasa.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
/* Raw TP-Link (Kasa) command sender/receiver
* Each invocation sends a single command and receives a single packet in response.
*
* This program is a minimal substitute for the tplink-lightbulb Node package.
* Because it's C, it's about 40x faster than the Node package. On a Raspberry
* Pi, that matters.
*
* Building:
* make
*
* Usage:
* ./kasa <ip-address> <json-blob>
*
* There's a good list of JSON blobs to try here:
* https://github.com/softScheck/tplink-smartplug/blob/master/tplink-smarthome-commands.txt
* Especially:
* - get bulb info: ./kasa <ip> '{"system":{"get_sysinfo":null}}'
* - turn bulb on: ./kasa <ip> '{"system":{"set_relay_state":{"state":1}}}'
* - turn bulb off: ./kasa <ip> '{"system":{"set_relay_state":{"state":0}}}'
*
* Written by Patrick Reynolds <[email protected]>
* Released into the public domain, or Creative Commons CC0, your choice.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#define KASA_PORT 9999
uint8_t *kasa_crypto(const uint8_t *p, int len, int enc) {
uint8_t *ret = malloc(len+1);
ret[len] = '\0';
uint8_t k = 0xab;
int i;
for (i=0; i<len; i++) {
ret[i] = (uint8_t)(k ^ p[i]);
k = enc ? ret[i] : p[i];
}
return ret;
}
uint8_t *kasa_encrypt(const uint8_t *p, int len) {
return kasa_crypto(p, len, 1);
}
uint8_t *kasa_decrypt(const uint8_t *p, int len) {
return kasa_crypto(p, len, 0);
}
int main(int argc, const char **argv) {
if (argc != 3) {
fprintf(stderr, "Usage:\n %s ip json-command\n", argv[0]);
exit(1);
}
struct in_addr addr;
if (!inet_aton(argv[1], &addr)) {
fprintf(stderr, "Could not parse \"%s\" as an IP\n", argv[1]);
exit(1);
}
uint8_t *enc = kasa_encrypt((const uint8_t*)argv[2], strlen(argv[2]));
int sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
if (sock == -1) {
perror("socket");
exit(1);
}
struct sockaddr_in sin;
sin.sin_family = AF_INET;
sin.sin_port = htons(0);
sin.sin_addr.s_addr = htonl(INADDR_ANY);
int res = bind(sock, (struct sockaddr*)&sin, sizeof(sin));
if (res == -1) {
perror("bind");
exit(1);
}
sin.sin_family = AF_INET;
sin.sin_port = htons(KASA_PORT);
sin.sin_addr = addr;
res = sendto(sock, enc, strlen(argv[2]), 0, (struct sockaddr*)&sin, sizeof(sin));
if (res == -1) {
perror("sendto");
exit(1);
}
free(enc);
char buf[4096];
socklen_t slen = sizeof(sin);
res = recvfrom(sock, buf, sizeof(buf), 0, (struct sockaddr*)&sin, &slen);
if (res == -1) {
perror("recvfrom");
exit(1);
}
uint8_t *dec = kasa_decrypt((const uint8_t*)buf, res);
fwrite((const char*)dec, 1, res, stdout);
putchar('\n');
free(dec);
return 0;
}