1
0
mirror of https://github.com/taigrr/tplinkController synced 2025-01-18 04:43:13 -08:00

Compare commits

..

No commits in common. "master" and "v1.1" have entirely different histories.
master ... v1.1

6 changed files with 126 additions and 158 deletions

1
.gitignore vendored
View File

@ -1,4 +1,3 @@
hs100 hs100
*.o *.o
*.swp *.swp
*~

View File

@ -1,7 +1,6 @@
target ?= hs100 target ?= hs100
objects := $(patsubst %.c,%.o,$(wildcard *.c)) objects := $(patsubst %.c,%.o,$(wildcard *.c))
LDFLAGS=-lm
CFLAGS=-std=c99 -Os CFLAGS=-std=c99 -Os
ifdef DEBUG ifdef DEBUG
CFLAGS+=-Wall -Werror -ggdb CFLAGS+=-Wall -Werror -ggdb

View File

@ -2,7 +2,7 @@
A tool for using TP-Link HS100/HS105/HS110 wi-fi smart plugs. You can turn A tool for using TP-Link HS100/HS105/HS110 wi-fi smart plugs. You can turn
them on and off, reboot them, and so on. You can even set them up without them on and off, reboot them, and so on. You can even set them up without
using TP-Link's app (see Initial Setup). using the app (see Initial Setup).
Tested to work on Linux, OSX, IRIX, and Windows under WSL. Tested to work on Linux, OSX, IRIX, and Windows under WSL.
@ -51,7 +51,7 @@ plug's AP.
- Disable cloud nonsense by setting a bogus server URL: `hs100 192.168.0.1 set_server localhost` - Disable cloud nonsense by setting a bogus server URL: `hs100 192.168.0.1 set_server localhost`
- Scan for your wifi AP using `hs100 192.168.0.1 scan`. Find your AP in the - Scan for your wifi AP using `hs100 192.168.0.1 scan`. Find your AP in the
list and note its `key_type`; you will need this to associate. list and note its `key_type`; you will need this to associate.
- Associate with your AP using `hs100 192.168.0.1 associate <ssid> <password> <key_type>` - Associate with your AP using `hs100 192.168.0.1 <ssid> <password> <key_type>`
. Your key\_type is a number that indicates the kind of wifi security that . Your key\_type is a number that indicates the kind of wifi security that
your AP is using. You can find it by doing a wifi scan (see previous step). your AP is using. You can find it by doing a wifi scan (see previous step).

119
comms.c
View File

