/work/toxcore/TCP_server.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* SPDX-License-Identifier: GPL-3.0-or-later |
2 | | * Copyright © 2016-2018 The TokTok team. |
3 | | * Copyright © 2014 Tox project. |
4 | | */ |
5 | | |
6 | | /** |
7 | | * Implementation of the TCP relay server part of Tox. |
8 | | */ |
9 | | #include "TCP_server.h" |
10 | | |
11 | | #include <string.h> |
12 | | #if !defined(_WIN32) && !defined(__WIN32__) && !defined (WIN32) |
13 | | #include <sys/ioctl.h> |
14 | | #endif /* !WIN32 */ |
15 | | |
16 | | #ifdef TCP_SERVER_USE_EPOLL |
17 | | #include <sys/epoll.h> |
18 | | #include <unistd.h> |
19 | | #endif /* TCP_SERVER_USE_EPOLL */ |
20 | | |
21 | | #include "DHT.h" |
22 | | #include "TCP_common.h" |
23 | | #include "ccompat.h" |
24 | | #include "crypto_core.h" |
25 | | #include "forwarding.h" |
26 | | #include "list.h" |
27 | | #include "logger.h" |
28 | | #include "mem.h" |
29 | | #include "mono_time.h" |
30 | | #include "network.h" |
31 | | #include "onion.h" |
32 | | |
33 | | #ifdef TCP_SERVER_USE_EPOLL |
34 | | #define TCP_SOCKET_LISTENING 0 |
35 | | #define TCP_SOCKET_INCOMING 1 |
36 | | #define TCP_SOCKET_UNCONFIRMED 2 |
37 | | #define TCP_SOCKET_CONFIRMED 3 |
38 | | #endif /* TCP_SERVER_USE_EPOLL */ |
39 | | |
40 | | typedef struct TCP_Secure_Conn { |
41 | | uint8_t public_key[CRYPTO_PUBLIC_KEY_SIZE]; |
42 | | uint32_t index; |
43 | | // TODO(iphydf): Add an enum for this (same as in TCP_client.c, probably). |
44 | | uint8_t status; /* 0 if not used, 1 if other is offline, 2 if other is online. */ |
45 | | uint8_t other_id; |
46 | | } TCP_Secure_Conn; |
47 | | |
48 | | typedef struct TCP_Secure_Connection { |
49 | | TCP_Connection con; |
50 | | |
51 | | uint8_t public_key[CRYPTO_PUBLIC_KEY_SIZE]; |
52 | | uint8_t recv_nonce[CRYPTO_NONCE_SIZE]; /* Nonce of received packets. */ |
53 | | uint16_t next_packet_length; |
54 | | TCP_Secure_Conn connections[NUM_CLIENT_CONNECTIONS]; |
55 | | uint8_t status; |
56 | | |
57 | | uint64_t identifier; |
58 | | |
59 | | uint64_t last_pinged; |
60 | | uint64_t ping_id; |
61 | | } TCP_Secure_Connection; |
62 | | |
63 | | static const TCP_Secure_Connection empty_tcp_secure_connection = {{nullptr}}; |
64 | | |
65 | | |
66 | | struct TCP_Server { |
67 | | const Logger *logger; |
68 | | const Memory *mem; |
69 | | const Random *rng; |
70 | | const Network *ns; |
71 | | Onion *onion; |
72 | | Forwarding *forwarding; |
73 | | |
74 | | #ifdef TCP_SERVER_USE_EPOLL |
75 | | int efd; |
76 | | uint64_t last_run_pinged; |
77 | | #endif /* TCP_SERVER_USE_EPOLL */ |
78 | | Socket *socks_listening; |
79 | | unsigned int num_listening_socks; |
80 | | |
81 | | uint8_t public_key[CRYPTO_PUBLIC_KEY_SIZE]; |
82 | | uint8_t secret_key[CRYPTO_SECRET_KEY_SIZE]; |
83 | | TCP_Secure_Connection incoming_connection_queue[MAX_INCOMING_CONNECTIONS]; |
84 | | uint16_t incoming_connection_queue_index; |
85 | | TCP_Secure_Connection unconfirmed_connection_queue[MAX_INCOMING_CONNECTIONS]; |
86 | | uint16_t unconfirmed_connection_queue_index; |
87 | | |
88 | | TCP_Secure_Connection *accepted_connection_array; |
89 | | uint32_t size_accepted_connections; |
90 | | uint32_t num_accepted_connections; |
91 | | |
92 | | uint64_t counter; |
93 | | |
94 | | BS_List accepted_key_list; |
95 | | }; |
96 | | |
97 | | static_assert(sizeof(TCP_Server) < 7 * 1024 * 1024, |
98 | | "TCP_Server struct should not grow more; it's already 6MB"); |
99 | | |
100 | | const uint8_t *tcp_server_public_key(const TCP_Server *tcp_server) |
101 | 26 | { |
102 | 26 | return tcp_server->public_key; |
103 | 26 | } |
104 | | |
105 | | size_t tcp_server_listen_count(const TCP_Server *tcp_server) |
106 | 3 | { |
107 | 3 | return tcp_server->num_listening_socks; |
108 | 3 | } |
109 | | |
110 | | /** This is needed to compile on Android below API 21 */ |
111 | | #ifdef TCP_SERVER_USE_EPOLL |
112 | | #ifndef EPOLLRDHUP |
113 | | #define EPOLLRDHUP 0x2000 |
114 | | #endif /* EPOLLRDHUP */ |
115 | | #endif /* TCP_SERVER_USE_EPOLL */ |
116 | | |
117 | | /** @brief Increase the size of the connection list |
118 | | * |
119 | | * @retval -1 on failure |
120 | | * @retval 0 on success. |
121 | | */ |
122 | | non_null() |
123 | | static int alloc_new_connections(TCP_Server *tcp_server, uint32_t num) |
124 | 21 | { |
125 | 21 | const uint32_t new_size = tcp_server->size_accepted_connections + num; |
126 | | |
127 | 21 | if (new_size < tcp_server->size_accepted_connections) { |
128 | 0 | return -1; |
129 | 0 | } |
130 | | |
131 | 21 | TCP_Secure_Connection *new_connections = (TCP_Secure_Connection *)mem_vrealloc( |
132 | 21 | tcp_server->mem, tcp_server->accepted_connection_array, |
133 | 21 | new_size, sizeof(TCP_Secure_Connection)); |
134 | | |
135 | 21 | if (new_connections == nullptr) { |
136 | 0 | return -1; |
137 | 0 | } |
138 | | |
139 | 21 | const uint32_t old_size = tcp_server->size_accepted_connections; |
140 | 105 | for (uint32_t i = 0; i < num; ++i) { |
141 | 84 | new_connections[old_size + i] = empty_tcp_secure_connection; |
142 | 84 | } |
143 | | |
144 | 21 | tcp_server->accepted_connection_array = new_connections; |
145 | 21 | tcp_server->size_accepted_connections = new_size; |
146 | 21 | return 0; |
147 | 21 | } |
148 | | |
149 | | non_null() |
150 | | static void wipe_secure_connection(TCP_Secure_Connection *con) |
151 | 13.2k | { |
152 | 13.2k | if (con->status != 0) { |
153 | 2.88k | wipe_priority_list(con->con.mem, con->con.priority_queue_start); |
154 | 2.88k | crypto_memzero(con, sizeof(TCP_Secure_Connection)); |
155 | 2.88k | } |
156 | 13.2k | } |
157 | | |
158 | | non_null() |
159 | | static void move_secure_connection(TCP_Secure_Connection *con_new, TCP_Secure_Connection *con_old) |
160 | 220 | { |
161 | 220 | *con_new = *con_old; |
162 | 220 | crypto_memzero(con_old, sizeof(TCP_Secure_Connection)); |
163 | 220 | } |
164 | | |
165 | | non_null() |
166 | | static void free_accepted_connection_array(TCP_Server *tcp_server) |
167 | 26 | { |
168 | 26 | if (tcp_server->accepted_connection_array == nullptr) { |
169 | 16 | return; |
170 | 16 | } |
171 | | |
172 | 94 | for (uint32_t i = 0; i < tcp_server->size_accepted_connections; ++i) { |
173 | 84 | wipe_secure_connection(&tcp_server->accepted_connection_array[i]); |
174 | 84 | } |
175 | | |
176 | 10 | mem_delete(tcp_server->mem, tcp_server->accepted_connection_array); |
177 | 10 | tcp_server->accepted_connection_array = nullptr; |
178 | 10 | tcp_server->size_accepted_connections = 0; |
179 | 10 | } |
180 | | |
181 | | /** |
182 | | * @return index corresponding to connection with peer on success |
183 | | * @retval -1 on failure. |
184 | | */ |
185 | | non_null() |
186 | | static int get_tcp_connection_index(const TCP_Server *tcp_server, const uint8_t *public_key) |
187 | 349 | { |
188 | 349 | return bs_list_find(&tcp_server->accepted_key_list, public_key); |
189 | 349 | } |
190 | | |
191 | | |
192 | | non_null() |
193 | | static int kill_accepted(TCP_Server *tcp_server, int index); |
194 | | |
195 | | /** @brief Add accepted TCP connection to the list. |
196 | | * |
197 | | * @return index on success |
198 | | * @retval -1 on failure |
199 | | */ |
200 | | non_null() |
201 | | static int add_accepted(TCP_Server *tcp_server, const Mono_Time *mono_time, TCP_Secure_Connection *con) |
202 | 65 | { |
203 | 65 | int index = get_tcp_connection_index(tcp_server, con->public_key); |
204 | | |
205 | 65 | if (index != -1) { /* If an old connection to the same public key exists, kill it. */ |
206 | 0 | kill_accepted(tcp_server, index); |
207 | 0 | index = -1; |
208 | 0 | } |
209 | | |
210 | 65 | if (tcp_server->size_accepted_connections == tcp_server->num_accepted_connections) { |
211 | 21 | if (alloc_new_connections(tcp_server, 4) == -1) { |
212 | 0 | return -1; |
213 | 0 | } |
214 | | |
215 | 21 | index = tcp_server->num_accepted_connections; |
216 | 44 | } else { |
217 | 81 | for (uint32_t i = tcp_server->size_accepted_connections; i != 0; --i) { |
218 | 81 | if (tcp_server->accepted_connection_array[i - 1].status == TCP_STATUS_NO_STATUS) { |
219 | 44 | index = i - 1; |
220 | 44 | break; |
221 | 44 | } |
222 | 81 | } |
223 | 44 | } |
224 | | |
225 | 65 | if (index == -1) { |
226 | 0 | LOGGER_ERROR(tcp_server->logger, "FAIL index is -1"); |
227 | 0 | return -1; |
228 | 0 | } |
229 | | |
230 | 65 | if (!bs_list_add(&tcp_server->accepted_key_list, con->public_key, index)) { |
231 | 0 | return -1; |
232 | 0 | } |
233 | | |
234 | 65 | move_secure_connection(&tcp_server->accepted_connection_array[index], con); |
235 | | |
236 | 65 | tcp_server->accepted_connection_array[index].status = TCP_STATUS_CONFIRMED; |
237 | 65 | ++tcp_server->num_accepted_connections; |
238 | 65 | tcp_server->accepted_connection_array[index].identifier = ++tcp_server->counter; |
239 | 65 | tcp_server->accepted_connection_array[index].last_pinged = mono_time_get(mono_time); |
240 | 65 | tcp_server->accepted_connection_array[index].ping_id = 0; |
241 | | |
242 | 65 | return index; |
243 | 65 | } |
244 | | |
245 | | /** @brief Delete accepted connection from list. |
246 | | * |
247 | | * @retval 0 on success |
248 | | * @retval -1 on failure |
249 | | */ |
250 | | non_null() |
251 | | static int del_accepted(TCP_Server *tcp_server, int index) |
252 | 4 | { |
253 | 4 | if ((uint32_t)index >= tcp_server->size_accepted_connections) { |
254 | 0 | return -1; |
255 | 0 | } |
256 | | |
257 | 4 | if (tcp_server->accepted_connection_array[index].status == TCP_STATUS_NO_STATUS) { |
258 | 0 | return -1; |
259 | 0 | } |
260 | | |
261 | 4 | if (!bs_list_remove(&tcp_server->accepted_key_list, tcp_server->accepted_connection_array[index].public_key, index)) { |
262 | 0 | return -1; |
263 | 0 | } |
264 | | |
265 | 4 | wipe_secure_connection(&tcp_server->accepted_connection_array[index]); |
266 | 4 | --tcp_server->num_accepted_connections; |
267 | | |
268 | 4 | if (tcp_server->num_accepted_connections == 0) { |
269 | 1 | free_accepted_connection_array(tcp_server); |
270 | 1 | } |
271 | | |
272 | 4 | return 0; |
273 | 4 | } |
274 | | |
275 | | /** Kill a TCP_Secure_Connection */ |
276 | | non_null() |
277 | | static void kill_tcp_secure_connection(TCP_Secure_Connection *con) |
278 | 250 | { |
279 | 250 | kill_sock(con->con.ns, con->con.sock); |
280 | 250 | wipe_secure_connection(con); |
281 | 250 | } |
282 | | |
283 | | non_null() |
284 | | static int rm_connection_index(TCP_Server *tcp_server, TCP_Secure_Connection *con, uint8_t con_number); |
285 | | |
286 | | /** @brief Kill an accepted TCP_Secure_Connection |
287 | | * |
288 | | * return -1 on failure. |
289 | | * return 0 on success. |
290 | | */ |
291 | | static int kill_accepted(TCP_Server *tcp_server, int index) |
292 | 4 | { |
293 | 4 | if ((uint32_t)index >= tcp_server->size_accepted_connections) { |
294 | 0 | return -1; |
295 | 0 | } |
296 | | |
297 | 964 | for (uint32_t i = 0; i < NUM_CLIENT_CONNECTIONS; ++i) { |
298 | 960 | rm_connection_index(tcp_server, &tcp_server->accepted_connection_array[index], i); |
299 | 960 | } |
300 | | |
301 | 4 | const Socket sock = tcp_server->accepted_connection_array[index].con.sock; |
302 | | |
303 | 4 | if (del_accepted(tcp_server, index) != 0) { |
304 | 0 | return -1; |
305 | 0 | } |
306 | | |
307 | 4 | kill_sock(tcp_server->ns, sock); |
308 | 4 | return 0; |
309 | 4 | } |
310 | | |
311 | | /** |
312 | | * @retval 1 if everything went well. |
313 | | * @retval -1 if the connection must be killed. |
314 | | */ |
315 | | non_null() |
316 | | static int handle_tcp_handshake(const Logger *logger, TCP_Secure_Connection *con, const uint8_t *data, uint16_t length, |
317 | | const uint8_t *self_secret_key) |
318 | 155 | { |
319 | 155 | if (length != TCP_CLIENT_HANDSHAKE_SIZE) { |
320 | 0 | LOGGER_ERROR(logger, "invalid handshake length: %d != %d", length, TCP_CLIENT_HANDSHAKE_SIZE); |
321 | 0 | return -1; |
322 | 0 | } |
323 | | |
324 | 155 | if (con->status != TCP_STATUS_CONNECTED) { |
325 | 0 | LOGGER_ERROR(logger, "TCP connection %u not connected", (unsigned int)con->identifier); |
326 | 0 | return -1; |
327 | 0 | } |
328 | | |
329 | 155 | uint8_t shared_key[CRYPTO_SHARED_KEY_SIZE]; |
330 | 155 | encrypt_precompute(data, self_secret_key, shared_key); |
331 | 155 | uint8_t plain[TCP_HANDSHAKE_PLAIN_SIZE]; |
332 | 155 | int len = decrypt_data_symmetric(shared_key, data + CRYPTO_PUBLIC_KEY_SIZE, |
333 | 155 | data + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE, TCP_HANDSHAKE_PLAIN_SIZE + CRYPTO_MAC_SIZE, plain); |
334 | | |
335 | 155 | if (len != TCP_HANDSHAKE_PLAIN_SIZE) { |
336 | 0 | LOGGER_ERROR(logger, "invalid TCP handshake decrypted length: %d != %d", len, TCP_HANDSHAKE_PLAIN_SIZE); |
337 | 0 | crypto_memzero(shared_key, sizeof(shared_key)); |
338 | 0 | return -1; |
339 | 0 | } |
340 | | |
341 | 155 | memcpy(con->public_key, data, CRYPTO_PUBLIC_KEY_SIZE); |
342 | 155 | uint8_t temp_secret_key[CRYPTO_SECRET_KEY_SIZE]; |
343 | 155 | uint8_t resp_plain[TCP_HANDSHAKE_PLAIN_SIZE]; |
344 | 155 | crypto_new_keypair(con->con.rng, resp_plain, temp_secret_key); |
345 | 155 | random_nonce(con->con.rng, con->con.sent_nonce); |
346 | 155 | memcpy(resp_plain + CRYPTO_PUBLIC_KEY_SIZE, con->con.sent_nonce, CRYPTO_NONCE_SIZE); |
347 | 155 | memcpy(con->recv_nonce, plain + CRYPTO_PUBLIC_KEY_SIZE, CRYPTO_NONCE_SIZE); |
348 | | |
349 | 155 | uint8_t response[TCP_SERVER_HANDSHAKE_SIZE]; |
350 | 155 | random_nonce(con->con.rng, response); |
351 | | |
352 | 155 | len = encrypt_data_symmetric(shared_key, response, resp_plain, TCP_HANDSHAKE_PLAIN_SIZE, |
353 | 155 | response + CRYPTO_NONCE_SIZE); |
354 | | |
355 | 155 | if (len != TCP_HANDSHAKE_PLAIN_SIZE + CRYPTO_MAC_SIZE) { |
356 | 0 | crypto_memzero(shared_key, sizeof(shared_key)); |
357 | 0 | return -1; |
358 | 0 | } |
359 | | |
360 | 155 | IP_Port ipp = {{{0}}}; |
361 | | |
362 | 155 | if (TCP_SERVER_HANDSHAKE_SIZE != net_send(con->con.ns, logger, con->con.sock, response, TCP_SERVER_HANDSHAKE_SIZE, &ipp)) { |
363 | 0 | crypto_memzero(shared_key, sizeof(shared_key)); |
364 | 0 | return -1; |
365 | 0 | } |
366 | | |
367 | 155 | encrypt_precompute(plain, temp_secret_key, con->con.shared_key); |
368 | 155 | con->status = TCP_STATUS_UNCONFIRMED; |
369 | | |
370 | 155 | crypto_memzero(shared_key, sizeof(shared_key)); |
371 | | |
372 | 155 | return 1; |
373 | 155 | } |
374 | | |
375 | | /** |
376 | | * @retval 1 if connection handshake was handled correctly. |
377 | | * @retval 0 if we didn't get it yet. |
378 | | * @retval -1 if the connection must be killed. |
379 | | */ |
380 | | non_null() |
381 | | static int read_connection_handshake(const Logger *logger, TCP_Secure_Connection *con, const uint8_t *self_secret_key) |
382 | 2.97k | { |
383 | 2.97k | uint8_t data[TCP_CLIENT_HANDSHAKE_SIZE]; |
384 | 2.97k | const int len = read_tcp_packet(logger, con->con.mem, con->con.ns, con->con.sock, data, TCP_CLIENT_HANDSHAKE_SIZE, &con->con.ip_port); |
385 | | |
386 | 2.97k | if (len == -1) { |
387 | 2.81k | LOGGER_TRACE(logger, "connection handshake is not ready yet"); |
388 | 2.81k | return 0; |
389 | 2.81k | } |
390 | | |
391 | 155 | return handle_tcp_handshake(logger, con, data, len, self_secret_key); |
392 | 2.97k | } |
393 | | |
394 | | /** |
395 | | * @retval 1 on success. |
396 | | * @retval 0 if could not send packet. |
397 | | * @retval -1 on failure (connection must be killed). |
398 | | */ |
399 | | non_null() |
400 | | static int send_routing_response(const Logger *logger, TCP_Secure_Connection *con, uint8_t rpid, |
401 | | const uint8_t *public_key) |
402 | 112 | { |
403 | 112 | uint8_t data[2 + CRYPTO_PUBLIC_KEY_SIZE]; |
404 | 112 | data[0] = TCP_PACKET_ROUTING_RESPONSE; |
405 | 112 | data[1] = rpid; |
406 | 112 | memcpy(data + 2, public_key, CRYPTO_PUBLIC_KEY_SIZE); |
407 | | |
408 | 112 | return write_packet_tcp_secure_connection(logger, &con->con, data, sizeof(data), true); |
409 | 112 | } |
410 | | |
411 | | /** |
412 | | * @retval 1 on success. |
413 | | * @retval 0 if could not send packet. |
414 | | * @retval -1 on failure (connection must be killed). |
415 | | */ |
416 | | non_null() |
417 | | static int send_connect_notification(const Logger *logger, TCP_Secure_Connection *con, uint8_t id) |
418 | 110 | { |
419 | 110 | uint8_t data[2] = {TCP_PACKET_CONNECTION_NOTIFICATION, (uint8_t)(id + NUM_RESERVED_PORTS)}; |
420 | 110 | return write_packet_tcp_secure_connection(logger, &con->con, data, sizeof(data), true); |
421 | 110 | } |
422 | | |
423 | | /** |
424 | | * @retval 1 on success. |
425 | | * @retval 0 if could not send packet. |
426 | | * @retval -1 on failure (connection must be killed). |
427 | | */ |
428 | | non_null() |
429 | | static int send_disconnect_notification(const Logger *logger, TCP_Secure_Connection *con, uint8_t id) |
430 | 3 | { |
431 | 3 | uint8_t data[2] = {TCP_PACKET_DISCONNECT_NOTIFICATION, (uint8_t)(id + NUM_RESERVED_PORTS)}; |
432 | 3 | return write_packet_tcp_secure_connection(logger, &con->con, data, sizeof(data), true); |
433 | 3 | } |
434 | | |
435 | | /** |
436 | | * @retval 0 on success. |
437 | | * @retval -1 on failure (connection must be killed). |
438 | | */ |
439 | | non_null() |
440 | | static int handle_tcp_routing_req(TCP_Server *tcp_server, uint32_t con_id, const uint8_t *public_key) |
441 | 112 | { |
442 | 112 | uint32_t index = -1; |
443 | 112 | TCP_Secure_Connection *con = &tcp_server->accepted_connection_array[con_id]; |
444 | | |
445 | | /* If person tries to cennect to himself we deny the request*/ |
446 | 112 | if (pk_equal(con->public_key, public_key)) { |
447 | 1 | if (send_routing_response(tcp_server->logger, con, 0, public_key) == -1) { |
448 | 0 | return -1; |
449 | 0 | } |
450 | | |
451 | 1 | return 0; |
452 | 1 | } |
453 | | |
454 | 26.7k | for (uint32_t i = 0; i < NUM_CLIENT_CONNECTIONS; ++i) { |
455 | 26.6k | if (con->connections[i].status != 0) { |
456 | 125 | if (pk_equal(public_key, con->connections[i].public_key)) { |
457 | 0 | if (send_routing_response(tcp_server->logger, con, i + NUM_RESERVED_PORTS, public_key) == -1) { |
458 | 0 | return -1; |
459 | 0 | } |
460 | | |
461 | 0 | return 0; |
462 | 0 | } |
463 | 26.5k | } else if (index == (uint32_t) -1) { |
464 | 111 | index = i; |
465 | 111 | } |
466 | 26.6k | } |
467 | | |
468 | 111 | if (index == (uint32_t) -1) { |
469 | 0 | if (send_routing_response(tcp_server->logger, con, 0, public_key) == -1) { |
470 | 0 | return -1; |
471 | 0 | } |
472 | | |
473 | 0 | return 0; |
474 | 0 | } |
475 | | |
476 | 111 | const int ret = send_routing_response(tcp_server->logger, con, index + NUM_RESERVED_PORTS, public_key); |
477 | | |
478 | 111 | if (ret == 0) { |
479 | 0 | return 0; |
480 | 0 | } |
481 | | |
482 | 111 | if (ret == -1) { |
483 | 0 | return -1; |
484 | 0 | } |
485 | | |
486 | 111 | con->connections[index].status = 1; |
487 | 111 | memcpy(con->connections[index].public_key, public_key, CRYPTO_PUBLIC_KEY_SIZE); |
488 | 111 | const int other_index = get_tcp_connection_index(tcp_server, public_key); |
489 | | |
490 | 111 | if (other_index != -1) { |
491 | 110 | uint32_t other_id = -1; |
492 | 110 | TCP_Secure_Connection *other_conn = &tcp_server->accepted_connection_array[other_index]; |
493 | | |
494 | 13.3k | for (uint32_t i = 0; i < NUM_CLIENT_CONNECTIONS; ++i) { |
495 | 13.2k | if (other_conn->connections[i].status == 1 |
496 | 13.2k | && pk_equal(other_conn->connections[i].public_key, con->public_key)) { |
497 | 55 | other_id = i; |
498 | 55 | break; |
499 | 55 | } |
500 | 13.2k | } |
501 | | |
502 | 110 | if (other_id != (uint32_t) -1) { |
503 | 55 | con->connections[index].status = 2; |
504 | 55 | con->connections[index].index = other_index; |
505 | 55 | con->connections[index].other_id = other_id; |
506 | 55 | other_conn->connections[other_id].status = 2; |
507 | 55 | other_conn->connections[other_id].index = con_id; |
508 | 55 | other_conn->connections[other_id].other_id = index; |
509 | | // TODO(irungentoo): return values? |
510 | 55 | send_connect_notification(tcp_server->logger, con, index); |
511 | 55 | send_connect_notification(tcp_server->logger, other_conn, other_id); |
512 | 55 | } |
513 | 110 | } |
514 | | |
515 | 111 | return 0; |
516 | 111 | } |
517 | | |
518 | | /** |
519 | | * @retval 0 on success. |
520 | | * @retval -1 on failure (connection must be killed). |
521 | | */ |
522 | | non_null() |
523 | | static int handle_tcp_oob_send(TCP_Server *tcp_server, uint32_t con_id, const uint8_t *public_key, const uint8_t *data, |
524 | | uint16_t length) |
525 | 173 | { |
526 | 173 | if (length == 0 || length > TCP_MAX_OOB_DATA_LENGTH) { |
527 | 0 | return -1; |
528 | 0 | } |
529 | | |
530 | 173 | const TCP_Secure_Connection *con = &tcp_server->accepted_connection_array[con_id]; |
531 | | |
532 | 173 | const int other_index = get_tcp_connection_index(tcp_server, public_key); |
533 | | |
534 | 173 | if (other_index != -1) { |
535 | 173 | const uint16_t resp_packet_size = 1 + CRYPTO_PUBLIC_KEY_SIZE + length; |
536 | 173 | VLA(uint8_t, resp_packet, resp_packet_size); |
537 | 173 | resp_packet[0] = TCP_PACKET_OOB_RECV; |
538 | 173 | memcpy(resp_packet + 1, con->public_key, CRYPTO_PUBLIC_KEY_SIZE); |
539 | 173 | memcpy(resp_packet + 1 + CRYPTO_PUBLIC_KEY_SIZE, data, length); |
540 | 173 | write_packet_tcp_secure_connection(tcp_server->logger, &tcp_server->accepted_connection_array[other_index].con, |
541 | 173 | resp_packet, resp_packet_size, false); |
542 | 173 | } |
543 | | |
544 | 173 | return 0; |
545 | 173 | } |
546 | | |
547 | | /** @brief Remove connection with con_number from the connections array of con. |
548 | | * |
549 | | * return -1 on failure. |
550 | | * return 0 on success. |
551 | | */ |
552 | | static int rm_connection_index(TCP_Server *tcp_server, TCP_Secure_Connection *con, uint8_t con_number) |
553 | 964 | { |
554 | 964 | if (con_number >= NUM_CLIENT_CONNECTIONS) { |
555 | 0 | return -1; |
556 | 0 | } |
557 | | |
558 | 964 | if (con->connections[con_number].status != 0) { |
559 | 4 | if (con->connections[con_number].status == 2) { |
560 | 3 | const uint32_t index = con->connections[con_number].index; |
561 | 3 | const uint8_t other_id = con->connections[con_number].other_id; |
562 | | |
563 | 3 | if (index >= tcp_server->size_accepted_connections) { |
564 | 0 | return -1; |
565 | 0 | } |
566 | | |
567 | 3 | tcp_server->accepted_connection_array[index].connections[other_id].other_id = 0; |
568 | 3 | tcp_server->accepted_connection_array[index].connections[other_id].index = 0; |
569 | 3 | tcp_server->accepted_connection_array[index].connections[other_id].status = 1; |
570 | | // TODO(irungentoo): return values? |
571 | 3 | send_disconnect_notification(tcp_server->logger, &tcp_server->accepted_connection_array[index], other_id); |
572 | 3 | } |
573 | | |
574 | 4 | con->connections[con_number].index = 0; |
575 | 4 | con->connections[con_number].other_id = 0; |
576 | 4 | con->connections[con_number].status = 0; |
577 | 4 | return 0; |
578 | 4 | } |
579 | | |
580 | 960 | return -1; |
581 | 964 | } |
582 | | |
583 | | /** @brief Encode con_id and identifier as a custom IP_Port. |
584 | | * |
585 | | * @return ip_port. |
586 | | */ |
587 | | static IP_Port con_id_to_ip_port(uint32_t con_id, uint64_t identifier) |
588 | 1.00k | { |
589 | 1.00k | IP_Port ip_port = {{{0}}}; |
590 | 1.00k | ip_port.ip.family = net_family_tcp_client(); |
591 | 1.00k | ip_port.ip.ip.v6.uint32[0] = con_id; |
592 | 1.00k | ip_port.ip.ip.v6.uint64[1] = identifier; |
593 | 1.00k | return ip_port; |
594 | | |
595 | 1.00k | } |
596 | | |
597 | | /** @brief Decode ip_port created by con_id_to_ip_port to con_id. |
598 | | * |
599 | | * @retval true on success. |
600 | | * @retval false if ip_port is invalid. |
601 | | */ |
602 | | non_null() |
603 | | static bool ip_port_to_con_id(const TCP_Server *tcp_server, const IP_Port *ip_port, uint32_t *con_id) |
604 | 808 | { |
605 | 808 | *con_id = ip_port->ip.ip.v6.uint32[0]; |
606 | | |
607 | 808 | return net_family_is_tcp_client(ip_port->ip.family) && |
608 | 808 | *con_id < tcp_server->size_accepted_connections && |
609 | 808 | tcp_server->accepted_connection_array[*con_id].identifier == ip_port->ip.ip.v6.uint64[1]; |
610 | 808 | } |
611 | | |
612 | | non_null() |
613 | | static int handle_onion_recv_1(void *object, const IP_Port *dest, const uint8_t *data, uint16_t length) |
614 | 808 | { |
615 | 808 | TCP_Server *tcp_server = (TCP_Server *)object; |
616 | 808 | uint32_t index; |
617 | | |
618 | 808 | if (!ip_port_to_con_id(tcp_server, dest, &index)) { |
619 | 0 | return 1; |
620 | 0 | } |
621 | | |
622 | 808 | TCP_Secure_Connection *con = &tcp_server->accepted_connection_array[index]; |
623 | | |
624 | 808 | const uint16_t packet_size = 1 + length; |
625 | 808 | VLA(uint8_t, packet, packet_size); |
626 | 808 | memcpy(packet + 1, data, length); |
627 | 808 | packet[0] = TCP_PACKET_ONION_RESPONSE; |
628 | | |
629 | 808 | if (write_packet_tcp_secure_connection(tcp_server->logger, &con->con, packet, packet_size, false) != 1) { |
630 | 0 | return 1; |
631 | 0 | } |
632 | | |
633 | 808 | return 0; |
634 | 808 | } |
635 | | |
636 | | non_null() |
637 | | static bool handle_forward_reply_tcp(void *object, const uint8_t *sendback_data, uint16_t sendback_data_len, |
638 | | const uint8_t *data, uint16_t length) |
639 | 5 | { |
640 | 5 | TCP_Server *tcp_server = (TCP_Server *)object; |
641 | | |
642 | 5 | if (sendback_data_len != 1 + sizeof(uint32_t) + sizeof(uint64_t)) { |
643 | 0 | return false; |
644 | 0 | } |
645 | | |
646 | 5 | if (*sendback_data != SENDBACK_TCP) { |
647 | 0 | return false; |
648 | 0 | } |
649 | | |
650 | 5 | uint32_t con_id; |
651 | 5 | uint64_t identifier; |
652 | 5 | net_unpack_u32(sendback_data + 1, &con_id); |
653 | 5 | net_unpack_u64(sendback_data + 1 + sizeof(uint32_t), &identifier); |
654 | | |
655 | 5 | if (con_id >= tcp_server->size_accepted_connections) { |
656 | 0 | return false; |
657 | 0 | } |
658 | | |
659 | 5 | TCP_Secure_Connection *con = &tcp_server->accepted_connection_array[con_id]; |
660 | | |
661 | 5 | if (con->identifier != identifier) { |
662 | 0 | return false; |
663 | 0 | } |
664 | | |
665 | 5 | const uint16_t packet_size = 1 + length; |
666 | 5 | VLA(uint8_t, packet, packet_size); |
667 | 5 | memcpy(packet + 1, data, length); |
668 | 5 | packet[0] = TCP_PACKET_FORWARDING; |
669 | | |
670 | 5 | return write_packet_tcp_secure_connection(tcp_server->logger, &con->con, packet, packet_size, false) == 1; |
671 | 5 | } |
672 | | |
673 | | /** |
674 | | * @retval 0 on success |
675 | | * @retval -1 on failure |
676 | | */ |
677 | | non_null() |
678 | | static int handle_tcp_packet(TCP_Server *tcp_server, uint32_t con_id, const uint8_t *data, uint16_t length) |
679 | 2.30k | { |
680 | 2.30k | if (length == 0) { |
681 | 0 | return -1; |
682 | 0 | } |
683 | | |
684 | 2.30k | TCP_Secure_Connection *const con = &tcp_server->accepted_connection_array[con_id]; |
685 | | |
686 | 2.30k | switch (data[0]) { |
687 | 112 | case TCP_PACKET_ROUTING_REQUEST: { |
688 | 112 | if (length != 1 + CRYPTO_PUBLIC_KEY_SIZE) { |
689 | 0 | return -1; |
690 | 0 | } |
691 | | |
692 | 112 | LOGGER_TRACE(tcp_server->logger, "handling routing request for %d", con_id); |
693 | 112 | return handle_tcp_routing_req(tcp_server, con_id, data + 1); |
694 | 112 | } |
695 | | |
696 | 0 | case TCP_PACKET_CONNECTION_NOTIFICATION: { |
697 | 0 | if (length != 2) { |
698 | 0 | return -1; |
699 | 0 | } |
700 | | |
701 | 0 | LOGGER_TRACE(tcp_server->logger, "handling connection notification for %d", con_id); |
702 | 0 | break; |
703 | 0 | } |
704 | | |
705 | 4 | case TCP_PACKET_DISCONNECT_NOTIFICATION: { |
706 | 4 | if (length != 2) { |
707 | 0 | return -1; |
708 | 0 | } |
709 | | |
710 | 4 | LOGGER_TRACE(tcp_server->logger, "handling disconnect notification for %d", con_id); |
711 | 4 | return rm_connection_index(tcp_server, con, data[1] - NUM_RESERVED_PORTS); |
712 | 4 | } |
713 | | |
714 | 67 | case TCP_PACKET_PING: { |
715 | 67 | if (length != 1 + sizeof(uint64_t)) { |
716 | 0 | return -1; |
717 | 0 | } |
718 | | |
719 | 67 | LOGGER_TRACE(tcp_server->logger, "handling ping for %d", con_id); |
720 | | |
721 | 67 | uint8_t response[1 + sizeof(uint64_t)]; |
722 | 67 | response[0] = TCP_PACKET_PONG; |
723 | 67 | memcpy(response + 1, data + 1, sizeof(uint64_t)); |
724 | 67 | write_packet_tcp_secure_connection(tcp_server->logger, &con->con, response, sizeof(response), true); |
725 | 67 | return 0; |
726 | 67 | } |
727 | | |
728 | 16 | case TCP_PACKET_PONG: { |
729 | 16 | if (length != 1 + sizeof(uint64_t)) { |
730 | 0 | return -1; |
731 | 0 | } |
732 | | |
733 | 16 | LOGGER_TRACE(tcp_server->logger, "handling pong for %d", con_id); |
734 | | |
735 | 16 | uint64_t ping_id; |
736 | 16 | memcpy(&ping_id, data + 1, sizeof(uint64_t)); |
737 | | |
738 | 16 | if (ping_id != 0) { |
739 | 16 | if (ping_id == con->ping_id) { |
740 | 16 | con->ping_id = 0; |
741 | 16 | } |
742 | | |
743 | 16 | return 0; |
744 | 16 | } |
745 | | |
746 | 0 | return -1; |
747 | 16 | } |
748 | | |
749 | 173 | case TCP_PACKET_OOB_SEND: { |
750 | 173 | if (length <= 1 + CRYPTO_PUBLIC_KEY_SIZE) { |
751 | 0 | return -1; |
752 | 0 | } |
753 | | |
754 | 173 | LOGGER_TRACE(tcp_server->logger, "handling oob send for %d", con_id); |
755 | | |
756 | 173 | return handle_tcp_oob_send(tcp_server, con_id, data + 1, data + 1 + CRYPTO_PUBLIC_KEY_SIZE, |
757 | 173 | length - (1 + CRYPTO_PUBLIC_KEY_SIZE)); |
758 | 173 | } |
759 | | |
760 | 1.00k | case TCP_PACKET_ONION_REQUEST: { |
761 | 1.00k | LOGGER_TRACE(tcp_server->logger, "handling onion request for %d", con_id); |
762 | | |
763 | 1.00k | if (tcp_server->onion != nullptr) { |
764 | 1.00k | if (length <= 1 + CRYPTO_NONCE_SIZE + ONION_SEND_BASE * 2) { |
765 | 0 | return -1; |
766 | 0 | } |
767 | | |
768 | 1.00k | IP_Port source = con_id_to_ip_port(con_id, con->identifier); |
769 | 1.00k | onion_send_1(tcp_server->onion, data + 1 + CRYPTO_NONCE_SIZE, length - (1 + CRYPTO_NONCE_SIZE), &source, |
770 | 1.00k | data + 1); |
771 | 1.00k | } |
772 | | |
773 | 1.00k | return 0; |
774 | 1.00k | } |
775 | | |
776 | 0 | case TCP_PACKET_ONION_RESPONSE: { |
777 | 0 | LOGGER_TRACE(tcp_server->logger, "handling onion response for %d", con_id); |
778 | 0 | return -1; |
779 | 1.00k | } |
780 | | |
781 | 9 | case TCP_PACKET_FORWARD_REQUEST: { |
782 | 9 | if (tcp_server->forwarding == nullptr) { |
783 | 0 | return -1; |
784 | 0 | } |
785 | | |
786 | 9 | const uint16_t sendback_data_len = 1 + sizeof(uint32_t) + sizeof(uint64_t); |
787 | 9 | uint8_t sendback_data[1 + sizeof(uint32_t) + sizeof(uint64_t)]; |
788 | 9 | sendback_data[0] = SENDBACK_TCP; |
789 | 9 | net_pack_u32(sendback_data + 1, con_id); |
790 | 9 | net_pack_u64(sendback_data + 1 + sizeof(uint32_t), con->identifier); |
791 | | |
792 | 9 | IP_Port dest; |
793 | 9 | const int ipport_length = unpack_ip_port(&dest, data + 1, length - 1, false); |
794 | | |
795 | 9 | if (ipport_length == -1) { |
796 | 0 | return -1; |
797 | 0 | } |
798 | | |
799 | 9 | const uint8_t *const forward_data = data + (1 + ipport_length); |
800 | 9 | const uint16_t forward_data_len = length - (1 + ipport_length); |
801 | | |
802 | 9 | if (forward_data_len > MAX_FORWARD_DATA_SIZE) { |
803 | 0 | return -1; |
804 | 0 | } |
805 | | |
806 | 9 | send_forwarding(tcp_server->forwarding, &dest, sendback_data, sendback_data_len, forward_data, forward_data_len); |
807 | 9 | return 0; |
808 | 9 | } |
809 | | |
810 | 0 | case TCP_PACKET_FORWARDING: { |
811 | 0 | return -1; |
812 | 9 | } |
813 | | |
814 | 913 | default: { |
815 | 913 | if (data[0] < NUM_RESERVED_PORTS) { |
816 | 0 | return -1; |
817 | 0 | } |
818 | | |
819 | 913 | const uint8_t c_id = data[0] - NUM_RESERVED_PORTS; |
820 | 913 | LOGGER_TRACE(tcp_server->logger, "handling packet id %d for %d", c_id, con_id); |
821 | | |
822 | 913 | if (c_id >= NUM_CLIENT_CONNECTIONS) { |
823 | 0 | return -1; |
824 | 0 | } |
825 | | |
826 | 913 | if (con->connections[c_id].status == 0) { |
827 | 0 | return -1; |
828 | 0 | } |
829 | | |
830 | 913 | if (con->connections[c_id].status != 2) { |
831 | 6 | return 0; |
832 | 6 | } |
833 | | |
834 | 907 | const uint32_t index = con->connections[c_id].index; |
835 | 907 | const uint8_t other_c_id = con->connections[c_id].other_id + NUM_RESERVED_PORTS; |
836 | 907 | VLA(uint8_t, new_data, length); |
837 | 907 | memcpy(new_data, data, length); |
838 | 907 | new_data[0] = other_c_id; |
839 | 907 | const int ret = write_packet_tcp_secure_connection(tcp_server->logger, |
840 | 907 | &tcp_server->accepted_connection_array[index].con, new_data, length, false); |
841 | | |
842 | 907 | if (ret == -1) { |
843 | 0 | return -1; |
844 | 0 | } |
845 | | |
846 | 907 | return 0; |
847 | 907 | } |
848 | 2.30k | } |
849 | | |
850 | 0 | return 0; |
851 | 2.30k | } |
852 | | |
853 | | |
854 | | non_null() |
855 | | static int confirm_tcp_connection(TCP_Server *tcp_server, const Mono_Time *mono_time, TCP_Secure_Connection *con, |
856 | | const uint8_t *data, uint16_t length) |
857 | 65 | { |
858 | 65 | const int index = add_accepted(tcp_server, mono_time, con); |
859 | | |
860 | 65 | if (index == -1) { |
861 | 0 | LOGGER_DEBUG(tcp_server->logger, "dropping connection %u: not accepted", (unsigned int)con->identifier); |
862 | 0 | kill_tcp_secure_connection(con); |
863 | 0 | return -1; |
864 | 0 | } |
865 | | |
866 | 65 | wipe_secure_connection(con); |
867 | | |
868 | 65 | if (handle_tcp_packet(tcp_server, index, data, length) == -1) { |
869 | 0 | LOGGER_DEBUG(tcp_server->logger, "dropping connection %u: data packet (len=%d) not handled", |
870 | 0 | (unsigned int)con->identifier, length); |
871 | 0 | kill_accepted(tcp_server, index); |
872 | 0 | return -1; |
873 | 0 | } |
874 | | |
875 | 65 | return index; |
876 | 65 | } |
877 | | |
878 | | /** |
879 | | * @return index on success |
880 | | * @retval -1 on failure |
881 | | */ |
882 | | non_null() |
883 | | static int accept_connection(TCP_Server *tcp_server, Socket sock) |
884 | 5.38k | { |
885 | 5.38k | if (!sock_valid(sock)) { |
886 | 2.50k | return -1; |
887 | 2.50k | } |
888 | | |
889 | 2.88k | if (!set_socket_nonblock(tcp_server->ns, sock)) { |
890 | 0 | kill_sock(tcp_server->ns, sock); |
891 | 0 | return -1; |
892 | 0 | } |
893 | | |
894 | 2.88k | if (!set_socket_nosigpipe(tcp_server->ns, sock)) { |
895 | 0 | kill_sock(tcp_server->ns, sock); |
896 | 0 | return -1; |
897 | 0 | } |
898 | | |
899 | 2.88k | const uint16_t index = tcp_server->incoming_connection_queue_index % MAX_INCOMING_CONNECTIONS; |
900 | | |
901 | 2.88k | TCP_Secure_Connection *conn = &tcp_server->incoming_connection_queue[index]; |
902 | | |
903 | 2.88k | if (conn->status != TCP_STATUS_NO_STATUS) { |
904 | 247 | LOGGER_DEBUG(tcp_server->logger, "connection %d dropped before accepting", index); |
905 | 247 | kill_tcp_secure_connection(conn); |
906 | 247 | } |
907 | | |
908 | 2.88k | conn->status = TCP_STATUS_CONNECTED; |
909 | 2.88k | conn->con.ns = tcp_server->ns; |
910 | 2.88k | conn->con.mem = tcp_server->mem; |
911 | 2.88k | conn->con.rng = tcp_server->rng; |
912 | 2.88k | conn->con.sock = sock; |
913 | 2.88k | conn->next_packet_length = 0; |
914 | | |
915 | 2.88k | ++tcp_server->incoming_connection_queue_index; |
916 | 2.88k | return index; |
917 | 2.88k | } |
918 | | |
919 | | non_null() |
920 | | static Socket new_listening_tcp_socket(const Logger *logger, const Network *ns, Family family, uint16_t port) |
921 | 35 | { |
922 | 35 | const Socket sock = net_socket(ns, family, TOX_SOCK_STREAM, TOX_PROTO_TCP); |
923 | | |
924 | 35 | if (!sock_valid(sock)) { |
925 | 0 | LOGGER_ERROR(logger, "TCP socket creation failed (family = %d)", family.value); |
926 | 0 | return net_invalid_socket(); |
927 | 0 | } |
928 | | |
929 | 35 | bool ok = set_socket_nonblock(ns, sock); |
930 | | |
931 | 35 | if (ok && net_family_is_ipv6(family)) { |
932 | 16 | ok = set_socket_dualstack(ns, sock); |
933 | 16 | } |
934 | | |
935 | 35 | if (ok) { |
936 | 35 | ok = set_socket_reuseaddr(ns, sock); |
937 | 35 | } |
938 | | |
939 | 35 | ok = ok && bind_to_port(ns, sock, family, port) && (net_listen(ns, sock, TCP_MAX_BACKLOG) == 0); |
940 | | |
941 | 35 | if (!ok) { |
942 | 0 | char *const error = net_new_strerror(net_error()); |
943 | 0 | LOGGER_WARNING(logger, "could not bind to TCP port %d (family = %d): %s", |
944 | 0 | port, family.value, error != nullptr ? error : "(null)"); |
945 | 0 | net_kill_strerror(error); |
946 | 0 | kill_sock(ns, sock); |
947 | 0 | return net_invalid_socket(); |
948 | 0 | } |
949 | | |
950 | 35 | LOGGER_DEBUG(logger, "successfully bound to TCP port %d", port); |
951 | 35 | return sock; |
952 | 35 | } |
953 | | |
954 | | TCP_Server *new_tcp_server(const Logger *logger, const Memory *mem, const Random *rng, const Network *ns, |
955 | | bool ipv6_enabled, uint16_t num_sockets, |
956 | | const uint16_t *ports, const uint8_t *secret_key, Onion *onion, Forwarding *forwarding) |
957 | 27 | { |
958 | 27 | if (num_sockets == 0 || ports == nullptr) { |
959 | 0 | LOGGER_ERROR(logger, "no sockets"); |
960 | 0 | return nullptr; |
961 | 0 | } |
962 | | |
963 | 27 | if (ns == nullptr) { |
964 | 0 | LOGGER_ERROR(logger, "NULL network"); |
965 | 0 | return nullptr; |
966 | 0 | } |
967 | | |
968 | 27 | TCP_Server *temp = (TCP_Server *)mem_alloc(mem, sizeof(TCP_Server)); |
969 | | |
970 | 27 | if (temp == nullptr) { |
971 | 1 | LOGGER_ERROR(logger, "TCP server allocation failed"); |
972 | 1 | return nullptr; |
973 | 1 | } |
974 | | |
975 | 26 | temp->logger = logger; |
976 | 26 | temp->mem = mem; |
977 | 26 | temp->ns = ns; |
978 | 26 | temp->rng = rng; |
979 | | |
980 | 26 | Socket *socks_listening = (Socket *)mem_valloc(mem, num_sockets, sizeof(Socket)); |
981 | | |
982 | 26 | if (socks_listening == nullptr) { |
983 | 1 | LOGGER_ERROR(logger, "socket allocation failed"); |
984 | 1 | mem_delete(mem, temp); |
985 | 1 | return nullptr; |
986 | 1 | } |
987 | | |
988 | 25 | temp->socks_listening = socks_listening; |
989 | | |
990 | | #ifdef TCP_SERVER_USE_EPOLL |
991 | | temp->efd = epoll_create(8); |
992 | | |
993 | | if (temp->efd == -1) { |
994 | | LOGGER_ERROR(logger, "epoll initialisation failed"); |
995 | | mem_delete(mem, socks_listening); |
996 | | mem_delete(mem, temp); |
997 | | return nullptr; |
998 | | } |
999 | | |
1000 | | #endif /* TCP_SERVER_USE_EPOLL */ |
1001 | | |
1002 | 25 | const Family family = ipv6_enabled ? net_family_ipv6() : net_family_ipv4(); |
1003 | | |
1004 | 60 | for (uint32_t i = 0; i < num_sockets; ++i) { |
1005 | 35 | const Socket sock = new_listening_tcp_socket(logger, ns, family, ports[i]); |
1006 | | |
1007 | 35 | if (!sock_valid(sock)) { |
1008 | 0 | continue; |
1009 | 0 | } |
1010 | | |
1011 | | #ifdef TCP_SERVER_USE_EPOLL |
1012 | | struct epoll_event ev; |
1013 | | |
1014 | | ev.events = EPOLLIN | EPOLLET; |
1015 | | ev.data.u64 = sock.sock | ((uint64_t)TCP_SOCKET_LISTENING << 32); |
1016 | | |
1017 | | if (epoll_ctl(temp->efd, EPOLL_CTL_ADD, sock.sock, &ev) == -1) { |
1018 | | continue; |
1019 | | } |
1020 | | |
1021 | | #endif /* TCP_SERVER_USE_EPOLL */ |
1022 | | |
1023 | 35 | temp->socks_listening[temp->num_listening_socks] = sock; |
1024 | 35 | ++temp->num_listening_socks; |
1025 | 35 | } |
1026 | | |
1027 | 25 | if (temp->num_listening_socks == 0) { |
1028 | 0 | mem_delete(mem, temp->socks_listening); |
1029 | 0 | mem_delete(mem, temp); |
1030 | 0 | return nullptr; |
1031 | 0 | } |
1032 | | |
1033 | 25 | if (onion != nullptr) { |
1034 | 20 | temp->onion = onion; |
1035 | 20 | set_callback_handle_recv_1(onion, &handle_onion_recv_1, temp); |
1036 | 20 | } |
1037 | | |
1038 | 25 | if (forwarding != nullptr) { |
1039 | 20 | temp->forwarding = forwarding; |
1040 | 20 | set_callback_forward_reply(forwarding, &handle_forward_reply_tcp, temp); |
1041 | 20 | } |
1042 | | |
1043 | 25 | memcpy(temp->secret_key, secret_key, CRYPTO_SECRET_KEY_SIZE); |
1044 | 25 | crypto_derive_public_key(temp->public_key, temp->secret_key); |
1045 | | |
1046 | 25 | bs_list_init(&temp->accepted_key_list, CRYPTO_PUBLIC_KEY_SIZE, 8); |
1047 | | |
1048 | 25 | return temp; |
1049 | 25 | } |
1050 | | |
1051 | | #ifndef TCP_SERVER_USE_EPOLL |
1052 | | non_null() |
1053 | | static void do_tcp_accept_new(TCP_Server *tcp_server) |
1054 | 2.41k | { |
1055 | 4.92k | for (uint32_t sock_idx = 0; sock_idx < tcp_server->num_listening_socks; ++sock_idx) { |
1056 | | |
1057 | 5.39k | for (uint32_t connection_idx = 0; connection_idx < MAX_INCOMING_CONNECTIONS; ++connection_idx) { |
1058 | 5.38k | const Socket sock = net_accept(tcp_server->ns, tcp_server->socks_listening[sock_idx]); |
1059 | | |
1060 | 5.38k | if (accept_connection(tcp_server, sock) == -1) { |
1061 | 2.50k | break; |
1062 | 2.50k | } |
1063 | 5.38k | } |
1064 | 2.51k | } |
1065 | 2.41k | } |
1066 | | #endif /* TCP_SERVER_USE_EPOLL */ |
1067 | | |
1068 | | non_null() |
1069 | | static int do_incoming(TCP_Server *tcp_server, uint32_t i) |
1070 | 618k | { |
1071 | 618k | TCP_Secure_Connection *const conn = &tcp_server->incoming_connection_queue[i]; |
1072 | | |
1073 | 618k | if (conn->status != TCP_STATUS_CONNECTED) { |
1074 | 615k | return -1; |
1075 | 615k | } |
1076 | | |
1077 | 2.97k | LOGGER_TRACE(tcp_server->logger, "handling incoming TCP connection %d", i); |
1078 | | |
1079 | 2.97k | const int ret = read_connection_handshake(tcp_server->logger, conn, tcp_server->secret_key); |
1080 | | |
1081 | 2.97k | if (ret == -1) { |
1082 | 0 | LOGGER_TRACE(tcp_server->logger, "incoming connection %d dropped due to failed handshake", i); |
1083 | 0 | kill_tcp_secure_connection(conn); |
1084 | 0 | return -1; |
1085 | 0 | } |
1086 | | |
1087 | 2.97k | if (ret != 1) { |
1088 | 2.81k | return -1; |
1089 | 2.81k | } |
1090 | | |
1091 | 155 | const int index_new = tcp_server->unconfirmed_connection_queue_index % MAX_INCOMING_CONNECTIONS; |
1092 | 155 | TCP_Secure_Connection *conn_old = conn; |
1093 | 155 | TCP_Secure_Connection *conn_new = &tcp_server->unconfirmed_connection_queue[index_new]; |
1094 | | |
1095 | 155 | if (conn_new->status != TCP_STATUS_NO_STATUS) { |
1096 | 0 | LOGGER_ERROR(tcp_server->logger, "incoming connection %d would overwrite existing", i); |
1097 | 0 | kill_tcp_secure_connection(conn_new); |
1098 | 0 | } |
1099 | | |
1100 | 155 | move_secure_connection(conn_new, conn_old); |
1101 | 155 | ++tcp_server->unconfirmed_connection_queue_index; |
1102 | | |
1103 | 155 | return index_new; |
1104 | 2.97k | } |
1105 | | |
1106 | | non_null() |
1107 | | static int do_unconfirmed(TCP_Server *tcp_server, const Mono_Time *mono_time, uint32_t i) |
1108 | 618k | { |
1109 | 618k | TCP_Secure_Connection *const conn = &tcp_server->unconfirmed_connection_queue[i]; |
1110 | | |
1111 | 618k | if (conn->status != TCP_STATUS_UNCONFIRMED) { |
1112 | 618k | return -1; |
1113 | 618k | } |
1114 | | |
1115 | 252 | LOGGER_TRACE(tcp_server->logger, "handling unconfirmed TCP connection %d", i); |
1116 | | |
1117 | 252 | uint8_t packet[MAX_PACKET_SIZE]; |
1118 | 252 | const int len = read_packet_tcp_secure_connection(tcp_server->logger, conn->con.mem, conn->con.ns, conn->con.sock, &conn->next_packet_length, conn->con.shared_key, conn->recv_nonce, packet, sizeof(packet), &conn->con.ip_port); |
1119 | | |
1120 | 252 | if (len == 0) { |
1121 | 184 | return -1; |
1122 | 184 | } |
1123 | | |
1124 | 68 | if (len == -1) { |
1125 | 3 | kill_tcp_secure_connection(conn); |
1126 | 3 | return -1; |
1127 | 3 | } |
1128 | | |
1129 | 65 | return confirm_tcp_connection(tcp_server, mono_time, conn, packet, len); |
1130 | 68 | } |
1131 | | |
1132 | | non_null() |
1133 | | static bool tcp_process_secure_packet(TCP_Server *tcp_server, uint32_t i) |
1134 | 16.7k | { |
1135 | 16.7k | TCP_Secure_Connection *const conn = &tcp_server->accepted_connection_array[i]; |
1136 | | |
1137 | 16.7k | uint8_t packet[MAX_PACKET_SIZE]; |
1138 | 16.7k | const int len = read_packet_tcp_secure_connection(tcp_server->logger, conn->con.mem, conn->con.ns, conn->con.sock, &conn->next_packet_length, conn->con.shared_key, conn->recv_nonce, packet, sizeof(packet), &conn->con.ip_port); |
1139 | 16.7k | LOGGER_TRACE(tcp_server->logger, "processing packet for %d: %d", i, len); |
1140 | | |
1141 | 16.7k | if (len == 0) { |
1142 | 14.5k | return false; |
1143 | 14.5k | } |
1144 | | |
1145 | 2.23k | if (len == -1) { |
1146 | 2 | kill_accepted(tcp_server, i); |
1147 | 2 | return false; |
1148 | 2 | } |
1149 | | |
1150 | 2.23k | if (handle_tcp_packet(tcp_server, i, packet, len) == -1) { |
1151 | 0 | LOGGER_TRACE(tcp_server->logger, "dropping connection %d: data packet (len=%d) not handled", i, len); |
1152 | 0 | kill_accepted(tcp_server, i); |
1153 | 0 | return false; |
1154 | 0 | } |
1155 | | |
1156 | 2.23k | return true; |
1157 | 2.23k | } |
1158 | | |
1159 | | non_null() |
1160 | | static void do_confirmed_recv(TCP_Server *tcp_server, uint32_t i) |
1161 | 14.5k | { |
1162 | 16.7k | while (tcp_process_secure_packet(tcp_server, i)) { |
1163 | | /* Keep reading until an error occurs or there is no more data to read. */ |
1164 | 2.23k | } |
1165 | 14.5k | } |
1166 | | |
1167 | | #ifndef TCP_SERVER_USE_EPOLL |
1168 | | non_null() |
1169 | | static void do_tcp_incoming(TCP_Server *tcp_server) |
1170 | 2.41k | { |
1171 | 620k | for (uint32_t i = 0; i < MAX_INCOMING_CONNECTIONS; ++i) { |
1172 | 618k | do_incoming(tcp_server, i); |
1173 | 618k | } |
1174 | 2.41k | } |
1175 | | |
1176 | | non_null() |
1177 | | static void do_tcp_unconfirmed(TCP_Server *tcp_server, const Mono_Time *mono_time) |
1178 | 2.41k | { |
1179 | 620k | for (uint32_t i = 0; i < MAX_INCOMING_CONNECTIONS; ++i) { |
1180 | 618k | do_unconfirmed(tcp_server, mono_time, i); |
1181 | 618k | } |
1182 | 2.41k | } |
1183 | | #endif /* TCP_SERVER_USE_EPOLL */ |
1184 | | |
1185 | | non_null() |
1186 | | static void do_tcp_confirmed(TCP_Server *tcp_server, const Mono_Time *mono_time) |
1187 | 2.41k | { |
1188 | | #ifdef TCP_SERVER_USE_EPOLL |
1189 | | |
1190 | | if (tcp_server->last_run_pinged == mono_time_get(mono_time)) { |
1191 | | return; |
1192 | | } |
1193 | | |
1194 | | tcp_server->last_run_pinged = mono_time_get(mono_time); |
1195 | | #endif /* TCP_SERVER_USE_EPOLL */ |
1196 | | |
1197 | 25.6k | for (uint32_t i = 0; i < tcp_server->size_accepted_connections; ++i) { |
1198 | 23.2k | TCP_Secure_Connection *conn = &tcp_server->accepted_connection_array[i]; |
1199 | | |
1200 | 23.2k | if (conn->status != TCP_STATUS_CONFIRMED) { |
1201 | 8.70k | continue; |
1202 | 8.70k | } |
1203 | | |
1204 | 14.5k | if (mono_time_is_timeout(mono_time, conn->last_pinged, TCP_PING_FREQUENCY)) { |
1205 | 18 | uint8_t ping[1 + sizeof(uint64_t)]; |
1206 | 18 | ping[0] = TCP_PACKET_PING; |
1207 | 18 | uint64_t ping_id = random_u64(conn->con.rng); |
1208 | | |
1209 | 18 | if (ping_id == 0) { |
1210 | 0 | ++ping_id; |
1211 | 0 | } |
1212 | | |
1213 | 18 | memcpy(ping + 1, &ping_id, sizeof(uint64_t)); |
1214 | 18 | const int ret = write_packet_tcp_secure_connection(tcp_server->logger, &conn->con, ping, sizeof(ping), true); |
1215 | | |
1216 | 18 | if (ret == 1) { |
1217 | 18 | conn->last_pinged = mono_time_get(mono_time); |
1218 | 18 | conn->ping_id = ping_id; |
1219 | 18 | } else { |
1220 | 0 | if (mono_time_is_timeout(mono_time, conn->last_pinged, TCP_PING_FREQUENCY + TCP_PING_TIMEOUT)) { |
1221 | 0 | kill_accepted(tcp_server, i); |
1222 | 0 | continue; |
1223 | 0 | } |
1224 | 0 | } |
1225 | 18 | } |
1226 | | |
1227 | 14.5k | if (conn->ping_id != 0 && mono_time_is_timeout(mono_time, conn->last_pinged, TCP_PING_TIMEOUT)) { |
1228 | 2 | kill_accepted(tcp_server, i); |
1229 | 2 | continue; |
1230 | 2 | } |
1231 | | |
1232 | 14.5k | send_pending_data(tcp_server->logger, &conn->con); |
1233 | | |
1234 | 14.5k | #ifndef TCP_SERVER_USE_EPOLL |
1235 | | |
1236 | 14.5k | do_confirmed_recv(tcp_server, i); |
1237 | | |
1238 | 14.5k | #endif /* TCP_SERVER_USE_EPOLL */ |
1239 | 14.5k | } |
1240 | 2.41k | } |
1241 | | |
1242 | | #ifdef TCP_SERVER_USE_EPOLL |
1243 | | non_null() |
1244 | | static bool tcp_epoll_process(TCP_Server *tcp_server, const Mono_Time *mono_time) |
1245 | | { |
1246 | | #define MAX_EVENTS 16 |
1247 | | struct epoll_event events[MAX_EVENTS]; |
1248 | | const int nfds = epoll_wait(tcp_server->efd, events, MAX_EVENTS, 0); |
1249 | | #undef MAX_EVENTS |
1250 | | |
1251 | | for (int n = 0; n < nfds; ++n) { |
1252 | | const Socket sock = {(int)(events[n].data.u64 & 0xFFFFFFFF)}; |
1253 | | const int status = (events[n].data.u64 >> 32) & 0xFF; |
1254 | | const int index = events[n].data.u64 >> 40; |
1255 | | |
1256 | | if ((events[n].events & EPOLLERR) != 0 || (events[n].events & EPOLLHUP) != 0 || (events[n].events & EPOLLRDHUP) != 0) { |
1257 | | switch (status) { |
1258 | | case TCP_SOCKET_LISTENING: { |
1259 | | // should never happen |
1260 | | LOGGER_ERROR(tcp_server->logger, "connection %d was in listening state", index); |
1261 | | break; |
1262 | | } |
1263 | | |
1264 | | case TCP_SOCKET_INCOMING: { |
1265 | | LOGGER_TRACE(tcp_server->logger, "incoming connection %d dropped", index); |
1266 | | kill_tcp_secure_connection(&tcp_server->incoming_connection_queue[index]); |
1267 | | break; |
1268 | | } |
1269 | | |
1270 | | case TCP_SOCKET_UNCONFIRMED: { |
1271 | | LOGGER_TRACE(tcp_server->logger, "unconfirmed connection %d dropped", index); |
1272 | | kill_tcp_secure_connection(&tcp_server->unconfirmed_connection_queue[index]); |
1273 | | break; |
1274 | | } |
1275 | | |
1276 | | case TCP_SOCKET_CONFIRMED: { |
1277 | | LOGGER_TRACE(tcp_server->logger, "confirmed connection %d dropped", index); |
1278 | | kill_accepted(tcp_server, index); |
1279 | | break; |
1280 | | } |
1281 | | } |
1282 | | |
1283 | | continue; |
1284 | | } |
1285 | | |
1286 | | |
1287 | | if ((events[n].events & EPOLLIN) == 0) { |
1288 | | continue; |
1289 | | } |
1290 | | |
1291 | | switch (status) { |
1292 | | case TCP_SOCKET_LISTENING: { |
1293 | | // socket is from socks_listening, accept connection |
1294 | | while (true) { |
1295 | | const Socket sock_new = net_accept(tcp_server->ns, sock); |
1296 | | |
1297 | | if (!sock_valid(sock_new)) { |
1298 | | break; |
1299 | | } |
1300 | | |
1301 | | const int index_new = accept_connection(tcp_server, sock_new); |
1302 | | |
1303 | | if (index_new == -1) { |
1304 | | continue; |
1305 | | } |
1306 | | |
1307 | | struct epoll_event ev; |
1308 | | |
1309 | | ev.events = EPOLLIN | EPOLLET | EPOLLRDHUP; |
1310 | | |
1311 | | ev.data.u64 = sock_new.sock | ((uint64_t)TCP_SOCKET_INCOMING << 32) | ((uint64_t)index_new << 40); |
1312 | | |
1313 | | if (epoll_ctl(tcp_server->efd, EPOLL_CTL_ADD, sock_new.sock, &ev) == -1) { |
1314 | | LOGGER_DEBUG(tcp_server->logger, "new connection %d was dropped due to epoll error %d", index, net_error()); |
1315 | | kill_tcp_secure_connection(&tcp_server->incoming_connection_queue[index_new]); |
1316 | | continue; |
1317 | | } |
1318 | | } |
1319 | | |
1320 | | break; |
1321 | | } |
1322 | | |
1323 | | case TCP_SOCKET_INCOMING: { |
1324 | | const int index_new = do_incoming(tcp_server, index); |
1325 | | |
1326 | | if (index_new != -1) { |
1327 | | LOGGER_TRACE(tcp_server->logger, "incoming connection %d was accepted as %d", index, index_new); |
1328 | | events[n].events = EPOLLIN | EPOLLET | EPOLLRDHUP; |
1329 | | events[n].data.u64 = sock.sock | ((uint64_t)TCP_SOCKET_UNCONFIRMED << 32) | ((uint64_t)index_new << 40); |
1330 | | |
1331 | | if (epoll_ctl(tcp_server->efd, EPOLL_CTL_MOD, sock.sock, &events[n]) == -1) { |
1332 | | LOGGER_DEBUG(tcp_server->logger, "incoming connection %d was dropped due to epoll error %d", index, net_error()); |
1333 | | kill_tcp_secure_connection(&tcp_server->unconfirmed_connection_queue[index_new]); |
1334 | | break; |
1335 | | } |
1336 | | } |
1337 | | |
1338 | | break; |
1339 | | } |
1340 | | |
1341 | | case TCP_SOCKET_UNCONFIRMED: { |
1342 | | const int index_new = do_unconfirmed(tcp_server, mono_time, index); |
1343 | | |
1344 | | if (index_new != -1) { |
1345 | | LOGGER_TRACE(tcp_server->logger, "unconfirmed connection %d was confirmed as %d", index, index_new); |
1346 | | events[n].events = EPOLLIN | EPOLLET | EPOLLRDHUP; |
1347 | | events[n].data.u64 = sock.sock | ((uint64_t)TCP_SOCKET_CONFIRMED << 32) | ((uint64_t)index_new << 40); |
1348 | | |
1349 | | if (epoll_ctl(tcp_server->efd, EPOLL_CTL_MOD, sock.sock, &events[n]) == -1) { |
1350 | | // remove from confirmed connections |
1351 | | LOGGER_DEBUG(tcp_server->logger, "unconfirmed connection %d was dropped due to epoll error %d", index, net_error()); |
1352 | | kill_accepted(tcp_server, index_new); |
1353 | | break; |
1354 | | } |
1355 | | } |
1356 | | |
1357 | | break; |
1358 | | } |
1359 | | |
1360 | | case TCP_SOCKET_CONFIRMED: { |
1361 | | do_confirmed_recv(tcp_server, index); |
1362 | | break; |
1363 | | } |
1364 | | } |
1365 | | } |
1366 | | |
1367 | | return nfds > 0; |
1368 | | } |
1369 | | |
1370 | | non_null() |
1371 | | static void do_tcp_epoll(TCP_Server *tcp_server, const Mono_Time *mono_time) |
1372 | | { |
1373 | | while (tcp_epoll_process(tcp_server, mono_time)) { |
1374 | | // Keep processing packets until there are no more FDs ready for reading. |
1375 | | continue; |
1376 | | } |
1377 | | } |
1378 | | #endif /* TCP_SERVER_USE_EPOLL */ |
1379 | | |
1380 | | void do_tcp_server(TCP_Server *tcp_server, const Mono_Time *mono_time) |
1381 | 2.41k | { |
1382 | | #ifdef TCP_SERVER_USE_EPOLL |
1383 | | do_tcp_epoll(tcp_server, mono_time); |
1384 | | |
1385 | | #else |
1386 | 2.41k | do_tcp_accept_new(tcp_server); |
1387 | 2.41k | do_tcp_incoming(tcp_server); |
1388 | 2.41k | do_tcp_unconfirmed(tcp_server, mono_time); |
1389 | 2.41k | #endif /* TCP_SERVER_USE_EPOLL */ |
1390 | | |
1391 | 2.41k | do_tcp_confirmed(tcp_server, mono_time); |
1392 | 2.41k | } |
1393 | | |
1394 | | void kill_tcp_server(TCP_Server *tcp_server) |
1395 | 25 | { |
1396 | 25 | if (tcp_server == nullptr) { |
1397 | 0 | return; |
1398 | 0 | } |
1399 | | |
1400 | 60 | for (uint32_t i = 0; i < tcp_server->num_listening_socks; ++i) { |
1401 | 35 | kill_sock(tcp_server->ns, tcp_server->socks_listening[i]); |
1402 | 35 | } |
1403 | | |
1404 | 25 | if (tcp_server->onion != nullptr) { |
1405 | 20 | set_callback_handle_recv_1(tcp_server->onion, nullptr, nullptr); |
1406 | 20 | } |
1407 | | |
1408 | 25 | if (tcp_server->forwarding != nullptr) { |
1409 | 20 | set_callback_forward_reply(tcp_server->forwarding, nullptr, nullptr); |
1410 | 20 | } |
1411 | | |
1412 | 25 | bs_list_free(&tcp_server->accepted_key_list); |
1413 | | |
1414 | | #ifdef TCP_SERVER_USE_EPOLL |
1415 | | close(tcp_server->efd); |
1416 | | #endif /* TCP_SERVER_USE_EPOLL */ |
1417 | | |
1418 | 6.42k | for (uint32_t i = 0; i < MAX_INCOMING_CONNECTIONS; ++i) { |
1419 | 6.40k | wipe_secure_connection(&tcp_server->incoming_connection_queue[i]); |
1420 | 6.40k | wipe_secure_connection(&tcp_server->unconfirmed_connection_queue[i]); |
1421 | 6.40k | } |
1422 | | |
1423 | 25 | free_accepted_connection_array(tcp_server); |
1424 | | |
1425 | 25 | crypto_memzero(tcp_server->secret_key, sizeof(tcp_server->secret_key)); |
1426 | | |
1427 | 25 | mem_delete(tcp_server->mem, tcp_server->socks_listening); |
1428 | 25 | mem_delete(tcp_server->mem, tcp_server); |
1429 | 25 | } |