Skip to content

Commit

Permalink
A bit of work done on the TCP relay server.
Browse files Browse the repository at this point in the history
  • Loading branch information
irungentoo committed Mar 14, 2014
1 parent 29afa26 commit 3acf43b
Show file tree
Hide file tree
Showing 5 changed files with 192 additions and 32 deletions.
117 changes: 117 additions & 0 deletions auto_tests/TCP_test.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <sys/types.h>
#include <stdint.h>
#include <string.h>
#include <check.h>
#include <stdlib.h>
#include <time.h>

#include "../toxcore/TCP_server.h"
#include "../toxcore/util.h"

#if defined(_WIN32) || defined(__WIN32__) || defined (WIN32)
#define c_sleep(x) Sleep(1*x)
#else
#include <unistd.h>
#define c_sleep(x) usleep(1000*x)
#endif

#define NUM_PORTS 3

START_TEST(test_basic)
{
uint16_t ports[NUM_PORTS] = {12345, 33445, 25643};
uint8_t self_public_key[crypto_box_PUBLICKEYBYTES];
uint8_t self_secret_key[crypto_box_SECRETKEYBYTES];
crypto_box_keypair(self_public_key, self_secret_key);
TCP_Server *tcp_s = new_TCP_server(1, NUM_PORTS, ports, self_public_key, self_secret_key);
ck_assert_msg(tcp_s != NULL, "Failed to create TCP relay server");

sock_t sock = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP);
struct sockaddr_in6 addr6_loopback = {0};
addr6_loopback.sin6_family = AF_INET6;
addr6_loopback.sin6_port = htons(ports[rand() % NUM_PORTS]);
addr6_loopback.sin6_addr = in6addr_loopback;

int ret = connect(sock, (struct sockaddr *)&addr6_loopback, sizeof(addr6_loopback));
ck_assert_msg(ret == 0, "Failed to connect to TCP relay server");

uint8_t f_public_key[crypto_box_PUBLICKEYBYTES];
uint8_t f_secret_key[crypto_box_SECRETKEYBYTES];
uint8_t f_nonce[crypto_box_NONCEBYTES];
crypto_box_keypair(f_public_key, f_secret_key);
random_nonce(f_nonce);

uint8_t t_secret_key[crypto_box_SECRETKEYBYTES];
uint8_t handshake_plain[TCP_HANDSHAKE_PLAIN_SIZE];
crypto_box_keypair(handshake_plain, t_secret_key);
memcpy(handshake_plain + crypto_box_PUBLICKEYBYTES, f_nonce, crypto_box_NONCEBYTES);
uint8_t handshake[TCP_CLIENT_HANDSHAKE_SIZE];
memcpy(handshake, f_public_key, crypto_box_PUBLICKEYBYTES);
new_nonce(handshake + crypto_box_PUBLICKEYBYTES);

ret = encrypt_data(self_public_key, f_secret_key, handshake + crypto_box_PUBLICKEYBYTES, handshake_plain,
TCP_HANDSHAKE_PLAIN_SIZE, handshake + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES);
ck_assert_msg(ret == TCP_CLIENT_HANDSHAKE_SIZE - (crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES),
"Encrypt failed.");
ck_assert_msg(send(sock, handshake, TCP_CLIENT_HANDSHAKE_SIZE - 1, 0) == TCP_CLIENT_HANDSHAKE_SIZE - 1, "send Failed.");
c_sleep(50);
do_TCP_server(tcp_s);
c_sleep(50);
do_TCP_server(tcp_s);
c_sleep(50);
ck_assert_msg(send(sock, handshake + (TCP_CLIENT_HANDSHAKE_SIZE - 1), 1, 0) == 1, "send Failed.");
c_sleep(50);
do_TCP_server(tcp_s);
c_sleep(50);
do_TCP_server(tcp_s);
c_sleep(50);
uint8_t response[TCP_SERVER_HANDSHAKE_SIZE];
uint8_t response_plain[TCP_HANDSHAKE_PLAIN_SIZE];
ck_assert_msg(recv(sock, response, TCP_SERVER_HANDSHAKE_SIZE, 0) == TCP_SERVER_HANDSHAKE_SIZE, "recv Failed.");
ret = decrypt_data(self_public_key, f_secret_key, response, response + crypto_box_NONCEBYTES,
TCP_SERVER_HANDSHAKE_SIZE - crypto_box_NONCEBYTES, response_plain);
ck_assert_msg(ret == TCP_HANDSHAKE_PLAIN_SIZE, "Decrypt Failed.");
uint8_t f_nonce_r[crypto_box_NONCEBYTES];
uint8_t f_shared_key[crypto_box_BEFORENMBYTES];
encrypt_precompute(response_plain, t_secret_key, f_shared_key);
memcpy(f_nonce_r, response_plain + crypto_box_BEFORENMBYTES, crypto_box_NONCEBYTES);


}
END_TEST