@ -1,28 +1,27 @@
#include <arpa/inet.h> #include <stddef.h>
#include <inttypes.h> #include <inttypes.h>
#include <stdbool.h> #include <stdbool.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <unistd.h> #include <unistd.h>
#include "comms.h" #include "comms.h"
#define RECV_BUF_SIZE 4096
bool hs100_encrypt(uint8_t *d, uint8_t *s, size_t len) bool hs100_encrypt(uint8_t *d, uint8_t *s, size_t len)
{ {
uint8_t key, temp; if(d == NULL)
size_t i;
if (d == NULL)
return false; return false;
if (s == NULL) if(s == NULL)
return false; return false;
if (len == 0) if(len == 0)
return false; return false;
key = 0xab; uint8_t key = 0xab;
for (i = 0; i < len; i++) { for(size_t i=0; i<len; i++) {
temp = key ^ s[i]; uint8_t temp = key ^ s[i];
key = temp; key = temp;
d[i] = temp; d[i] = temp;
} }
@ -31,19 +30,16 @@ bool hs100_encrypt(uint8_t *d, uint8_t *s, size_t len)
bool hs100_decrypt(uint8_t *d, uint8_t *s, size_t len) bool hs100_decrypt(uint8_t *d, uint8_t *s, size_t len)
{ {
uint8_t key, temp; if(d == NULL)
size_t i;
if (d == NULL)
return false; return false;
if (s == NULL) if(s == NULL)
return false; return false;
if (len == 0) if(len == 0)
return false; return false;
key = 0xab; uint8_t key = 0xab;
for (i = 0; i < len; i++) { for(size_t i=0; i<len; i++) {
temp = key ^ s[i]; uint8_t temp = key ^ s[i];
key = s[i]; key = s[i];
d[i] = temp; d[i] = temp;
} }
@ -52,23 +48,17 @@ bool hs100_decrypt(uint8_t *d, uint8_t *s, size_t len)
uint8_t *hs100_encode(size_t *outlen, char *srcmsg) uint8_t *hs100_encode(size_t *outlen, char *srcmsg)
{ {
size_t srcmsg_len; if(srcmsg == NULL) return NULL;
uint8_t *d;
uint32_t temp;
if (srcmsg == NULL) size_t srcmsg_len = strlen(srcmsg);
return NULL;
srcmsg_len = strlen(srcmsg);
*outlen = srcmsg_len + 4; *outlen = srcmsg_len + 4;
d = calloc(1, *outlen); uint8_t *d = calloc(1, *outlen);
if (d == NULL) if(d == NULL) return NULL;
return NULL; if(!hs100_encrypt(d+4, (uint8_t *)srcmsg, srcmsg_len)) {
if (!hs100_encrypt(d + 4, (uint8_t *) srcmsg, srcmsg_len)) {
free(d); free(d);
return NULL; return NULL;
} }
temp = htonl(srcmsg_len); uint32_t temp = htonl(srcmsg_len);
memcpy(d, &temp, 4); memcpy(d, &temp, 4);
return d; return d;
@ -76,24 +66,20 @@ uint8_t *hs100_encode(size_t *outlen, char *srcmsg)
char *hs100_decode(uint8_t *s, size_t s_len) char *hs100_decode(uint8_t *s, size_t s_len)
{ {
if(s == NULL) return NULL;
if(s_len <= 4) return NULL;
uint32_t in_s_len; uint32_t in_s_len;
char *outbuf;
if (s == NULL)
return NULL;
if (s_len <= 4)
return NULL;
memcpy(&in_s_len, s, 4); memcpy(&in_s_len, s, 4);
in_s_len = ntohl(in_s_len); in_s_len = ntohl(in_s_len);
if ((s_len - 4) < in_s_len) { if((s_len - 4) < in_s_len) {
/* packet was cut short- adjust in_s_len */ // packet was cut short- adjust in_s_len
in_s_len = s_len - 4; in_s_len = s_len - 4;
} }
outbuf = calloc(1, in_s_len + 1); char *outbuf = calloc(1,in_s_len+1);
if (!hs100_decrypt((uint8_t *) outbuf, s + 4, in_s_len)) { if(!hs100_decrypt((uint8_t*)outbuf, s+4, in_s_len)) {
free(outbuf); free(outbuf);
return NULL; return NULL;
} }
@ -104,44 +90,33 @@ char *hs100_decode(uint8_t *s, size_t s_len)
char *hs100_send(char *servaddr, char *msg) char *hs100_send(char *servaddr, char *msg)
{ {
size_t s_len; size_t s_len;
int sock; uint8_t *s = hs100_encode(&s_len, msg);
uint8_t *s, *recvbuf; if(s == NULL)
return NULL;
int sock = socket(AF_INET, SOCK_STREAM, 0);
if(sock < 0) return NULL;
struct sockaddr_in address; struct sockaddr_in address;
uint32_t msglen;
size_t recvsize;
char *recvmsg;
s = hs100_encode(&s_len, msg);
if (s == NULL)
return NULL;
sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock < 0)
return NULL;
memset(&address, '0', sizeof(struct sockaddr_in)); memset(&address, '0', sizeof(struct sockaddr_in));
address.sin_family = AF_INET; address.sin_family = AF_INET;
address.sin_port = htons(9999); address.sin_port = htons(9999);
if (inet_pton(AF_INET, servaddr, &address.sin_addr) <= 0) if(inet_pton(AF_INET, servaddr, &address.sin_addr)<=0)
return NULL; return NULL;
if (connect(sock, (struct sockaddr *)&address, if(connect(sock, (struct sockaddr *)&address,
sizeof(struct sockaddr_in)) < 0) sizeof(struct sockaddr_in)) < 0)
return NULL; return NULL;
send(sock, s, s_len, 0); send(sock, s, s_len, 0);
free(s); free(s);
recvsize = recv(sock, &msglen, sizeof(msglen), MSG_PEEK); uint8_t recvbuf[RECV_BUF_SIZE];
if (recvsize != sizeof(msglen)) { size_t received_size = recv(sock, recvbuf, RECV_BUF_SIZE, 0);
return NULL;
}
msglen = ntohl(msglen) + 4;
recvbuf = calloc(1, (size_t) msglen);
recvsize = recv(sock, recvbuf, msglen, MSG_WAITALL);
close(sock); close(sock);
recvmsg = hs100_decode(recvbuf, msglen); if(received_size == 0)
free(recvbuf); return NULL;
char *recvmsg = hs100_decode(recvbuf, received_size);
return recvmsg; return recvmsg;
} }

View File

@ -1,65 +0,0 @@
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "comms.h"
char *handler_associate(int argc, char *argv[])
{
const char *template =
"{\"netif\":{\"set_stainfo\":{\"ssid\":\"%s\",\"password\":"
"\"%s\",\"key_type\":%d}}}";
char *plug_addr = argv[1];
char *ssid = argv[3];
char *password = argv[4];
char *key_type = argv[5];
char *endptr, *msg, *response;
int key_type_num;
size_t len;
if (argc < 6) {
fprintf(stderr, "not enough arguments\n");
exit(1);
}
errno = 0;
key_type_num = (int)strtol(key_type, &endptr, 10);
if (errno || endptr == key_type) {
fprintf(stderr, "invalid key type: %s\n", key_type);
exit(1);
}
len = snprintf(NULL, 0, template, ssid, password,
key_type_num);
len++; /* snprintf does not count the null terminator */
msg = calloc(1, len);
snprintf(msg, len, template, ssid, password, key_type_num);
response = hs100_send(plug_addr, msg);
return response;
}
char *handler_set_server(int argc, char *argv[])
{
const char *template =
"{\"cnCloud\":{\"set_server_url\":{\"server\":\"%s\"}}}";
char *plug_addr = argv[1];
char *server = argv[3];
size_t len;
char *msg, *response;
if (argc < 4) {
fprintf(stderr, "not enough arguments\n");
exit(1);
}
len = snprintf(NULL, 0, template, server);
len++; /* snprintf does not count the null terminator */
msg = calloc(1, len);
snprintf(msg, len, template, server);
response = hs100_send(plug_addr, msg);
return response;
}

94
hs100.c
View File

@ -1,18 +1,75 @@
#include <stdio.h> #include <stdio.h>
#include <inttypes.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <errno.h>
#include "version.h" #include "version.h"
#include "comms.h" #include "comms.h"
// handlers for more complicated commands char *handler_associate(int argc, char *argv[])
extern char *handler_associate(int argc, char *argv[]); {
extern char *handler_set_server(int argc, char *argv[]); if(argc < 6) {
fprintf(stderr, "not enough arguments\n");
exit(1);
}
char *plug_addr = argv[1];
char *ssid = argv[3];
char *password = argv[4];
char *key_type = argv[5];
errno = 0;
char *endptr;
int key_type_num = (int)strtol(key_type, &endptr, 10);
if(errno || endptr == key_type) {
fprintf(stderr, "invalid key type: %s\n", key_type);
exit(1);
}
const char *template =
"{\"netif\":{\"set_stainfo\":{\"ssid\":\"%s\",\"password\":"
"\"%s\",\"key_type\":%d}}}";
size_t len = snprintf(NULL, 0, template, ssid, password,
key_type_num);
len++; // snprintf does not count the null terminator
char *msg = calloc(1, len);
snprintf(msg, len, template, ssid, password, key_type_num);
char *response = hs100_send(plug_addr, msg);
return response;
}
char *handler_set_server(int argc, char *argv[])
{
if(argc < 4) {
fprintf(stderr, "not enough arguments\n");
exit(1);
}
char *plug_addr = argv[1];
char *server = argv[3];
const char *template =
"{\"cnCloud\":{\"set_server_url\":{\"server\":\"%s\"}}}";
size_t len = snprintf(NULL, 0, template, server);
len++; // snprintf does not count the null terminator
char *msg = calloc(1, len);
snprintf(msg, len, template, server);
char *response = hs100_send(plug_addr, msg);
return response;
}
struct cmd_s { struct cmd_s {
char *command; char *command;
char *help; char *help;
char *json; char *json;
char *(*handler) (int argc, char *argv[]); char *(*handler)(int argc, char *argv[]);
int end; int end;
}; };
struct cmd_s cmds[] = { struct cmd_s cmds[] = {
@ -67,8 +124,9 @@ struct cmd_s cmds[] = {
struct cmd_s *get_cmd_from_name(char *needle) struct cmd_s *get_cmd_from_name(char *needle)
{ {
int cmds_index = 0; int cmds_index = 0;
while (!cmds[cmds_index].end) { while(!cmds[cmds_index].end)
if (!strcmp(cmds[cmds_index].command, needle)) {
if(!strcmp(cmds[cmds_index].command, needle))
return &cmds[cmds_index]; return &cmds[cmds_index];
cmds_index++; cmds_index++;
} }
@ -77,14 +135,16 @@ struct cmd_s *get_cmd_from_name(char *needle)
void print_usage() void print_usage()
{ {
fprintf(stderr, "hs100 version " VERSION_STRING fprintf(stderr, "hs100 version " VERSION_STRING ", Copyright (C) 2018 Jason Benaim.\n"
", Copyright (C) 2018-2019 Jason Benaim.\n" "A tool for using certain wifi smart plugs.\n"
"A tool for using certain wifi smart plugs.\n\n" "\n"
"usage: hs100 <ip> <command>\n\n" "usage: hs100 <ip> <command>\n"
"\n"
"Commands:\n" "Commands:\n"
); );
int cmds_index = 0; int cmds_index = 0;
while (!cmds[cmds_index].end) { while(!cmds[cmds_index].end)
{
fprintf(stderr, "\t%s\n\n", cmds[cmds_index].help); fprintf(stderr, "\t%s\n\n", cmds[cmds_index].help);
cmds_index++; cmds_index++;
} }
@ -93,7 +153,7 @@ void print_usage()
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
if (argc < 3) { if(argc < 3) {
print_usage(); print_usage();
return 1; return 1;
} }
@ -102,17 +162,17 @@ int main(int argc, char *argv[])
char *response = NULL; char *response = NULL;
struct cmd_s *cmd = get_cmd_from_name(cmd_string); struct cmd_s *cmd = get_cmd_from_name(cmd_string);
if (cmd != NULL) { if(cmd != NULL) {
if (cmd->handler != NULL) if(cmd->handler != NULL)
response = cmd->handler(argc, argv); response = cmd->handler(argc, argv);
else if (cmd->json != NULL) else if(cmd->json != NULL)
response = hs100_send(plug_addr, cmd->json); response = hs100_send(plug_addr, cmd->json);
} else { } else {
// command not recognized, so send it to the plug raw // command not recognized, so send it to the plug raw
response = hs100_send(plug_addr, cmd_string); response = hs100_send(plug_addr, cmd_string);
} }
if (response == NULL) { if(response == NULL) {
fprintf(stderr, "failed to send command\n"); fprintf(stderr, "failed to send command\n");
return 1; return 1;
} }