A bit of work done on the TCP relay server.

This commit is contained in:
irungentoo 2014-03-14 14:12:35 -04:00
parent 29afa26396
commit 3acf43b76a
5 changed files with 192 additions and 32 deletions

117
auto_tests/TCP_test.c Normal file
View File

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

View File

@ -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 [[uint16_t (length of data)][data]][[uint16_t (length of
data)][data]][[uint16_t (length of data)][data]] 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: When the client connects to the server, he sends this packet:
[public key of client (32 bytes)][nonce for the encrypted data [24 [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 bytes]][encrypted with the private key of the client and public key of the

View File

@ -41,7 +41,7 @@ Friend_requests.c:
[NOT STARTED] Make the core save/datafile portable across client versions/different processor architectures. [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) blocks UDP (or is just unpunchable) (docs/TCP_Network.txt)
[NEEDS TESTING] Make the save made with tox_save_encrypted(...) harder to brute force. [NEEDS TESTING] Make the save made with tox_save_encrypted(...) harder to brute force.

View File

@ -118,7 +118,7 @@ static uint16_t read_length(sock_t sock)
int count; int count;
ioctl(sock, FIONREAD, &count); ioctl(sock, FIONREAD, &count);
if (count >= sizeof(uint16_t)) { if ((unsigned int)count >= sizeof(uint16_t)) {
uint16_t length; uint16_t length;
int len = recv(sock, &length, sizeof(uint16_t), 0); int len = recv(sock, &length, sizeof(uint16_t), 0);
@ -169,7 +169,7 @@ static void kill_TCP_connection(TCP_Secure_Connection *con)
memset(con, 0, sizeof(TCP_Secure_Connection)); 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. * 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) static int handle_TCP_handshake(TCP_Secure_Connection *con, uint8_t *data, uint16_t length, uint8_t *self_secret_key)
@ -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); encrypt_precompute(plain, temp_secret_key, con->shared_key);
con->status = TCP_STATUS_UNCONFIRMED; 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. * return -1 if the connection must be killed.
*/ */
static int read_connection_handshake(TCP_Secure_Connection *con, uint8_t *self_secret_key) static int read_connection_handshake(TCP_Secure_Connection *con, uint8_t *self_secret_key)
{ {
while (1) { uint8_t data[TCP_CLIENT_HANDSHAKE_SIZE];
if (con->next_packet_length == 0) { int len = 0;
uint16_t len = read_length(con->sock);
if (len == 0) if ((len = read_TCP_packet(con->sock, data, TCP_CLIENT_HANDSHAKE_SIZE)) != -1) {
break; return handle_TCP_handshake(con, data, len, self_secret_key);
if (len != TCP_CLIENT_HANDSHAKE_SIZE)
return -1;
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;
}
}
} }
return 0;
} }
/* return 1 on success /* return 1 on success
@ -253,8 +241,17 @@ static int accept_connection(TCP_Server *TCP_server, sock_t sock)
return 0; 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; return 1;
} }
@ -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) if (num_sockets == 0 || ports == NULL)
return NULL; return NULL;
TCP_Server *temp = calloc(1, sizeof(Networking_Core)); TCP_Server *temp = calloc(1, sizeof(TCP_Server));
if (temp == NULL) if (temp == NULL)
return NULL; return NULL;
@ -324,22 +321,63 @@ TCP_Server *new_TCP_server(uint8_t ipv6_enabled, uint16_t num_sockets, uint16_t
return temp; return temp;
} }
void do_TCP_server(TCP_Server *TCP_server) static void do_TCP_accept_new(TCP_Server *TCP_server)
{ {
uint32_t i; uint32_t i;
for (i = 0; i < TCP_server->num_listening_socks; ++i) { for (i = 0; i < TCP_server->num_listening_socks; ++i) {
struct sockaddr_storage addr; struct sockaddr_storage addr;
int addrlen = sizeof(addr); unsigned int addrlen = sizeof(addr);
sock_t sock; sock_t sock;
do { do {
sock = accept(TCP_server->socks_listening[i], (struct sockaddr *)&addr, &addrlen); sock = accept(TCP_server->socks_listening[i], (struct sockaddr *)&addr, &addrlen);
//TODO
} while (accept_connection(TCP_server, sock)); } 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) void kill_TCP_server(TCP_Server *TCP_server)
{ {
uint32_t i; uint32_t i;

View File

@ -22,12 +22,12 @@
#include "net_crypto.h" #include "net_crypto.h"
#define TCP_MAX_BACKLOG 128 #define MAX_INCOMMING_CONNECTIONS 32
#define TCP_MAX_BACKLOG MAX_INCOMMING_CONNECTIONS
#define MAX_PACKET_SIZE 8192 #define MAX_PACKET_SIZE 8192
#define MAX_INCOMMING_CONNECTIONS 32
#define TCP_HANDSHAKE_PLAIN_SIZE (crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES) #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) #define TCP_SERVER_HANDSHAKE_SIZE (crypto_box_NONCEBYTES + TCP_HANDSHAKE_PLAIN_SIZE + crypto_box_MACBYTES)
#define TCP_CLIENT_HANDSHAKE_SIZE (crypto_box_PUBLICKEYBYTES + TCP_SERVER_HANDSHAKE_SIZE) #define TCP_CLIENT_HANDSHAKE_SIZE (crypto_box_PUBLICKEYBYTES + TCP_SERVER_HANDSHAKE_SIZE)
@ -57,6 +57,8 @@ typedef struct {
uint8_t secret_key[crypto_box_SECRETKEYBYTES]; uint8_t secret_key[crypto_box_SECRETKEYBYTES];
TCP_Secure_Connection incomming_connection_queue[MAX_INCOMMING_CONNECTIONS]; TCP_Secure_Connection incomming_connection_queue[MAX_INCOMMING_CONNECTIONS];
uint16_t incomming_connection_queue_index; uint16_t incomming_connection_queue_index;
TCP_Secure_Connection unconfirmed_connection_queue[MAX_INCOMMING_CONNECTIONS];
uint16_t unconfirmed_connection_queue_index;
} TCP_Server; } TCP_Server;
/* Create new TCP server instance. /* Create new TCP server instance.