summaryrefslogtreecommitdiff
path: root/toxcore
diff options
context:
space:
mode:
Diffstat (limited to 'toxcore')
-rw-r--r--toxcore/Messenger.c2
-rw-r--r--toxcore/TCP_server.c391
-rw-r--r--toxcore/TCP_server.h75
3 files changed, 467 insertions, 1 deletions
diff --git a/toxcore/Messenger.c b/toxcore/Messenger.c
index f4e497d0..9d5fe22a 100644
--- a/toxcore/Messenger.c
+++ b/toxcore/Messenger.c
@@ -2416,7 +2416,7 @@ static int friends_list_load(Messenger *m, uint8_t *data, uint32_t length)
2416 memcpy(address + crypto_box_PUBLICKEYBYTES, &(temp.friendrequest_nospam), sizeof(uint32_t)); 2416 memcpy(address + crypto_box_PUBLICKEYBYTES, &(temp.friendrequest_nospam), sizeof(uint32_t));
2417 uint16_t checksum = address_checksum(address, FRIEND_ADDRESS_SIZE - sizeof(checksum)); 2417 uint16_t checksum = address_checksum(address, FRIEND_ADDRESS_SIZE - sizeof(checksum));
2418 memcpy(address + crypto_box_PUBLICKEYBYTES + sizeof(uint32_t), &checksum, sizeof(checksum)); 2418 memcpy(address + crypto_box_PUBLICKEYBYTES + sizeof(uint32_t), &checksum, sizeof(checksum));
2419 m_addfriend(m, address, temp.info, temp.info_size); 2419 m_addfriend(m, address, temp.info, ntohs(temp.info_size));
2420 } 2420 }
2421 } 2421 }
2422 2422
diff --git a/toxcore/TCP_server.c b/toxcore/TCP_server.c
new file mode 100644
index 00000000..df56f490
--- /dev/null
+++ b/toxcore/TCP_server.c
@@ -0,0 +1,391 @@
1/*
2* TCP_server.c -- Implementation of the TCP relay server part of Tox.
3*
4* Copyright (C) 2013 Tox project All Rights Reserved.
5*
6* This file is part of Tox.
7*
8* Tox is free software: you can redistribute it and/or modify
9* it under the terms of the GNU General Public License as published by
10* the Free Software Foundation, either version 3 of the License, or
11* (at your option) any later version.
12*
13* Tox is distributed in the hope that it will be useful,
14* but WITHOUT ANY WARRANTY; without even the implied warranty of
15* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16* GNU General Public License for more details.
17*
18* You should have received a copy of the GNU General Public License
19* along with Tox. If not, see <http://www.gnu.org/licenses/>.
20*
21*/
22
23#include "TCP_server.h"
24
25#if !defined(_WIN32) && !defined(__WIN32__) && !defined (WIN32)
26#include <sys/ioctl.h>
27#endif
28
29/* return 1 if valid
30 * return 0 if not valid
31 */
32static int sock_valid(sock_t sock)
33{
34#if defined(_WIN32) || defined(__WIN32__) || defined (WIN32)
35
36 if (sock == INVALID_SOCKET) {
37#else
38
39 if (sock < 0) {
40#endif
41 return 0;
42 }
43
44 return 1;
45}
46
47static void kill_sock(sock_t sock)
48{
49#if defined(_WIN32) || defined(__WIN32__) || defined (WIN32)
50 closesocket(sock);
51#else
52 close(sock);
53#endif
54}
55
56/* return 1 on success
57 * return 0 on failure
58 */
59static int set_nonblock(sock_t sock)
60{
61#if defined(_WIN32) || defined(__WIN32__) || defined (WIN32)
62 u_long mode = 1;
63 return (ioctlsocket(sock, FIONBIO, &mode) == 0);
64#else
65 return (fcntl(sock, F_SETFL, O_NONBLOCK, 1) == 0);
66#endif
67}
68
69/* return 1 on success
70 * return 0 on failure
71 */
72static int set_dualstack(sock_t sock)
73{
74 char ipv6only = 0;
75 socklen_t optsize = sizeof(ipv6only);
76 int res = getsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &ipv6only, &optsize);
77
78 if ((res == 0) && (ipv6only == 0))
79 return 1;
80
81 ipv6only = 0;
82 return (setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &ipv6only, sizeof(ipv6only)) == 0);
83}
84
85/* return 1 on success
86 * return 0 on failure
87 */
88static int bind_to_port(sock_t sock, int family, uint16_t port)
89{
90 struct sockaddr_storage addr = {0};
91 size_t addrsize;
92
93 if (family == AF_INET) {
94 struct sockaddr_in *addr4 = (struct sockaddr_in *)&addr;
95
96 addrsize = sizeof(struct sockaddr_in);
97 addr4->sin_family = AF_INET;
98 addr4->sin_port = htons(port);
99 } else if (family == AF_INET6) {
100 struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&addr;
101
102 addrsize = sizeof(struct sockaddr_in6);
103 addr6->sin6_family = AF_INET6;
104 addr6->sin6_port = htons(port);
105 } else {
106 return 0;
107 }
108
109 return (bind(sock, (struct sockaddr *)&addr, addrsize) == 0);
110}
111
112/* return length on success
113 * return 0 if nothing has been read from socket.
114 * return ~0 on failure.
115 */
116static uint16_t read_length(sock_t sock)
117{
118 int count;
119 ioctl(sock, FIONREAD, &count);
120
121 if ((unsigned int)count >= sizeof(uint16_t)) {
122 uint16_t length;
123 int len = recv(sock, &length, sizeof(uint16_t), 0);
124
125 if (len != sizeof(uint16_t)) {
126 fprintf(stderr, "FAIL recv packet\n");
127 return 0;
128 }
129
130 length = ntohs(length);
131
132 if (length > MAX_PACKET_SIZE) {
133 return ~0;
134 }
135
136 return length;
137 }
138
139 return 0;
140}
141
142/* return length on success
143 * return -1 on failure
144 */
145static int read_TCP_packet(sock_t sock, uint8_t *data, uint16_t length)
146{
147 int count;
148 ioctl(sock, FIONREAD, &count);
149
150 if (count >= length) {
151 int len = recv(sock, data, length, 0);
152
153 if (len != length) {
154 fprintf(stderr, "FAIL recv packet\n");
155 return -1;
156 }
157
158 return length;
159 }
160
161 return -1;
162}
163
164/* Kill a TCP_Secure_Connection
165 */
166static void kill_TCP_connection(TCP_Secure_Connection *con)
167{
168 kill_sock(con->sock);
169 memset(con, 0, sizeof(TCP_Secure_Connection));
170}
171
172/* return 1 if everything went well.
173 * return -1 if the connection must be killed.
174 */
175static int handle_TCP_handshake(TCP_Secure_Connection *con, uint8_t *data, uint16_t length, uint8_t *self_secret_key)
176{
177 if (length != TCP_CLIENT_HANDSHAKE_SIZE)
178 return -1;
179
180 if (con->status != TCP_STATUS_CONNECTED)
181 return -1;
182
183 uint8_t shared_key[crypto_box_BEFORENMBYTES];
184 encrypt_precompute(data, self_secret_key, shared_key);
185 uint8_t plain[TCP_HANDSHAKE_PLAIN_SIZE];
186 int len = decrypt_data_fast(shared_key, data + crypto_box_PUBLICKEYBYTES,
187 data + crypto_box_PUBLICKEYBYTES + crypto_box_NONCEBYTES, TCP_HANDSHAKE_PLAIN_SIZE + crypto_box_MACBYTES, plain);
188
189 if (len != TCP_HANDSHAKE_PLAIN_SIZE)
190 return -1;
191
192 uint8_t temp_secret_key[crypto_box_SECRETKEYBYTES];
193 uint8_t resp_plain[TCP_HANDSHAKE_PLAIN_SIZE];
194 crypto_box_keypair(resp_plain, temp_secret_key);
195 random_nonce(con->sent_nonce);
196 memcpy(resp_plain + crypto_box_PUBLICKEYBYTES, con->sent_nonce, crypto_box_NONCEBYTES);
197 memcpy(con->recv_nonce, plain + crypto_box_PUBLICKEYBYTES, crypto_box_NONCEBYTES);
198
199 uint8_t response[TCP_SERVER_HANDSHAKE_SIZE];
200 new_nonce(response);
201
202 len = encrypt_data_fast(shared_key, response, resp_plain, TCP_HANDSHAKE_PLAIN_SIZE, response + crypto_box_NONCEBYTES);
203
204 if (len != TCP_HANDSHAKE_PLAIN_SIZE + crypto_box_MACBYTES)
205 return -1;
206
207 if (TCP_SERVER_HANDSHAKE_SIZE != send(con->sock, response, TCP_SERVER_HANDSHAKE_SIZE, 0))
208 return -1;
209
210 encrypt_precompute(plain, temp_secret_key, con->shared_key);
211 con->status = TCP_STATUS_UNCONFIRMED;
212 return 1;
213}
214
215/* return 1 if connection handshake was handled correctly.
216 * return 0 if we didn't get it yet.
217 * return -1 if the connection must be killed.
218 */
219static int read_connection_handshake(TCP_Secure_Connection *con, uint8_t *self_secret_key)
220{
221 uint8_t data[TCP_CLIENT_HANDSHAKE_SIZE];
222 int len = 0;
223
224 if ((len = read_TCP_packet(con->sock, data, TCP_CLIENT_HANDSHAKE_SIZE)) != -1) {
225 return handle_TCP_handshake(con, data, len, self_secret_key);
226 }
227
228 return 0;
229}
230
231/* return 1 on success
232 * return 0 on failure
233 */
234static int accept_connection(TCP_Server *TCP_server, sock_t sock)
235{
236 if (!sock_valid(sock))
237 return 0;
238
239 if (!set_nonblock(sock)) {
240 kill_sock(sock);
241 return 0;
242 }
243
244 TCP_Secure_Connection *conn =
245 &TCP_server->incomming_connection_queue[TCP_server->incomming_connection_queue_index % MAX_INCOMMING_CONNECTIONS];
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;
255 return 1;
256}
257
258static sock_t new_listening_TCP_socket(int family, uint16_t port)
259{
260 sock_t sock = socket(family, SOCK_STREAM, IPPROTO_TCP);
261
262 if (!sock_valid(sock)) {
263 return ~0;
264 }
265
266 int ok = set_nonblock(sock);
267
268 if (ok && family == AF_INET6) {
269 ok = set_dualstack(sock);
270 }
271
272 ok = ok && bind_to_port(sock, family, port) && (listen(sock, TCP_MAX_BACKLOG) == 0);
273
274 if (!ok) {
275 kill_sock(sock);
276 return ~0;
277 }
278
279 return sock;
280}
281
282TCP_Server *new_TCP_server(uint8_t ipv6_enabled, uint16_t num_sockets, uint16_t *ports, uint8_t *public_key,
283 uint8_t *secret_key)
284{
285 if (num_sockets == 0 || ports == NULL)
286 return NULL;
287
288 TCP_Server *temp = calloc(1, sizeof(TCP_Server));
289
290 if (temp == NULL)
291 return NULL;
292
293 temp->socks_listening = calloc(num_sockets, sizeof(sock_t));
294
295 if (temp->socks_listening == NULL) {
296 free(temp);
297 return NULL;
298 }
299
300 uint8_t family;
301
302 if (ipv6_enabled) {
303 family = AF_INET6;
304 } else {
305 family = AF_INET;
306 }
307
308 uint32_t i;
309
310 for (i = 0; i < num_sockets; ++i) {
311 sock_t sock = new_listening_TCP_socket(family, ports[i]);
312
313 if (sock_valid(sock)) {
314 temp->socks_listening[temp->num_listening_socks] = sock;
315 ++temp->num_listening_socks;
316 }
317 }
318
319 memcpy(temp->public_key, public_key, crypto_box_PUBLICKEYBYTES);
320 memcpy(temp->secret_key, secret_key, crypto_box_SECRETKEYBYTES);
321 return temp;
322}
323
324static void do_TCP_accept_new(TCP_Server *TCP_server)
325{
326 uint32_t i;
327
328 for (i = 0; i < TCP_server->num_listening_socks; ++i) {
329 struct sockaddr_storage addr;
330 unsigned int addrlen = sizeof(addr);
331 sock_t sock;
332
333 do {
334 sock = accept(TCP_server->socks_listening[i], (struct sockaddr *)&addr, &addrlen);
335 } while (accept_connection(TCP_server, sock));
336 }
337}
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
381void kill_TCP_server(TCP_Server *TCP_server)
382{
383 uint32_t i;
384
385 for (i = 0; i < TCP_server->num_listening_socks; ++i) {
386 kill_sock(TCP_server->socks_listening[i]);
387 }
388
389 free(TCP_server->socks_listening);
390 free(TCP_server);
391}
diff --git a/toxcore/TCP_server.h b/toxcore/TCP_server.h
new file mode 100644
index 00000000..89ccb50f
--- /dev/null
+++ b/toxcore/TCP_server.h
@@ -0,0 +1,75 @@
1/*
2* TCP_server.h -- Implementation of the TCP relay server part of Tox.
3*
4* Copyright (C) 2013 Tox project All Rights Reserved.
5*
6* This file is part of Tox.
7*
8* Tox is free software: you can redistribute it and/or modify
9* it under the terms of the GNU General Public License as published by
10* the Free Software Foundation, either version 3 of the License, or
11* (at your option) any later version.
12*
13* Tox is distributed in the hope that it will be useful,
14* but WITHOUT ANY WARRANTY; without even the implied warranty of
15* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16* GNU General Public License for more details.
17*
18* You should have received a copy of the GNU General Public License
19* along with Tox. If not, see <http://www.gnu.org/licenses/>.
20*
21*/
22
23#include "net_crypto.h"
24
25#define MAX_INCOMMING_CONNECTIONS 32
26
27#define TCP_MAX_BACKLOG MAX_INCOMMING_CONNECTIONS
28
29#define MAX_PACKET_SIZE 8192
30
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)
33#define TCP_CLIENT_HANDSHAKE_SIZE (crypto_box_PUBLICKEYBYTES + TCP_SERVER_HANDSHAKE_SIZE)
34
35enum {
36 TCP_STATUS_NO_STATUS,
37 TCP_STATUS_CONNECTED,
38 TCP_STATUS_UNCONFIRMED,
39 TCP_STATUS_CONFIRMED,
40};
41
42typedef struct {
43 uint8_t status;
44 sock_t sock;
45 uint8_t public_key[crypto_box_PUBLICKEYBYTES];
46 uint8_t recv_nonce[crypto_box_NONCEBYTES]; /* Nonce of received packets. */
47 uint8_t sent_nonce[crypto_box_NONCEBYTES]; /* Nonce of sent packets. */
48 uint8_t shared_key[crypto_box_BEFORENMBYTES];
49 uint16_t next_packet_length;
50} TCP_Secure_Connection;
51
52typedef struct {
53 sock_t *socks_listening;
54 unsigned int num_listening_socks;
55
56 uint8_t public_key[crypto_box_PUBLICKEYBYTES];
57 uint8_t secret_key[crypto_box_SECRETKEYBYTES];
58 TCP_Secure_Connection incomming_connection_queue[MAX_INCOMMING_CONNECTIONS];
59 uint16_t incomming_connection_queue_index;
60 TCP_Secure_Connection unconfirmed_connection_queue[MAX_INCOMMING_CONNECTIONS];
61 uint16_t unconfirmed_connection_queue_index;
62} TCP_Server;
63
64/* Create new TCP server instance.
65 */
66TCP_Server *new_TCP_server(uint8_t ipv6_enabled, uint16_t num_sockets, uint16_t *ports, uint8_t *public_key,
67 uint8_t *secret_key);
68
69/* Run the TCP_server
70 */
71void do_TCP_server(TCP_Server *TCP_server);
72
73/* Kill the TCP server
74 */
75void kill_TCP_server(TCP_Server *TCP_server);