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
|
||||
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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
uint8_t data[TCP_CLIENT_HANDSHAKE_SIZE];
|
||||
int len = 0;
|
||||
|
||||
if (len == 0)
|
||||
break;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
|
|
@ -22,12 +22,12 @@
|
|||
|
||||
#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_INCOMMING_CONNECTIONS 32
|
||||
|
||||
#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_CLIENT_HANDSHAKE_SIZE (crypto_box_PUBLICKEYBYTES + TCP_SERVER_HANDSHAKE_SIZE)
|
||||
|
@ -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.
|
||||
|
|
Loading…
Reference in New Issue
Block a user