mirror of
https://github.com/irungentoo/toxcore.git
synced 2024-03-22 13:30:51 +08:00
A bit of work done on the TCP relay server.
This commit is contained in:
parent
29afa26396
commit
3acf43b76a
117
auto_tests/TCP_test.c
Normal file
117
auto_tests/TCP_test.c
Normal 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;
|
||||||
|
}
|
|
@ -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
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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.
|
||||||
|
|
Loading…
Reference in New Issue
Block a user