#define DEFTESTCASE(NAME) \
TCase *tc_##NAME = tcase_create(#NAME); \
tcase_add_test(tc_##NAME, test_##NAME); \
suite_add_tcase(s, tc_##NAME);

#define DEFTESTCASE_SLOW(NAME, TIMEOUT) \
DEFTESTCASE(NAME) \
tcase_set_timeout(tc_##NAME, TIMEOUT);
Suite *TCP_suite(void)
{
Suite *s = suite_create("TCP");

DEFTESTCASE_SLOW(basic, 5);
return s;
}

int main(int argc, char *argv[])
{
srand((unsigned int) time(NULL));

Suite *TCP = TCP_suite();
SRunner *test_runner = srunner_create(TCP);

int number_failed = 0;
srunner_run_all(test_runner, CK_NORMAL);
number_failed = srunner_ntests_failed(test_runner);

srunner_free(test_runner);

return number_failed;
}
3 changes: 3 additions & 0 deletions docs/TCP_Network.txt
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@ So if you would inspect the TCP stream you would see:
[[uint16_t (length of data)][data]][[uint16_t (length of
data)][data]][[uint16_t (length of data)][data]]

Note that both handshake packets don't have this format (the length for them is
always the same so we don't need to specify it.)

When the client connects to the server, he sends this packet:
[public key of client (32 bytes)][nonce for the encrypted data [24
bytes]][encrypted with the private key of the client and public key of the
Expand Down
2 changes: 1 addition & 1 deletion docs/TODO
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ Friend_requests.c:

[NOT STARTED] Make the core save/datafile portable across client versions/different processor architectures.

[NOT STARTED] A way for people to connect to people on Tox if they are behind a bad NAT that
[IN PROGRESS] A way for people to connect to people on Tox if they are behind a bad NAT that
blocks UDP (or is just unpunchable) (docs/TCP_Network.txt)

[NEEDS TESTING] Make the save made with tox_save_encrypted(...) harder to brute force.
Expand Down
94 changes: 66 additions & 28 deletions toxcore/TCP_server.c
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ static uint16_t read_length(sock_t sock)
int count;
ioctl(sock, FIONREAD, &count);

if (count >= sizeof(uint16_t)) {
if ((unsigned int)count >= sizeof(uint16_t)) {
uint16_t length;
int len = recv(sock, &length, sizeof(uint16_t), 0);

Expand Down Expand Up @@ -169,7 +169,7 @@ static void kill_TCP_connection(TCP_Secure_Connection *con)
memset(con, 0, sizeof(TCP_Secure_Connection));
}

/* return 0 if everything went well.
/* return 1 if everything went well.
* return -1 if the connection must be killed.
*/
static int handle_TCP_handshake(TCP_Secure_Connection *con, uint8_t *data, uint16_t length, uint8_t *self_secret_key)
Expand Down Expand Up @@ -209,35 +209,23 @@ static int handle_TCP_handshake(TCP_Secure_Connection *con, uint8_t *data, uint1

encrypt_precompute(plain, temp_secret_key, con->shared_key);
con->status = TCP_STATUS_UNCONFIRMED;
return 0;
return 1;
}

/* return 0 if everything went well.
/* return 1 if connection handshake was handled correctly.
* return 0 if we didn't get it yet.
* return -1 if the connection must be killed.
*/
static int read_connection_handshake(TCP_Secure_Connection *con, uint8_t *self_secret_key)
{
while (1) {
if (con->next_packet_length == 0) {
uint16_t len = read_length(con->sock);

if (len == 0)
break;

if (len != TCP_CLIENT_HANDSHAKE_SIZE)
return -1;
uint8_t data[TCP_CLIENT_HANDSHAKE_SIZE];
int len = 0;

con->next_packet_length = len;
} else {
uint8_t data[con->next_packet_length];

if (read_TCP_packet(con->sock, data, con->next_packet_length) != -1) {
return handle_TCP_handshake(con, data, con->next_packet_length, self_secret_key);
} else {
break;
}
}
if ((len = read_TCP_packet(con->sock, data, TCP_CLIENT_HANDSHAKE_SIZE)) != -1) {
return handle_TCP_handshake(con, data, len, self_secret_key);
}

return 0;
}

/* return 1 on success
Expand All @@ -253,8 +241,17 @@ static int accept_connection(TCP_Server *TCP_server, sock_t sock)
return 0;
}

printf("accepted %u\n", sock);
TCP_Secure_Connection *conn =
&TCP_server->incomming_connection_queue[TCP_server->incomming_connection_queue_index % MAX_INCOMMING_CONNECTIONS];

if (conn->status != TCP_STATUS_NO_STATUS)
kill_TCP_connection(conn);

conn->status = TCP_STATUS_CONNECTED;
conn->sock = sock;
conn->next_packet_length = 0;

++TCP_server->incomming_connection_queue_index;
return 1;
}

Expand Down Expand Up @@ -288,7 +285,7 @@ TCP_Server *new_TCP_server(uint8_t ipv6_enabled, uint16_t num_sockets, uint16_t
if (num_sockets == 0 || ports == NULL)
return NULL;

TCP_Server *temp = calloc(1, sizeof(Networking_Core));
TCP_Server *temp = calloc(1, sizeof(TCP_Server));

if (temp == NULL)
return NULL;
Expand Down Expand Up @@ -324,22 +321,63 @@ TCP_Server *new_TCP_server(uint8_t ipv6_enabled, uint16_t num_sockets, uint16_t
return temp;
}

void do_TCP_server(TCP_Server *TCP_server)
static void do_TCP_accept_new(TCP_Server *TCP_server)
{
uint32_t i;

for (i = 0; i < TCP_server->num_listening_socks; ++i) {
struct sockaddr_storage addr;
int addrlen = sizeof(addr);
unsigned int addrlen = sizeof(addr);
sock_t sock;

do {
sock = accept(TCP_server->socks_listening[i], (struct sockaddr *)&addr, &addrlen);
//TODO
} while (accept_connection(TCP_server, sock));
}
}

static void do_TCP_incomming(TCP_Server *TCP_server)
{
uint32_t i;

for (i = 0; i < MAX_INCOMMING_CONNECTIONS; ++i) {
if (TCP_server->incomming_connection_queue[i].status != TCP_STATUS_CONNECTED)
continue;

int ret = read_connection_handshake(&TCP_server->incomming_connection_queue[i], TCP_server->secret_key);

if (ret == -1) {
kill_TCP_connection(&TCP_server->incomming_connection_queue[i]);
} else if (ret == 1) {
TCP_Secure_Connection *conn_old = &TCP_server->incomming_connection_queue[i];
TCP_Secure_Connection *conn_new =
&TCP_server->unconfirmed_connection_queue[TCP_server->unconfirmed_connection_queue_index % MAX_INCOMMING_CONNECTIONS];

if (conn_new->status != TCP_STATUS_NO_STATUS)
kill_TCP_connection(conn_new);

memcpy(conn_new, conn_old, sizeof(TCP_Secure_Connection));
memset(conn_old, 0, sizeof(TCP_Secure_Connection));
++TCP_server->unconfirmed_connection_queue_index;
}
}
}

static void do_TCP_unconfirmed(TCP_Server *TCP_server)
{
uint32_t i;

for (i = 0; i < MAX_INCOMMING_CONNECTIONS; ++i) {
if (TCP_server->incomming_connection_queue[i].status != TCP_STATUS_CONNECTED)
continue;
}
}
void do_TCP_server(TCP_Server *TCP_server)
{
do_TCP_accept_new(TCP_server);
do_TCP_incomming(TCP_server);
}

void kill_TCP_server(TCP_Server *TCP_server)
{
uint32_t i;
Expand Down
8 changes: 5 additions & 3 deletions toxcore/TCP_server.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,11 @@

#include "net_crypto.h"

#define TCP_MAX_BACKLOG 128
#define MAX_INCOMMING_CONNECTIONS 32

#define MAX_PACKET_SIZE 8192
#define TCP_MAX_BACKLOG MAX_INCOMMING_CONNECTIONS

#define MAX_INCOMMING_CONNECTIONS 32
#define MAX_PACKET_SIZE 8192

#define TCP_HANDSHAKE_PLAIN_SIZE (crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES)
#define TCP_SERVER_HANDSHAKE_SIZE (crypto_box_NONCEBYTES + TCP_HANDSHAKE_PLAIN_SIZE + crypto_box_MACBYTES)
Expand Down Expand Up @@ -57,6 +57,8 @@ typedef struct {
uint8_t secret_key[crypto_box_SECRETKEYBYTES];
TCP_Secure_Connection incomming_connection_queue[MAX_INCOMMING_CONNECTIONS];
uint16_t incomming_connection_queue_index;
TCP_Secure_Connection unconfirmed_connection_queue[MAX_INCOMMING_CONNECTIONS];
uint16_t unconfirmed_connection_queue_index;
} TCP_Server;

/* Create new TCP server instance.
Expand Down

0 comments on commit 3acf43b

Please sign in to comment.