summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--auto_tests/TCP_test.c117
-rw-r--r--docs/TCP_Network.txt3
-rw-r--r--docs/TODO2
-rw-r--r--toxcore/TCP_server.c94
-rw-r--r--toxcore/TCP_server.h8
5 files changed, 192 insertions, 32 deletions
diff --git a/auto_tests/TCP_test.c b/auto_tests/TCP_test.c
new file mode 100644
index 00000000..983b07d2
--- /dev/null
+++ b/auto_tests/TCP_test.c
@@ -0,0 +1,117 @@
1#ifdef HAVE_CONFIG_H
2#include "config.h"
3#endif
4
5#include <sys/types.h>
6#include <stdint.h>
7#include <string.h>
8#include <check.h>
9#include <stdlib.h>
10#include <time.h>
11
12#include "../toxcore/TCP_server.h"
13#include "../toxcore/util.h"
14
15#if defined(_WIN32) || defined(__WIN32__) || defined (WIN32)
16#define c_sleep(x) Sleep(1*x)
17#else
18#include <unistd.h>
19#define c_sleep(x) usleep(1000*x)
20#endif
21
22#define NUM_PORTS 3
23
24START_TEST(test_basic)
25{
26 uint16_t ports[NUM_PORTS] = {12345, 33445, 25643};
27 uint8_t self_public_key[crypto_box_PUBLICKEYBYTES];
28 uint8_t self_secret_key[crypto_box_SECRETKEYBYTES];
29 crypto_box_keypair(self_public_key, self_secret_key);
30 TCP_Server *tcp_s = new_TCP_server(1, NUM_PORTS, ports, self_public_key, self_secret_key);
31 ck_assert_msg(tcp_s != NULL, "Failed to create TCP relay server");
32
33 sock_t sock = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP);
34 struct sockaddr_in6 addr6_loopback = {0};
35 addr6_loopback.sin6_family = AF_INET6;
36 addr6_loopback.sin6_port = htons(ports[rand() % NUM_PORTS]);
37 addr6_loopback.sin6_addr = in6addr_loopback;
38
39 int ret = connect(sock, (struct sockaddr *)&addr6_loopback, sizeof(addr6_loopback));
40 ck_assert_msg(ret == 0, "Failed to connect to TCP relay server");
41
42 uint8_t f_public_key[crypto_box_PUBLICKEYBYTES];
43 uint8_t f_secret_key[crypto_box_SECRETKEYBYTES];
44 uint8_t f_nonce[crypto_box_NONCEBYTES];
45 crypto_box_keypair(f_public_key, f_secret_key);
46 random_nonce(f_nonce);
47
48 uint8_t t_secret_key[crypto_box_SECRETKEYBYTES];
49 uint8_t handshake_plain[TCP_HANDSHAKE_PLAIN_SIZE];
50 crypto_box_keypair(handshake_plain, t_secret_key);
51 memcpy(handshake_plain + crypto_box_PUBLICKEYBYTES, f_nonce, crypto_box_NONCEBYTES);
52 uint8_t handshake[TCP_CLIENT_HANDSHAKE_SIZE];
53 memcpy(handshake, f_public_key, crypto_box_PUBLICKEYBYTES);
54 new_nonce(handshake + crypto_box_PUBLICKEYBYTES);
55
56 ret = encrypt_data(self_public_key, f_secret_key, handshake + crypto_box_PUBLICKEYBYTES, handshake_plain,
57 TCP_HANDSHAKE_PLAIN_SIZE, handshake + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES);
58 ck_assert_msg(ret == TCP_CLIENT_HANDSHAKE_SIZE - (crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES),
59 "Encrypt failed.");
60 ck_assert_msg(send(sock, handshake, TCP_CLIENT_HANDSHAKE_SIZE - 1, 0) == TCP_CLIENT_HANDSHAKE_SIZE - 1, "send Failed.");
61 c_sleep(50);
62 do_TCP_server(tcp_s);
63 c_sleep(50);
64 do_TCP_server(tcp_s);
65 c_sleep(50);
66 ck_assert_msg(send(sock, handshake + (TCP_CLIENT_HANDSHAKE_SIZE - 1), 1, 0) == 1, "send Failed.");
67 c_sleep(50);
68 do_TCP_server(tcp_s);
69 c_sleep(50);
70 do_TCP_server(tcp_s);
71 c_sleep(50);
72 uint8_t response[TCP_SERVER_HANDSHAKE_SIZE];
73 uint8_t response_plain[TCP_HANDSHAKE_PLAIN_SIZE];
74 ck_assert_msg(recv(sock, response, TCP_SERVER_HANDSHAKE_SIZE, 0) == TCP_SERVER_HANDSHAKE_SIZE, "recv Failed.");
75 ret = decrypt_data(self_public_key, f_secret_key, response, response + crypto_box_NONCEBYTES,
76 TCP_SERVER_HANDSHAKE_SIZE - crypto_box_NONCEBYTES, response_plain);
77 ck_assert_msg(ret == TCP_HANDSHAKE_PLAIN_SIZE, "Decrypt Failed.");
78 uint8_t f_nonce_r[crypto_box_NONCEBYTES];
79 uint8_t f_shared_key[crypto_box_BEFORENMBYTES];
80 encrypt_precompute(response_plain, t_secret_key, f_shared_key);
81 memcpy(f_nonce_r, response_plain + crypto_box_BEFORENMBYTES, crypto_box_NONCEBYTES);
82
83
84}
85END_TEST
86
87#define DEFTESTCASE(NAME) \
88 TCase *tc_##NAME = tcase_create(#NAME); \
89 tcase_add_test(tc_##NAME, test_##NAME); \
90 suite_add_tcase(s, tc_##NAME);
91
92#define DEFTESTCASE_SLOW(NAME, TIMEOUT) \
93 DEFTESTCASE(NAME) \
94 tcase_set_timeout(tc_##NAME, TIMEOUT);
95Suite *TCP_suite(void)
96{
97 Suite *s = suite_create("TCP");
98
99 DEFTESTCASE_SLOW(basic, 5);
100 return s;
101}
102
103int main(int argc, char *argv[])
104{
105 srand((unsigned int) time(NULL));
106
107 Suite *TCP = TCP_suite();
108 SRunner *test_runner = srunner_create(TCP);
109
110 int number_failed = 0;
111 srunner_run_all(test_runner, CK_NORMAL);
112 number_failed = srunner_ntests_failed(test_runner);
113
114 srunner_free(test_runner);
115
116 return number_failed;
117}
diff --git a/docs/TCP_Network.txt b/docs/TCP_Network.txt
index ce52b8e9..80cdfbdb 100644
--- a/docs/TCP_Network.txt
+++ b/docs/TCP_Network.txt
@@ -58,6 +58,9 @@ So if you would inspect the TCP stream you would see:
58[[uint16_t (length of data)][data]][[uint16_t (length of 58[[uint16_t (length of data)][data]][[uint16_t (length of
59data)][data]][[uint16_t (length of data)][data]] 59data)][data]][[uint16_t (length of data)][data]]
60 60
61Note that both handshake packets don't have this format (the length for them is
62always the same so we don't need to specify it.)
63
61When the client connects to the server, he sends this packet: 64When the client connects to the server, he sends this packet:
62[public key of client (32 bytes)][nonce for the encrypted data [24 65[public key of client (32 bytes)][nonce for the encrypted data [24
63bytes]][encrypted with the private key of the client and public key of the 66bytes]][encrypted with the private key of the client and public key of the
diff --git a/docs/TODO b/docs/TODO
index 6c0197db..f7ef8ade 100644
--- a/docs/TODO
+++ b/docs/TODO
@@ -41,7 +41,7 @@ Friend_requests.c:
41 41
42[NOT STARTED] Make the core save/datafile portable across client versions/different processor architectures. 42[NOT STARTED] Make the core save/datafile portable across client versions/different processor architectures.
43 43
44[NOT STARTED] A way for people to connect to people on Tox if they are behind a bad NAT that 44[IN PROGRESS] A way for people to connect to people on Tox if they are behind a bad NAT that
45blocks UDP (or is just unpunchable) (docs/TCP_Network.txt) 45blocks UDP (or is just unpunchable) (docs/TCP_Network.txt)
46 46
47[NEEDS TESTING] Make the save made with tox_save_encrypted(...) harder to brute force. 47[NEEDS TESTING] Make the save made with tox_save_encrypted(...) harder to brute force.
diff --git a/toxcore/TCP_server.c b/toxcore/TCP_server.c
index 602d0000..df56f490 100644
--- a/toxcore/TCP_server.c
+++ b/toxcore/TCP_server.c
@@ -118,7 +118,7 @@ static uint16_t read_length(sock_t sock)
118 int count; 118 int count;
119 ioctl(sock, FIONREAD, &count); 119 ioctl(sock, FIONREAD, &count);
120 120
121 if (count >= sizeof(uint16_t)) { 121 if ((unsigned int)count >= sizeof(uint16_t)) {
122 uint16_t length; 122 uint16_t length;
123 int len = recv(sock, &length, sizeof(uint16_t), 0); 123 int len = recv(sock, &length, sizeof(uint16_t), 0);
124 124
@@ -169,7 +169,7 @@ static void kill_TCP_connection(TCP_Secure_Connection *con)
169 memset(con, 0, sizeof(TCP_Secure_Connection)); 169 memset(con, 0, sizeof(TCP_Secure_Connection));
170} 170}
171 171
172/* return 0 if everything went well. 172/* return 1 if everything went well.
173 * return -1 if the connection must be killed. 173 * return -1 if the connection must be killed.
174 */ 174 */
175static int handle_TCP_handshake(TCP_Secure_Connection *con, uint8_t *data, uint16_t length, uint8_t *self_secret_key) 175static 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
209 209
210 encrypt_precompute(plain, temp_secret_key, con->shared_key); 210 encrypt_precompute(plain, temp_secret_key, con->shared_key);
211 con->status = TCP_STATUS_UNCONFIRMED; 211 con->status = TCP_STATUS_UNCONFIRMED;
212 return 0; 212 return 1;
213} 213}
214 214
215/* return 0 if everything went well. 215/* return 1 if connection handshake was handled correctly.
216 * return 0 if we didn't get it yet.
216 * return -1 if the connection must be killed. 217 * return -1 if the connection must be killed.
217 */ 218 */
218static int read_connection_handshake(TCP_Secure_Connection *con, uint8_t *self_secret_key) 219static int read_connection_handshake(TCP_Secure_Connection *con, uint8_t *self_secret_key)
219{ 220{
220 while (1) { 221 uint8_t data[TCP_CLIENT_HANDSHAKE_SIZE];
221 if (con->next_packet_length == 0) { 222 int len = 0;
222 uint16_t len = read_length(con->sock);
223
224 if (len == 0)
225 break;
226
227 if (len != TCP_CLIENT_HANDSHAKE_SIZE)
228 return -1;
229 223
230 con->next_packet_length = len; 224 if ((len = read_TCP_packet(con->sock, data, TCP_CLIENT_HANDSHAKE_SIZE)) != -1) {
231 } else { 225 return handle_TCP_handshake(con, data, len, self_secret_key);
232 uint8_t data[con->next_packet_length];
233
234 if (read_TCP_packet(con->sock, data, con->next_packet_length) != -1) {
235 return handle_TCP_handshake(con, data, con->next_packet_length, self_secret_key);
236 } else {
237 break;
238 }
239 }
240 } 226 }
227
228 return 0;
241} 229}
242 230
243/* return 1 on success 231/* return 1 on success
@@ -253,8 +241,17 @@ static int accept_connection(TCP_Server *TCP_server, sock_t sock)
253 return 0; 241 return 0;
254 } 242 }
255 243
256 printf("accepted %u\n", sock); 244 TCP_Secure_Connection *conn =
245 &TCP_server->incomming_connection_queue[TCP_server->incomming_connection_queue_index % MAX_INCOMMING_CONNECTIONS];
257 246
247 if (conn->status != TCP_STATUS_NO_STATUS)
248 kill_TCP_connection(conn);
249
250 conn->status = TCP_STATUS_CONNECTED;
251 conn->sock = sock;
252 conn->next_packet_length = 0;
253
254 ++TCP_server->incomming_connection_queue_index;
258 return 1; 255 return 1;
259} 256}
260 257
@@ -288,7 +285,7 @@ TCP_Server *new_TCP_server(uint8_t ipv6_enabled, uint16_t num_sockets, uint16_t
288 if (num_sockets == 0 || ports == NULL) 285 if (num_sockets == 0 || ports == NULL)
289 return NULL; 286 return NULL;
290 287
291 TCP_Server *temp = calloc(1, sizeof(Networking_Core)); 288 TCP_Server *temp = calloc(1, sizeof(TCP_Server));
292 289
293 if (temp == NULL) 290 if (temp == NULL)
294 return NULL; 291 return NULL;
@@ -324,22 +321,63 @@ TCP_Server *new_TCP_server(uint8_t ipv6_enabled, uint16_t num_sockets, uint16_t
324 return temp; 321 return temp;
325} 322}
326 323
327void do_TCP_server(TCP_Server *TCP_server) 324static void do_TCP_accept_new(TCP_Server *TCP_server)
328{ 325{
329 uint32_t i; 326 uint32_t i;
330 327
331 for (i = 0; i < TCP_server->num_listening_socks; ++i) { 328 for (i = 0; i < TCP_server->num_listening_socks; ++i) {
332 struct sockaddr_storage addr; 329 struct sockaddr_storage addr;
333 int addrlen = sizeof(addr); 330 unsigned int addrlen = sizeof(addr);
334 sock_t sock; 331 sock_t sock;
335 332
336 do { 333 do {
337 sock = accept(TCP_server->socks_listening[i], (struct sockaddr *)&addr, &addrlen); 334 sock = accept(TCP_server->socks_listening[i], (struct sockaddr *)&addr, &addrlen);
338 //TODO
339 } while (accept_connection(TCP_server, sock)); 335 } while (accept_connection(TCP_server, sock));
340 } 336 }
341} 337}
342 338
339static void do_TCP_incomming(TCP_Server *TCP_server)
340{
341 uint32_t i;
342
343 for (i = 0; i < MAX_INCOMMING_CONNECTIONS; ++i) {
344 if (TCP_server->incomming_connection_queue[i].status != TCP_STATUS_CONNECTED)
345 continue;
346
347 int ret = read_connection_handshake(&TCP_server->incomming_connection_queue[i], TCP_server->secret_key);
348
349 if (ret == -1) {
350 kill_TCP_connection(&TCP_server->incomming_connection_queue[i]);
351 } else if (ret == 1) {
352 TCP_Secure_Connection *conn_old = &TCP_server->incomming_connection_queue[i];
353 TCP_Secure_Connection *conn_new =
354 &TCP_server->unconfirmed_connection_queue[TCP_server->unconfirmed_connection_queue_index % MAX_INCOMMING_CONNECTIONS];
355
356 if (conn_new->status != TCP_STATUS_NO_STATUS)
357 kill_TCP_connection(conn_new);
358
359 memcpy(conn_new, conn_old, sizeof(TCP_Secure_Connection));
360 memset(conn_old, 0, sizeof(TCP_Secure_Connection));
361 ++TCP_server->unconfirmed_connection_queue_index;
362 }
363 }
364}
365
366static void do_TCP_unconfirmed(TCP_Server *TCP_server)
367{
368 uint32_t i;
369
370 for (i = 0; i < MAX_INCOMMING_CONNECTIONS; ++i) {
371 if (TCP_server->incomming_connection_queue[i].status != TCP_STATUS_CONNECTED)
372 continue;
373 }
374}
375void do_TCP_server(TCP_Server *TCP_server)
376{
377 do_TCP_accept_new(TCP_server);
378 do_TCP_incomming(TCP_server);
379}
380
343void kill_TCP_server(TCP_Server *TCP_server) 381void kill_TCP_server(TCP_Server *TCP_server)
344{ 382{
345 uint32_t i; 383 uint32_t i;
diff --git a/toxcore/TCP_server.h b/toxcore/TCP_server.h
index 573108af..89ccb50f 100644
--- a/toxcore/TCP_server.h
+++ b/toxcore/TCP_server.h
@@ -22,11 +22,11 @@
22 22
23#include "net_crypto.h" 23#include "net_crypto.h"
24 24
25#define TCP_MAX_BACKLOG 128 25#define MAX_INCOMMING_CONNECTIONS 32
26 26
27#define MAX_PACKET_SIZE 8192 27#define TCP_MAX_BACKLOG MAX_INCOMMING_CONNECTIONS
28 28
29#define MAX_INCOMMING_CONNECTIONS 32 29#define MAX_PACKET_SIZE 8192
30 30
31#define TCP_HANDSHAKE_PLAIN_SIZE (crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES) 31#define TCP_HANDSHAKE_PLAIN_SIZE (crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES)
32#define TCP_SERVER_HANDSHAKE_SIZE (crypto_box_NONCEBYTES + TCP_HANDSHAKE_PLAIN_SIZE + crypto_box_MACBYTES) 32#define TCP_SERVER_HANDSHAKE_SIZE (crypto_box_NONCEBYTES + TCP_HANDSHAKE_PLAIN_SIZE + crypto_box_MACBYTES)
@@ -57,6 +57,8 @@ typedef struct {
57 uint8_t secret_key[crypto_box_SECRETKEYBYTES]; 57 uint8_t secret_key[crypto_box_SECRETKEYBYTES];
58 TCP_Secure_Connection incomming_connection_queue[MAX_INCOMMING_CONNECTIONS]; 58 TCP_Secure_Connection incomming_connection_queue[MAX_INCOMMING_CONNECTIONS];
59 uint16_t incomming_connection_queue_index; 59 uint16_t incomming_connection_queue_index;
60 TCP_Secure_Connection unconfirmed_connection_queue[MAX_INCOMMING_CONNECTIONS];
61 uint16_t unconfirmed_connection_queue_index;
60} TCP_Server; 62} TCP_Server;
61 63
62/* Create new TCP server instance. 64/* Create new TCP server instance.