Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

close duplicate client connections #170

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion include/homekit/characteristics.h
Original file line number Diff line number Diff line change
Expand Up @@ -815,7 +815,7 @@
.unit = homekit_unit_celsius, \
.permissions = homekit_permissions_paired_read \
| homekit_permissions_notify, \
.min_value = (float[]) {0}, \
.min_value = (float[]) {-50}, \
.max_value = (float[]) {100}, \
.min_step = (float[]) {0.1}, \
.value = HOMEKIT_FLOAT_(_value), \
Expand Down
2 changes: 1 addition & 1 deletion src/homekit_mdns_debug.c
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ uint8_t *mdns_print_answer(uint8_t *data, uint8_t *payload) {

uint16_t answer_type = mdns_read_u16(data + 0);
uint16_t answer_class = mdns_read_u16(data + 2);
uint32_t answer_ttl = mdns_read_u32(data + 4);
// uint32_t answer_ttl = mdns_read_u32(data + 4);
uint16_t answer_len = mdns_read_u16(data + 8);
data += 10;

Expand Down
70 changes: 67 additions & 3 deletions src/server.c
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,14 @@ typedef enum {
} characteristic_format_t;


typedef enum {
ENCRYPTION_STATE_FALSE = 0,
ENCRYPTION_STATE_VERIFIED,
ENCRYPTION_STATE_GOT_ACCESSORIES,
ENCRYPTION_STATE_IN_USE,
} ENCRYPTION_STATE;


typedef struct {
Srp *srp;
byte *public_key;
Expand Down Expand Up @@ -201,7 +209,7 @@ struct _client_context_t {

bool disconnect;

bool encrypted;
int encrypted;
byte read_key[32];
byte write_key[32];
int count_reads;
Expand Down Expand Up @@ -471,7 +479,7 @@ client_context_t *client_context_new() {
c->id = 0;

c->pairing_id = -1;
c->encrypted = false;
c->encrypted = ENCRYPTION_STATE_FALSE;
c->count_reads = 0;
c->count_writes = 0;

Expand Down Expand Up @@ -1101,6 +1109,20 @@ void send_tlv_error_response(client_context_t *context, int state, TLVError erro
}


void send_tlv_delay_response(client_context_t *context, int state, int delay) {
tlv_values_t *response = tlv_new();
if (!response) {
// TODO: panic?
return;
}
tlv_add_integer_value(response, TLVType_State, 1, state);
tlv_add_integer_value(response, TLVType_Error, 1, TLVError_Backoff);
tlv_add_integer_value(response, TLVType_RetryDelay, 1, delay);

send_tlv_response(context, response);
}


void send_tlv_response(client_context_t *context, tlv_values_t *values) {
CLIENT_DEBUG(context, "Sending TLV response");
TLV_DEBUG(values);
Expand Down Expand Up @@ -1249,6 +1271,8 @@ void homekit_server_on_identify(client_context_t *context) {
CLIENT_INFO(context, "Identify");
DEBUG_HEAP();

context->encrypted = ENCRYPTION_STATE_IN_USE;

if (context->server->paired) {
// Already paired
send_json_error_response(context, 400, HAPStatus_InsufficientPrivileges);
Expand Down Expand Up @@ -1969,6 +1993,19 @@ void homekit_server_on_pair_verify(client_context_t *context, const byte *data,
case 1: {
CLIENT_INFO(context, "Pair Verify Step 1/2");

int committed=0;
client_context_t *c = server->clients;
while (c) {
if (c->encrypted<ENCRYPTION_STATE_GOT_ACCESSORIES && !c->disconnect) committed++;
c = c->next;
}
if (xPortGetFreeHeapSize()<committed*6000) { //TODO: make this an external value?
CLIENT_ERROR(context, "Not enough free heap to commit to %d new clients, delaying this client 2s",committed);
send_tlv_delay_response(context, 2, 2); //2 second holdoff
context->disconnect = true;
break;
}

CLIENT_DEBUG(context, "Importing device Curve25519 public key");
tlv_t *tlv_device_public_key = tlv_get_value(message, TLVType_PublicKey);
if (!tlv_device_public_key) {
Expand Down Expand Up @@ -2503,7 +2540,7 @@ void homekit_server_on_pair_verify(client_context_t *context, const byte *data,

context->pairing_id = pairing_id;
context->permissions = permissions;
context->encrypted = true;
context->encrypted = ENCRYPTION_STATE_VERIFIED;

HOMEKIT_NOTIFY_EVENT(context->server, HOMEKIT_EVENT_CLIENT_VERIFIED);

Expand Down Expand Up @@ -2615,12 +2652,16 @@ void homekit_server_on_get_accessories(client_context_t *context) {
json_flush(json);

client_send_chunk(NULL, 0, context);

context->encrypted = ENCRYPTION_STATE_GOT_ACCESSORIES;
}

void homekit_server_on_get_characteristics(client_context_t *context) {
CLIENT_INFO(context, "Get Characteristics");
DEBUG_HEAP();

context->encrypted = ENCRYPTION_STATE_IN_USE;

if (context->server->endpoint_params.ids[0].aid == 0) {
CLIENT_ERROR(context, "Invalid get characteristics request: missing ID parameter");
send_json_error_response(context, 400, HAPStatus_InvalidValue);
Expand Down Expand Up @@ -2719,6 +2760,8 @@ void homekit_server_on_update_characteristics(client_context_t *context, const b
CLIENT_INFO(context, "Update Characteristics");
DEBUG_HEAP();

context->encrypted = ENCRYPTION_STATE_IN_USE;

cJSON *json = cJSON_Parse((char *)data);

if (!json) {
Expand Down Expand Up @@ -3159,6 +3202,8 @@ void homekit_server_on_pairings(client_context_t *context, const byte *data, siz
DEBUG("HomeKit Pairings");
DEBUG_HEAP();

context->encrypted = ENCRYPTION_STATE_IN_USE;

tlv_values_t *message = tlv_new();
if (!message) {
CLIENT_ERROR(context, "Failed to allocate memory for TLV payload");
Expand Down Expand Up @@ -3426,6 +3471,8 @@ void homekit_server_on_resource(client_context_t *context) {
CLIENT_INFO(context, "Resource");
DEBUG_HEAP();

context->encrypted = ENCRYPTION_STATE_IN_USE;

if (!context->server->config->on_resource) {
send_404_response(context);
return;
Expand Down Expand Up @@ -3759,6 +3806,21 @@ void homekit_server_close_client(homekit_server_t *server, client_context_t *con
}


void homekit_server_close_duplicate_clients(homekit_server_t *server, struct sockaddr_in addr) {
struct sockaddr_in old_addr;
socklen_t addr_len = sizeof(addr);
client_context_t *context = server->clients;

while (context) {
if ( getpeername(context->socket, (struct sockaddr *)&old_addr, &addr_len) == 0 &&
(old_addr.sin_addr.s_addr == addr.sin_addr.s_addr) &&
(old_addr.sin_port != addr.sin_port) )
context->disconnect = true;
context = context->next;
}
}


client_context_t *homekit_server_accept_client(homekit_server_t *server) {
int s = accept(server->listen_fd, (struct sockaddr *)NULL, (socklen_t *)NULL);
if (s < 0) {
Expand Down Expand Up @@ -3831,6 +3893,8 @@ client_context_t *homekit_server_accept_client(homekit_server_t *server) {
} else {
strcpy(address_buffer, "?.?.?.?");
}

homekit_server_close_duplicate_clients(server, addr); //remove old connections with same ip but different port

CLIENT_INFO(context, "Got new client connection from %s", address_buffer);

Expand Down