/work/toxcore/TCP_client.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* SPDX-License-Identifier: GPL-3.0-or-later |
2 | | * Copyright © 2016-2026 The TokTok team. |
3 | | * Copyright © 2014 Tox project. |
4 | | */ |
5 | | |
6 | | /** |
7 | | * Implementation of the TCP relay client part of Tox. |
8 | | */ |
9 | | #include "TCP_client.h" |
10 | | |
11 | | #include <assert.h> |
12 | | #include <stdio.h> |
13 | | #include <string.h> |
14 | | |
15 | | #include "TCP_common.h" |
16 | | #include "attributes.h" |
17 | | #include "ccompat.h" |
18 | | #include "crypto_core.h" |
19 | | #include "forwarding.h" |
20 | | #include "logger.h" |
21 | | #include "mem.h" |
22 | | #include "mono_time.h" |
23 | | #include "net_profile.h" |
24 | | #include "network.h" |
25 | | #include "util.h" |
26 | | |
27 | | typedef struct TCP_Client_Conn { |
28 | | // TODO(iphydf): Add an enum for this. |
29 | | uint8_t status; /* 0 if not used, 1 if other is offline, 2 if other is online. */ |
30 | | uint8_t public_key[CRYPTO_PUBLIC_KEY_SIZE]; |
31 | | uint32_t number; |
32 | | } TCP_Client_Conn; |
33 | | |
34 | | struct TCP_Client_Connection { |
35 | | TCP_Connection con; |
36 | | TCP_Client_Status status; |
37 | | uint8_t self_public_key[CRYPTO_PUBLIC_KEY_SIZE]; /* our public key */ |
38 | | uint8_t public_key[CRYPTO_PUBLIC_KEY_SIZE]; /* public key of the server */ |
39 | | IP_Port ip_port; /* The ip and port of the server */ |
40 | | TCP_Proxy_Info proxy_info; |
41 | | uint8_t recv_nonce[CRYPTO_NONCE_SIZE]; /* Nonce of received packets. */ |
42 | | uint16_t next_packet_length; |
43 | | |
44 | | uint8_t temp_secret_key[CRYPTO_SECRET_KEY_SIZE]; |
45 | | |
46 | | uint64_t kill_at; |
47 | | |
48 | | uint64_t last_pinged; |
49 | | uint64_t ping_id; |
50 | | |
51 | | uint64_t ping_response_id; |
52 | | uint64_t ping_request_id; |
53 | | |
54 | | TCP_Client_Conn connections[NUM_CLIENT_CONNECTIONS]; |
55 | | tcp_routing_response_cb *_Nullable response_callback; |
56 | | void *_Nullable response_callback_object; |
57 | | tcp_routing_status_cb *_Nullable status_callback; |
58 | | void *_Nullable status_callback_object; |
59 | | tcp_routing_data_cb *_Nullable data_callback; |
60 | | void *_Nullable data_callback_object; |
61 | | tcp_oob_data_cb *_Nullable oob_data_callback; |
62 | | void *_Nullable oob_data_callback_object; |
63 | | |
64 | | tcp_onion_response_cb *_Nullable onion_callback; |
65 | | void *_Nullable onion_callback_object; |
66 | | |
67 | | forwarded_response_cb *_Nullable forwarded_response_callback; |
68 | | void *_Nullable forwarded_response_callback_object; |
69 | | |
70 | | /* Can be used by user. */ |
71 | | void *_Nullable custom_object; |
72 | | uint32_t custom_uint; |
73 | | }; |
74 | | |
75 | | const uint8_t *tcp_con_public_key(const TCP_Client_Connection *con) |
76 | 3.93k | { |
77 | 3.93k | return con->public_key; |
78 | 3.93k | } |
79 | | |
80 | | IP_Port tcp_con_ip_port(const TCP_Client_Connection *con) |
81 | 3.70k | { |
82 | 3.70k | return con->ip_port; |
83 | 3.70k | } |
84 | | |
85 | | TCP_Client_Status tcp_con_status(const TCP_Client_Connection *con) |
86 | 41.5k | { |
87 | 41.5k | return con->status; |
88 | 41.5k | } |
89 | | void *tcp_con_custom_object(const TCP_Client_Connection *con) |
90 | 1.73k | { |
91 | 1.73k | return con->custom_object; |
92 | 1.73k | } |
93 | | uint32_t tcp_con_custom_uint(const TCP_Client_Connection *con) |
94 | 1.73k | { |
95 | 1.73k | return con->custom_uint; |
96 | 1.73k | } |
97 | | void tcp_con_set_custom_object(TCP_Client_Connection *con, void *object) |
98 | 60 | { |
99 | 60 | con->custom_object = object; |
100 | 60 | } |
101 | | void tcp_con_set_custom_uint(TCP_Client_Connection *con, uint32_t value) |
102 | 59 | { |
103 | 59 | con->custom_uint = value; |
104 | 59 | } |
105 | | |
106 | | /** |
107 | | * @retval true on success |
108 | | * @retval false on failure |
109 | | */ |
110 | | static bool connect_sock_to(const Network *_Nonnull ns, const Logger *_Nonnull logger, const Memory *_Nonnull mem, Socket sock, const IP_Port *_Nonnull ip_port, |
111 | | const TCP_Proxy_Info *_Nonnull proxy_info) |
112 | 99 | { |
113 | 99 | Net_Err_Connect err; |
114 | 99 | if (proxy_info->proxy_type != TCP_PROXY_NONE) { |
115 | 28 | net_connect(ns, mem, logger, sock, &proxy_info->ip_port, &err); |
116 | 71 | } else { |
117 | 71 | net_connect(ns, mem, logger, sock, ip_port, &err); |
118 | 71 | } |
119 | 99 | switch (err) { |
120 | 99 | case NET_ERR_CONNECT_OK: |
121 | 99 | case NET_ERR_CONNECT_FAILED: { |
122 | | /* nonblocking socket, connect will never return success */ |
123 | 99 | return true; |
124 | 99 | } |
125 | 0 | case NET_ERR_CONNECT_INVALID_FAMILY: |
126 | 0 | return false; |
127 | 99 | } |
128 | 0 | LOGGER_ERROR(logger, "unexpected error code %s from net_connect", net_err_connect_to_string(err)); |
129 | 0 | return false; |
130 | 99 | } |
131 | | |
132 | | /** |
133 | | * @retval 1 on success. |
134 | | * @retval 0 on failure. |
135 | | */ |
136 | | static int proxy_http_generate_connection_request(TCP_Client_Connection *_Nonnull tcp_conn) |
137 | 11 | { |
138 | 11 | const char one[] = "CONNECT "; |
139 | 11 | const char two[] = " HTTP/1.1\nHost: "; |
140 | 11 | const char three[] = "\r\n\r\n"; |
141 | | |
142 | 11 | char ip[TOX_INET6_ADDRSTRLEN]; |
143 | | |
144 | 11 | if (!ip_parse_addr(&tcp_conn->ip_port.ip, ip, sizeof(ip))) { |
145 | 0 | return 0; |
146 | 0 | } |
147 | | |
148 | 11 | const uint16_t port = net_ntohs(tcp_conn->ip_port.port); |
149 | 11 | const int written = snprintf((char *)tcp_conn->con.last_packet, MAX_PACKET_SIZE, "%s%s:%hu%s%s:%hu%s", one, ip, port, |
150 | 11 | two, ip, port, three); |
151 | | |
152 | 11 | if (written < 0 || MAX_PACKET_SIZE < written) { |
153 | 0 | return 0; |
154 | 0 | } |
155 | | |
156 | 11 | tcp_conn->con.last_packet_length = written; |
157 | 11 | tcp_conn->con.last_packet_sent = 0; |
158 | 11 | return 1; |
159 | 11 | } |
160 | | |
161 | | /** |
162 | | * @retval 1 on success. |
163 | | * @retval 0 if no data received. |
164 | | * @retval -1 on failure (connection refused). |
165 | | */ |
166 | | static int proxy_http_read_connection_response(const Logger *_Nonnull logger, const TCP_Client_Connection *_Nonnull tcp_conn) |
167 | 2 | { |
168 | 2 | const char success[] = "200"; |
169 | 2 | uint8_t data[16]; // draining works the best if the length is a power of 2 |
170 | | |
171 | 2 | const TCP_Connection *con0 = &tcp_conn->con; |
172 | 2 | const int ret = read_tcp_packet(logger, con0->mem, con0->ns, con0->sock, data, sizeof(data) - 1, &con0->ip_port); |
173 | | |
174 | 2 | if (ret == -1) { |
175 | 1 | return 0; |
176 | 1 | } |
177 | | |
178 | 1 | data[sizeof(data) - 1] = 0; |
179 | | |
180 | 1 | if (strstr((const char *)data, success) != nullptr) { |
181 | | // drain all data |
182 | 1 | uint16_t data_left = net_socket_data_recv_buffer(tcp_conn->con.ns, tcp_conn->con.sock); |
183 | | |
184 | 6 | while (data_left > 0) { |
185 | 5 | uint8_t temp_data[16]; |
186 | 5 | const uint16_t temp_data_size = min_u16(data_left, sizeof(temp_data)); |
187 | 5 | const TCP_Connection *con = &tcp_conn->con; |
188 | | |
189 | 5 | if (read_tcp_packet(logger, con->mem, con->ns, con->sock, temp_data, temp_data_size, |
190 | 5 | &con->ip_port) == -1) { |
191 | 0 | LOGGER_ERROR(logger, "failed to drain TCP data (but ignoring failure)"); |
192 | 0 | return 1; |
193 | 0 | } |
194 | | |
195 | 5 | data_left -= temp_data_size; |
196 | 5 | } |
197 | | |
198 | 1 | return 1; |
199 | 1 | } |
200 | | |
201 | 0 | return -1; |
202 | 1 | } |
203 | | |
204 | | enum Tcp_Socks5_Proxy_Hs { |
205 | | TCP_SOCKS5_PROXY_HS_VERSION_SOCKS5 = 0x05, |
206 | | TCP_SOCKS5_PROXY_HS_COMM_ESTABLISH_REQUEST = 0x01, |
207 | | TCP_SOCKS5_PROXY_HS_COMM_REQUEST_GRANTED = 0x00, |
208 | | TCP_SOCKS5_PROXY_HS_AUTH_METHODS_SUPPORTED = 0x01, |
209 | | TCP_SOCKS5_PROXY_HS_NO_AUTH = 0x00, |
210 | | TCP_SOCKS5_PROXY_HS_RESERVED = 0x00, |
211 | | TCP_SOCKS5_PROXY_HS_ADDR_TYPE_IPV4 = 0x01, |
212 | | TCP_SOCKS5_PROXY_HS_ADDR_TYPE_IPV6 = 0x04, |
213 | | }; |
214 | | |
215 | | static void proxy_socks5_generate_greetings(TCP_Client_Connection *_Nonnull tcp_conn) |
216 | 16 | { |
217 | 16 | tcp_conn->con.last_packet[0] = TCP_SOCKS5_PROXY_HS_VERSION_SOCKS5; |
218 | 16 | tcp_conn->con.last_packet[1] = TCP_SOCKS5_PROXY_HS_AUTH_METHODS_SUPPORTED; |
219 | 16 | tcp_conn->con.last_packet[2] = TCP_SOCKS5_PROXY_HS_NO_AUTH; |
220 | | |
221 | 16 | tcp_conn->con.last_packet_length = 3; |
222 | 16 | tcp_conn->con.last_packet_sent = 0; |
223 | 16 | } |
224 | | |
225 | | /** |
226 | | * @retval 1 on success. |
227 | | * @retval 0 if no data received. |
228 | | * @retval -1 on failure (connection refused). |
229 | | */ |
230 | | static int socks5_read_handshake_response(const Logger *_Nonnull logger, const TCP_Client_Connection *_Nonnull tcp_conn) |
231 | 2 | { |
232 | 2 | uint8_t data[2]; |
233 | 2 | const TCP_Connection *con = &tcp_conn->con; |
234 | 2 | const int ret = read_tcp_packet(logger, con->mem, con->ns, con->sock, data, sizeof(data), &con->ip_port); |
235 | | |
236 | 2 | if (ret == -1) { |
237 | 1 | return 0; |
238 | 1 | } |
239 | | |
240 | 1 | if (data[0] == TCP_SOCKS5_PROXY_HS_VERSION_SOCKS5 && data[1] == TCP_SOCKS5_PROXY_HS_COMM_REQUEST_GRANTED) { |
241 | 1 | return 1; |
242 | 1 | } |
243 | | |
244 | 0 | return -1; |
245 | 1 | } |
246 | | |
247 | | static void proxy_socks5_generate_connection_request(TCP_Client_Connection *_Nonnull tcp_conn) |
248 | 1 | { |
249 | 1 | tcp_conn->con.last_packet[0] = TCP_SOCKS5_PROXY_HS_VERSION_SOCKS5; |
250 | 1 | tcp_conn->con.last_packet[1] = TCP_SOCKS5_PROXY_HS_COMM_ESTABLISH_REQUEST; |
251 | 1 | tcp_conn->con.last_packet[2] = TCP_SOCKS5_PROXY_HS_RESERVED; |
252 | 1 | uint16_t length = 3; |
253 | | |
254 | 1 | if (net_family_is_ipv4(tcp_conn->ip_port.ip.family)) { |
255 | 1 | tcp_conn->con.last_packet[3] = TCP_SOCKS5_PROXY_HS_ADDR_TYPE_IPV4; |
256 | 1 | ++length; |
257 | 1 | memcpy(tcp_conn->con.last_packet + length, tcp_conn->ip_port.ip.ip.v4.uint8, sizeof(IP4)); |
258 | 1 | length += sizeof(IP4); |
259 | 1 | } else { |
260 | 0 | tcp_conn->con.last_packet[3] = TCP_SOCKS5_PROXY_HS_ADDR_TYPE_IPV6; |
261 | 0 | ++length; |
262 | 0 | memcpy(tcp_conn->con.last_packet + length, tcp_conn->ip_port.ip.ip.v6.uint8, sizeof(IP6)); |
263 | 0 | length += sizeof(IP6); |
264 | 0 | } |
265 | | |
266 | 1 | memcpy(tcp_conn->con.last_packet + length, &tcp_conn->ip_port.port, sizeof(uint16_t)); |
267 | 1 | length += sizeof(uint16_t); |
268 | | |
269 | 1 | tcp_conn->con.last_packet_length = length; |
270 | 1 | tcp_conn->con.last_packet_sent = 0; |
271 | 1 | } |
272 | | |
273 | | /** |
274 | | * @retval 1 on success. |
275 | | * @retval 0 if no data received. |
276 | | * @retval -1 on failure (connection refused). |
277 | | */ |
278 | | static int proxy_socks5_read_connection_response(const Logger *_Nonnull logger, const TCP_Client_Connection *_Nonnull tcp_conn) |
279 | 2 | { |
280 | 2 | if (net_family_is_ipv4(tcp_conn->ip_port.ip.family)) { |
281 | 2 | uint8_t data[4 + sizeof(IP4) + sizeof(uint16_t)]; |
282 | 2 | const TCP_Connection *con = &tcp_conn->con; |
283 | 2 | const int ret = read_tcp_packet(logger, con->mem, con->ns, con->sock, data, sizeof(data), &con->ip_port); |
284 | | |
285 | 2 | if (ret == -1) { |
286 | 1 | return 0; |
287 | 1 | } |
288 | | |
289 | 1 | if (data[0] == TCP_SOCKS5_PROXY_HS_VERSION_SOCKS5 && data[1] == TCP_SOCKS5_PROXY_HS_COMM_REQUEST_GRANTED) { |
290 | 1 | return 1; |
291 | 1 | } |
292 | 1 | } else { |
293 | 0 | uint8_t data[4 + sizeof(IP6) + sizeof(uint16_t)]; |
294 | 0 | const TCP_Connection *con = &tcp_conn->con; |
295 | 0 | const int ret = read_tcp_packet(logger, con->mem, con->ns, con->sock, data, sizeof(data), &con->ip_port); |
296 | |
|
297 | 0 | if (ret == -1) { |
298 | 0 | return 0; |
299 | 0 | } |
300 | | |
301 | 0 | if (data[0] == TCP_SOCKS5_PROXY_HS_VERSION_SOCKS5 && data[1] == TCP_SOCKS5_PROXY_HS_COMM_REQUEST_GRANTED) { |
302 | 0 | return 1; |
303 | 0 | } |
304 | 0 | } |
305 | | |
306 | 0 | return -1; |
307 | 2 | } |
308 | | |
309 | | /** |
310 | | * @retval 0 on success. |
311 | | * @retval -1 on failure. |
312 | | */ |
313 | | static int generate_handshake(TCP_Client_Connection *_Nonnull tcp_conn) |
314 | 73 | { |
315 | 73 | uint8_t plain[CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE]; |
316 | 73 | crypto_new_keypair(tcp_conn->con.rng, plain, tcp_conn->temp_secret_key); |
317 | 73 | random_nonce(tcp_conn->con.rng, tcp_conn->con.sent_nonce); |
318 | 73 | memcpy(plain + CRYPTO_PUBLIC_KEY_SIZE, tcp_conn->con.sent_nonce, CRYPTO_NONCE_SIZE); |
319 | 73 | memcpy(tcp_conn->con.last_packet, tcp_conn->self_public_key, CRYPTO_PUBLIC_KEY_SIZE); |
320 | 73 | random_nonce(tcp_conn->con.rng, tcp_conn->con.last_packet + CRYPTO_PUBLIC_KEY_SIZE); |
321 | 73 | const int len = encrypt_data_symmetric(tcp_conn->con.mem, tcp_conn->con.shared_key, tcp_conn->con.last_packet + CRYPTO_PUBLIC_KEY_SIZE, plain, |
322 | 73 | sizeof(plain), tcp_conn->con.last_packet + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE); |
323 | | |
324 | 73 | if (len != sizeof(plain) + CRYPTO_MAC_SIZE) { |
325 | 0 | return -1; |
326 | 0 | } |
327 | | |
328 | 73 | tcp_conn->con.last_packet_length = CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE + sizeof(plain) + CRYPTO_MAC_SIZE; |
329 | 73 | tcp_conn->con.last_packet_sent = 0; |
330 | 73 | return 0; |
331 | 73 | } |
332 | | |
333 | | /** |
334 | | * @param data must be of length TCP_SERVER_HANDSHAKE_SIZE |
335 | | * |
336 | | * @retval 0 on success. |
337 | | * @retval -1 on failure. |
338 | | */ |
339 | | static int handle_handshake(TCP_Client_Connection *_Nonnull tcp_conn, const uint8_t *_Nonnull data) |
340 | 64 | { |
341 | 64 | uint8_t plain[CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE]; |
342 | 64 | const int len = decrypt_data_symmetric(tcp_conn->con.mem, tcp_conn->con.shared_key, data, data + CRYPTO_NONCE_SIZE, |
343 | 64 | TCP_SERVER_HANDSHAKE_SIZE - CRYPTO_NONCE_SIZE, plain); |
344 | | |
345 | 64 | if (len != sizeof(plain)) { |
346 | 0 | return -1; |
347 | 0 | } |
348 | | |
349 | 64 | memcpy(tcp_conn->recv_nonce, plain + CRYPTO_PUBLIC_KEY_SIZE, CRYPTO_NONCE_SIZE); |
350 | 64 | encrypt_precompute(plain, tcp_conn->temp_secret_key, tcp_conn->con.shared_key); |
351 | 64 | crypto_memzero(tcp_conn->temp_secret_key, CRYPTO_SECRET_KEY_SIZE); |
352 | 64 | return 0; |
353 | 64 | } |
354 | | |
355 | | /** |
356 | | * @retval 1 on success. |
357 | | * @retval 0 if could not send packet. |
358 | | * @retval -1 on failure (connection must be killed). |
359 | | */ |
360 | | int send_routing_request(const Logger *logger, TCP_Client_Connection *con, const uint8_t *public_key) |
361 | 112 | { |
362 | 112 | uint8_t packet[1 + CRYPTO_PUBLIC_KEY_SIZE]; |
363 | 112 | packet[0] = TCP_PACKET_ROUTING_REQUEST; |
364 | 112 | memcpy(packet + 1, public_key, CRYPTO_PUBLIC_KEY_SIZE); |
365 | 112 | return write_packet_tcp_secure_connection(logger, &con->con, packet, sizeof(packet), true); |
366 | 112 | } |
367 | | |
368 | | void routing_response_handler(TCP_Client_Connection *con, tcp_routing_response_cb *response_callback, void *object) |
369 | 61 | { |
370 | 61 | con->response_callback = response_callback; |
371 | 61 | con->response_callback_object = object; |
372 | 61 | } |
373 | | |
374 | | void routing_status_handler(TCP_Client_Connection *con, tcp_routing_status_cb *status_callback, void *object) |
375 | 60 | { |
376 | 60 | con->status_callback = status_callback; |
377 | 60 | con->status_callback_object = object; |
378 | 60 | } |
379 | | |
380 | | static int tcp_send_ping_response(const Logger *_Nonnull logger, TCP_Client_Connection *_Nonnull con); |
381 | | static int tcp_send_ping_request(const Logger *_Nonnull logger, TCP_Client_Connection *_Nonnull con); |
382 | | |
383 | | /** |
384 | | * @retval 1 on success. |
385 | | * @retval 0 if could not send packet. |
386 | | * @retval -1 on failure. |
387 | | */ |
388 | | int send_data(const Logger *logger, TCP_Client_Connection *con, uint8_t con_id, const uint8_t *data, uint16_t length) |
389 | 1.34k | { |
390 | 1.34k | if (con_id >= NUM_CLIENT_CONNECTIONS) { |
391 | 0 | return -1; |
392 | 0 | } |
393 | | |
394 | 1.34k | if (con->connections[con_id].status != 2) { |
395 | 0 | return -1; |
396 | 0 | } |
397 | | |
398 | 1.34k | if (tcp_send_ping_response(logger, con) == 0 || tcp_send_ping_request(logger, con) == 0) { |
399 | 0 | return 0; |
400 | 0 | } |
401 | | |
402 | 1.34k | if (1 + length > MAX_PACKET_SIZE) { |
403 | 1 | LOGGER_ERROR(logger, "Packet length too long: %u", length); |
404 | 1 | return -1; |
405 | 1 | } |
406 | | |
407 | 1.33k | const uint16_t packet_size = 1 + length; |
408 | 1.33k | VLA(uint8_t, packet, packet_size); |
409 | 1.33k | packet[0] = con_id + NUM_RESERVED_PORTS; |
410 | 1.33k | memcpy(packet + 1, data, length); |
411 | 1.33k | return write_packet_tcp_secure_connection(logger, &con->con, packet, packet_size, false); |
412 | 1.34k | } |
413 | | |
414 | | /** |
415 | | * @retval 1 on success. |
416 | | * @retval 0 if could not send packet. |
417 | | * @retval -1 on failure. |
418 | | */ |
419 | | int send_oob_packet(const Logger *logger, TCP_Client_Connection *con, const uint8_t *public_key, const uint8_t *data, |
420 | | uint16_t length) |
421 | 202 | { |
422 | 202 | if (length == 0 || length > TCP_MAX_OOB_DATA_LENGTH) { |
423 | 0 | return -1; |
424 | 0 | } |
425 | | |
426 | 202 | const uint16_t packet_size = 1 + CRYPTO_PUBLIC_KEY_SIZE + length; |
427 | 202 | VLA(uint8_t, packet, packet_size); |
428 | 202 | packet[0] = TCP_PACKET_OOB_SEND; |
429 | 202 | memcpy(packet + 1, public_key, CRYPTO_PUBLIC_KEY_SIZE); |
430 | 202 | memcpy(packet + 1 + CRYPTO_PUBLIC_KEY_SIZE, data, length); |
431 | 202 | return write_packet_tcp_secure_connection(logger, &con->con, packet, packet_size, false); |
432 | 202 | } |
433 | | |
434 | | /** @brief Set the number that will be used as an argument in the callbacks related to con_id. |
435 | | * |
436 | | * When not set by this function, the number is -1. |
437 | | * |
438 | | * return 0 on success. |
439 | | * return -1 on failure. |
440 | | */ |
441 | | int set_tcp_connection_number(TCP_Client_Connection *con, uint8_t con_id, uint32_t number) |
442 | 111 | { |
443 | 111 | if (con_id >= NUM_CLIENT_CONNECTIONS) { |
444 | 0 | return -1; |
445 | 0 | } |
446 | | |
447 | 111 | if (con->connections[con_id].status == 0) { |
448 | 0 | return -1; |
449 | 0 | } |
450 | | |
451 | 111 | con->connections[con_id].number = number; |
452 | 111 | return 0; |
453 | 111 | } |
454 | | |
455 | | void routing_data_handler(TCP_Client_Connection *con, tcp_routing_data_cb *data_callback, void *object) |
456 | 60 | { |
457 | 60 | con->data_callback = data_callback; |
458 | 60 | con->data_callback_object = object; |
459 | 60 | } |
460 | | |
461 | | void oob_data_handler(TCP_Client_Connection *con, tcp_oob_data_cb *oob_data_callback, void *object) |
462 | 60 | { |
463 | 60 | con->oob_data_callback = oob_data_callback; |
464 | 60 | con->oob_data_callback_object = object; |
465 | 60 | } |
466 | | |
467 | | /** |
468 | | * @retval 1 on success. |
469 | | * @retval 0 if could not send packet. |
470 | | * @retval -1 on failure (connection must be killed). |
471 | | */ |
472 | | static int client_send_disconnect_notification(const Logger *_Nonnull logger, TCP_Client_Connection *_Nonnull con, uint8_t id) |
473 | 106 | { |
474 | 106 | uint8_t packet[1 + 1]; |
475 | 106 | packet[0] = TCP_PACKET_DISCONNECT_NOTIFICATION; |
476 | 106 | packet[1] = id; |
477 | 106 | return write_packet_tcp_secure_connection(logger, &con->con, packet, sizeof(packet), true); |
478 | 106 | } |
479 | | |
480 | | /** |
481 | | * @retval 1 on success. |
482 | | * @retval 0 if could not send packet. |
483 | | * @retval -1 on failure (connection must be killed). |
484 | | */ |
485 | | static int tcp_send_ping_request(const Logger *logger, TCP_Client_Connection *con) |
486 | 41.7k | { |
487 | 41.7k | if (con->ping_request_id == 0) { |
488 | 41.6k | return 1; |
489 | 41.6k | } |
490 | | |
491 | 117 | uint8_t packet[1 + sizeof(uint64_t)]; |
492 | 117 | packet[0] = TCP_PACKET_PING; |
493 | 117 | memcpy(packet + 1, &con->ping_request_id, sizeof(uint64_t)); |
494 | 117 | const int ret = write_packet_tcp_secure_connection(logger, &con->con, packet, sizeof(packet), true); |
495 | | |
496 | 117 | if (ret == 1) { |
497 | 109 | con->ping_request_id = 0; |
498 | 109 | } |
499 | | |
500 | 117 | return ret; |
501 | 41.7k | } |
502 | | |
503 | | /** |
504 | | * @retval 1 on success. |
505 | | * @retval 0 if could not send packet. |
506 | | * @retval -1 on failure (connection must be killed). |
507 | | */ |
508 | | static int tcp_send_ping_response(const Logger *logger, TCP_Client_Connection *con) |
509 | 41.6k | { |
510 | 41.6k | if (con->ping_response_id == 0) { |
511 | 41.6k | return 1; |
512 | 41.6k | } |
513 | | |
514 | 42 | uint8_t packet[1 + sizeof(uint64_t)]; |
515 | 42 | packet[0] = TCP_PACKET_PONG; |
516 | 42 | memcpy(packet + 1, &con->ping_response_id, sizeof(uint64_t)); |
517 | 42 | const int ret = write_packet_tcp_secure_connection(logger, &con->con, packet, sizeof(packet), true); |
518 | | |
519 | 45 | if (ret == 1) { |
520 | 45 | con->ping_response_id = 0; |
521 | 45 | } |
522 | | |
523 | 42 | return ret; |
524 | 41.6k | } |
525 | | |
526 | | /** |
527 | | * @retval 1 on success. |
528 | | * @retval 0 if could not send packet. |
529 | | * @retval -1 on failure (connection must be killed). |
530 | | */ |
531 | | int send_disconnect_request(const Logger *logger, TCP_Client_Connection *con, uint8_t con_id) |
532 | 106 | { |
533 | 106 | if (con_id >= NUM_CLIENT_CONNECTIONS) { |
534 | 0 | return -1; |
535 | 0 | } |
536 | | |
537 | 106 | con->connections[con_id].status = 0; |
538 | 106 | con->connections[con_id].number = 0; |
539 | 106 | return client_send_disconnect_notification(logger, con, con_id + NUM_RESERVED_PORTS); |
540 | 106 | } |
541 | | |
542 | | /** |
543 | | * @retval 1 on success. |
544 | | * @retval 0 if could not send packet. |
545 | | * @retval -1 on failure (connection must be killed). |
546 | | */ |
547 | | int send_onion_request(const Logger *logger, TCP_Client_Connection *con, const uint8_t *data, uint16_t length) |
548 | 6.55k | { |
549 | 6.55k | if (1 + length > MAX_PACKET_SIZE) { |
550 | 0 | LOGGER_ERROR(logger, "Packet length too long: %u", length); |
551 | 0 | return -1; |
552 | 0 | } |
553 | | |
554 | 6.55k | const uint16_t packet_size = 1 + length; |
555 | 6.55k | VLA(uint8_t, packet, packet_size); |
556 | 6.55k | packet[0] = TCP_PACKET_ONION_REQUEST; |
557 | 6.55k | memcpy(packet + 1, data, length); |
558 | 6.55k | return write_packet_tcp_secure_connection(logger, &con->con, packet, packet_size, false); |
559 | 6.55k | } |
560 | | |
561 | | void onion_response_handler(TCP_Client_Connection *con, tcp_onion_response_cb *onion_callback, void *object) |
562 | 59 | { |
563 | 59 | con->onion_callback = onion_callback; |
564 | 59 | con->onion_callback_object = object; |
565 | 59 | } |
566 | | |
567 | | /** @retval 1 on success. |
568 | | * @retval 0 if could not send packet. |
569 | | * @retval -1 on failure (connection must be killed). |
570 | | */ |
571 | | int send_forward_request_tcp(const Logger *logger, TCP_Client_Connection *con, const IP_Port *dest, const uint8_t *data, uint16_t length) |
572 | 5 | { |
573 | 5 | if (length > MAX_FORWARD_DATA_SIZE) { |
574 | 0 | return -1; |
575 | 0 | } |
576 | | |
577 | 5 | VLA(uint8_t, packet, 1 + MAX_PACKED_IPPORT_SIZE + length); |
578 | 5 | packet[0] = TCP_PACKET_FORWARD_REQUEST; |
579 | 5 | const int ipport_length = pack_ip_port(logger, packet + 1, MAX_PACKED_IPPORT_SIZE, dest); |
580 | | |
581 | 5 | if (ipport_length == -1) { |
582 | 0 | return 0; |
583 | 0 | } |
584 | | |
585 | 5 | memcpy(packet + 1 + ipport_length, data, length); |
586 | 5 | return write_packet_tcp_secure_connection(logger, &con->con, packet, 1 + ipport_length + length, false); |
587 | 5 | } |
588 | | |
589 | | void forwarding_handler(TCP_Client_Connection *con, forwarded_response_cb *forwarded_response_callback, void *object) |
590 | 59 | { |
591 | 59 | con->forwarded_response_callback = forwarded_response_callback; |
592 | 59 | con->forwarded_response_callback_object = object; |
593 | 59 | } |
594 | | |
595 | | /** Create new TCP connection to ip_port/public_key */ |
596 | | TCP_Client_Connection *new_tcp_connection( |
597 | | const Logger *logger, const Memory *mem, const Mono_Time *mono_time, const Random *rng, const Network *ns, |
598 | | const IP_Port *ip_port, const uint8_t *public_key, const uint8_t *self_public_key, const uint8_t *self_secret_key, |
599 | | const TCP_Proxy_Info *proxy_info, Net_Profile *net_profile) |
600 | 99 | { |
601 | 99 | assert(logger != nullptr); |
602 | 99 | assert(mem != nullptr); |
603 | 99 | assert(mono_time != nullptr); |
604 | 99 | assert(rng != nullptr); |
605 | 99 | assert(ns != nullptr); |
606 | | |
607 | 99 | if (!net_family_is_ipv4(ip_port->ip.family) && !net_family_is_ipv6(ip_port->ip.family)) { |
608 | 0 | LOGGER_ERROR(logger, "Invalid IP family: %d", ip_port->ip.family.value); |
609 | 0 | return nullptr; |
610 | 0 | } |
611 | | |
612 | 99 | const TCP_Proxy_Info default_proxyinfo = {{{{0}}}}; |
613 | | |
614 | 99 | if (proxy_info == nullptr) { |
615 | 5 | proxy_info = &default_proxyinfo; |
616 | 5 | } |
617 | | |
618 | 99 | Family family = ip_port->ip.family; |
619 | | |
620 | 99 | if (proxy_info->proxy_type != TCP_PROXY_NONE) { |
621 | 28 | family = proxy_info->ip_port.ip.family; |
622 | 28 | } |
623 | | |
624 | 99 | const Socket sock = net_socket(ns, family, TOX_SOCK_STREAM, TOX_PROTO_TCP); |
625 | | |
626 | 99 | if (!sock_valid(sock)) { |
627 | 0 | LOGGER_ERROR(logger, "Failed to create TCP socket with family %d", family.value); |
628 | 0 | return nullptr; |
629 | 0 | } |
630 | | |
631 | 99 | if (!set_socket_nosigpipe(ns, sock)) { |
632 | 0 | LOGGER_ERROR(logger, "Failed to set TCP socket to ignore SIGPIPE"); |
633 | 0 | kill_sock(ns, sock); |
634 | 0 | return nullptr; |
635 | 0 | } |
636 | | |
637 | 99 | if (!set_socket_nonblock(ns, sock)) { |
638 | 0 | LOGGER_ERROR(logger, "Failed to set TCP socket to non-blocking"); |
639 | 0 | kill_sock(ns, sock); |
640 | 0 | return nullptr; |
641 | 0 | } |
642 | | |
643 | 99 | if (!connect_sock_to(ns, logger, mem, sock, ip_port, proxy_info)) { |
644 | 0 | Ip_Ntoa ip_ntoa; |
645 | 0 | LOGGER_WARNING(logger, "Failed to connect TCP socket to %s:%u", |
646 | 0 | net_ip_ntoa(&ip_port->ip, &ip_ntoa), net_ntohs(ip_port->port)); |
647 | 0 | kill_sock(ns, sock); |
648 | 0 | return nullptr; |
649 | 0 | } |
650 | | |
651 | 99 | TCP_Client_Connection *temp = (TCP_Client_Connection *)mem_alloc(mem, sizeof(TCP_Client_Connection)); |
652 | | |
653 | 99 | if (temp == nullptr) { |
654 | 1 | LOGGER_ERROR(logger, "Failed to allocate memory for TCP_Client_Connection"); |
655 | 1 | kill_sock(ns, sock); |
656 | 1 | return nullptr; |
657 | 1 | } |
658 | | |
659 | 98 | temp->con.ns = ns; |
660 | 98 | temp->con.mem = mem; |
661 | 98 | temp->con.rng = rng; |
662 | 98 | temp->con.sock = sock; |
663 | 98 | temp->con.ip_port = *ip_port; |
664 | 98 | temp->con.net_profile = net_profile; |
665 | 98 | memcpy(temp->public_key, public_key, CRYPTO_PUBLIC_KEY_SIZE); |
666 | 98 | memcpy(temp->self_public_key, self_public_key, CRYPTO_PUBLIC_KEY_SIZE); |
667 | 98 | encrypt_precompute(temp->public_key, self_secret_key, temp->con.shared_key); |
668 | 98 | temp->ip_port = *ip_port; |
669 | 98 | temp->proxy_info = *proxy_info; |
670 | | |
671 | 98 | switch (proxy_info->proxy_type) { |
672 | 11 | case TCP_PROXY_HTTP: { |
673 | 11 | temp->status = TCP_CLIENT_PROXY_HTTP_CONNECTING; |
674 | 11 | proxy_http_generate_connection_request(temp); |
675 | 11 | break; |
676 | 0 | } |
677 | | |
678 | 16 | case TCP_PROXY_SOCKS5: { |
679 | 16 | temp->status = TCP_CLIENT_PROXY_SOCKS5_CONNECTING; |
680 | 16 | proxy_socks5_generate_greetings(temp); |
681 | 16 | break; |
682 | 0 | } |
683 | | |
684 | 71 | case TCP_PROXY_NONE: { |
685 | 71 | temp->status = TCP_CLIENT_CONNECTING; |
686 | | |
687 | 71 | if (generate_handshake(temp) == -1) { |
688 | 0 | LOGGER_ERROR(logger, "Failed to generate handshake"); |
689 | 0 | kill_sock(ns, sock); |
690 | 0 | mem_delete(mem, temp); |
691 | 0 | return nullptr; |
692 | 0 | } |
693 | | |
694 | 71 | break; |
695 | 71 | } |
696 | 98 | } |
697 | | |
698 | 98 | temp->kill_at = mono_time_get(mono_time) + TCP_CONNECTION_TIMEOUT; |
699 | | |
700 | 98 | return temp; |
701 | 98 | } |
702 | | |
703 | | static int handle_tcp_client_routing_response(TCP_Client_Connection *_Nonnull conn, const uint8_t *_Nonnull data, uint16_t length) |
704 | 113 | { |
705 | 113 | if (length != 1 + 1 + CRYPTO_PUBLIC_KEY_SIZE) { |
706 | 0 | return -1; |
707 | 0 | } |
708 | | |
709 | 113 | if (data[1] < NUM_RESERVED_PORTS) { |
710 | 0 | return 0; |
711 | 0 | } |
712 | | |
713 | 113 | const uint8_t con_id = data[1] - NUM_RESERVED_PORTS; |
714 | | |
715 | 113 | if (conn->connections[con_id].status != 0) { |
716 | 0 | return 0; |
717 | 0 | } |
718 | | |
719 | 113 | conn->connections[con_id].status = 1; |
720 | 113 | conn->connections[con_id].number = -1; |
721 | 113 | memcpy(conn->connections[con_id].public_key, data + 2, CRYPTO_PUBLIC_KEY_SIZE); |
722 | | |
723 | 113 | if (conn->response_callback != nullptr) { |
724 | 111 | conn->response_callback(conn->response_callback_object, con_id, conn->connections[con_id].public_key); |
725 | 111 | } |
726 | | |
727 | 113 | return 0; |
728 | 113 | } |
729 | | |
730 | | static int handle_tcp_client_connection_notification(TCP_Client_Connection *_Nonnull conn, const uint8_t *_Nonnull data, uint16_t length) |
731 | 111 | { |
732 | 111 | if (length != 1 + 1) { |
733 | 0 | return -1; |
734 | 0 | } |
735 | | |
736 | 111 | if (data[1] < NUM_RESERVED_PORTS) { |
737 | 0 | return -1; |
738 | 0 | } |
739 | | |
740 | 111 | const uint8_t con_id = data[1] - NUM_RESERVED_PORTS; |
741 | | |
742 | 111 | if (conn->connections[con_id].status != 1) { |
743 | 0 | return 0; |
744 | 0 | } |
745 | | |
746 | 111 | conn->connections[con_id].status = 2; |
747 | | |
748 | 111 | if (conn->status_callback != nullptr) { |
749 | 109 | conn->status_callback(conn->status_callback_object, conn->connections[con_id].number, con_id, |
750 | 109 | conn->connections[con_id].status); |
751 | 109 | } |
752 | | |
753 | 111 | return 0; |
754 | 111 | } |
755 | | |
756 | | static int handle_tcp_client_disconnect_notification(TCP_Client_Connection *_Nonnull conn, const uint8_t *_Nonnull data, uint16_t length) |
757 | 3 | { |
758 | 3 | if (length != 1 + 1) { |
759 | 0 | return -1; |
760 | 0 | } |
761 | | |
762 | 3 | if (data[1] < NUM_RESERVED_PORTS) { |
763 | 0 | return -1; |
764 | 0 | } |
765 | | |
766 | 3 | const uint8_t con_id = data[1] - NUM_RESERVED_PORTS; |
767 | | |
768 | 3 | if (conn->connections[con_id].status == 0) { |
769 | 0 | return 0; |
770 | 0 | } |
771 | | |
772 | 3 | if (conn->connections[con_id].status != 2) { |
773 | 0 | return 0; |
774 | 0 | } |
775 | | |
776 | 3 | conn->connections[con_id].status = 1; |
777 | | |
778 | 3 | if (conn->status_callback != nullptr) { |
779 | 3 | conn->status_callback(conn->status_callback_object, conn->connections[con_id].number, con_id, |
780 | 3 | conn->connections[con_id].status); |
781 | 3 | } |
782 | | |
783 | 3 | return 0; |
784 | 3 | } |
785 | | |
786 | | static int handle_tcp_client_ping(const Logger *_Nonnull logger, TCP_Client_Connection *_Nonnull conn, const uint8_t *_Nonnull data, uint16_t length) |
787 | 45 | { |
788 | 45 | if (length != 1 + sizeof(uint64_t)) { |
789 | 0 | return -1; |
790 | 0 | } |
791 | | |
792 | 45 | uint64_t ping_id; |
793 | 45 | memcpy(&ping_id, data + 1, sizeof(uint64_t)); |
794 | 45 | conn->ping_response_id = ping_id; |
795 | 45 | tcp_send_ping_response(logger, conn); |
796 | 45 | return 0; |
797 | 45 | } |
798 | | |
799 | | static int handle_tcp_client_pong(TCP_Client_Connection *_Nonnull conn, const uint8_t *_Nonnull data, uint16_t length) |
800 | 107 | { |
801 | 107 | if (length != 1 + sizeof(uint64_t)) { |
802 | 0 | return -1; |
803 | 0 | } |
804 | | |
805 | 107 | uint64_t ping_id; |
806 | 107 | memcpy(&ping_id, data + 1, sizeof(uint64_t)); |
807 | | |
808 | 107 | if (ping_id != 0) { |
809 | 107 | if (ping_id == conn->ping_id) { |
810 | 107 | conn->ping_id = 0; |
811 | 107 | } |
812 | | |
813 | 107 | return 0; |
814 | 107 | } |
815 | | |
816 | 0 | return -1; |
817 | 107 | } |
818 | | |
819 | | static int handle_tcp_client_oob_recv(TCP_Client_Connection *_Nonnull conn, const uint8_t *_Nonnull data, uint16_t length, void *_Nullable userdata) |
820 | 196 | { |
821 | 196 | if (length <= 1 + CRYPTO_PUBLIC_KEY_SIZE) { |
822 | 0 | return -1; |
823 | 0 | } |
824 | | |
825 | 196 | if (conn->oob_data_callback != nullptr) { |
826 | 196 | conn->oob_data_callback(conn->oob_data_callback_object, data + 1, data + 1 + CRYPTO_PUBLIC_KEY_SIZE, |
827 | 196 | length - (1 + CRYPTO_PUBLIC_KEY_SIZE), userdata); |
828 | 196 | } |
829 | | |
830 | 196 | return 0; |
831 | 196 | } |
832 | | |
833 | | /** |
834 | | * @retval 0 on success |
835 | | * @retval -1 on failure |
836 | | */ |
837 | | static int handle_tcp_client_packet(const Logger *_Nonnull logger, TCP_Client_Connection *_Nonnull conn, const uint8_t *_Nonnull data, |
838 | | uint16_t length, void *_Nullable userdata) |
839 | 8.32k | { |
840 | 8.32k | if (length <= 1) { |
841 | 0 | return -1; |
842 | 0 | } |
843 | | |
844 | 8.32k | netprof_record_packet(conn->con.net_profile, data[0], length, PACKET_DIRECTION_RECV); |
845 | | |
846 | 8.32k | switch (data[0]) { |
847 | 113 | case TCP_PACKET_ROUTING_RESPONSE: |
848 | 113 | return handle_tcp_client_routing_response(conn, data, length); |
849 | | |
850 | 111 | case TCP_PACKET_CONNECTION_NOTIFICATION: |
851 | 111 | return handle_tcp_client_connection_notification(conn, data, length); |
852 | | |
853 | 3 | case TCP_PACKET_DISCONNECT_NOTIFICATION: |
854 | 3 | return handle_tcp_client_disconnect_notification(conn, data, length); |
855 | | |
856 | 45 | case TCP_PACKET_PING: |
857 | 45 | return handle_tcp_client_ping(logger, conn, data, length); |
858 | | |
859 | 107 | case TCP_PACKET_PONG: |
860 | 107 | return handle_tcp_client_pong(conn, data, length); |
861 | | |
862 | 196 | case TCP_PACKET_OOB_RECV: |
863 | 196 | return handle_tcp_client_oob_recv(conn, data, length, userdata); |
864 | | |
865 | 6.53k | case TCP_PACKET_ONION_RESPONSE: { |
866 | 6.53k | if (conn->onion_callback != nullptr) { |
867 | 6.53k | conn->onion_callback(conn->onion_callback_object, data + 1, length - 1, userdata); |
868 | 6.53k | } |
869 | 6.53k | return 0; |
870 | 0 | } |
871 | | |
872 | 5 | case TCP_PACKET_FORWARDING: { |
873 | 5 | if (conn->forwarded_response_callback != nullptr) { |
874 | 5 | conn->forwarded_response_callback(conn->forwarded_response_callback_object, data + 1, length - 1, userdata); |
875 | 5 | } |
876 | 5 | return 0; |
877 | 0 | } |
878 | | |
879 | 1.20k | default: { |
880 | 1.20k | if (data[0] < NUM_RESERVED_PORTS) { |
881 | 0 | return -1; |
882 | 0 | } |
883 | | |
884 | 1.20k | const uint8_t con_id = data[0] - NUM_RESERVED_PORTS; |
885 | | |
886 | 1.20k | if (conn->data_callback != nullptr) { |
887 | 1.20k | conn->data_callback(conn->data_callback_object, conn->connections[con_id].number, con_id, data + 1, length - 1, |
888 | 1.20k | userdata); |
889 | 1.20k | } |
890 | 1.20k | } |
891 | 8.32k | } |
892 | | |
893 | 1.20k | return 0; |
894 | 8.32k | } |
895 | | |
896 | | static bool tcp_process_packet(const Logger *_Nonnull logger, TCP_Client_Connection *_Nonnull conn, void *_Nullable userdata) |
897 | 48.6k | { |
898 | 48.6k | uint8_t packet[MAX_PACKET_SIZE]; |
899 | 48.6k | const int len = read_packet_tcp_secure_connection(logger, conn->con.mem, conn->con.ns, conn->con.sock, &conn->next_packet_length, conn->con.shared_key, conn->recv_nonce, packet, sizeof(packet), |
900 | 48.6k | &conn->ip_port); |
901 | | |
902 | 48.6k | if (len == 0) { |
903 | 40.1k | return false; |
904 | 40.1k | } |
905 | | |
906 | 8.40k | if (len == -1) { |
907 | 0 | conn->status = TCP_CLIENT_DISCONNECTED; |
908 | 0 | return false; |
909 | 0 | } |
910 | | |
911 | 8.40k | if (handle_tcp_client_packet(logger, conn, packet, len, userdata) == -1) { |
912 | 0 | conn->status = TCP_CLIENT_DISCONNECTED; |
913 | 0 | return false; |
914 | 0 | } |
915 | | |
916 | 8.40k | return true; |
917 | 8.40k | } |
918 | | |
919 | | static int do_confirmed_tcp(const Logger *_Nonnull logger, TCP_Client_Connection *_Nonnull conn, const Mono_Time *_Nonnull mono_time, |
920 | | void *_Nullable userdata) |
921 | 40.2k | { |
922 | 40.2k | send_pending_data(logger, &conn->con); |
923 | 40.2k | tcp_send_ping_response(logger, conn); |
924 | 40.2k | tcp_send_ping_request(logger, conn); |
925 | | |
926 | 40.2k | if (mono_time_is_timeout(mono_time, conn->last_pinged, TCP_PING_FREQUENCY)) { |
927 | 109 | uint64_t ping_id = random_u64(conn->con.rng); |
928 | | |
929 | 109 | if (ping_id == 0) { |
930 | 0 | ++ping_id; |
931 | 0 | } |
932 | | |
933 | 109 | conn->ping_request_id = ping_id; |
934 | 109 | conn->ping_id = ping_id; |
935 | 109 | tcp_send_ping_request(logger, conn); |
936 | 109 | conn->last_pinged = mono_time_get(mono_time); |
937 | 109 | } |
938 | | |
939 | 40.2k | if (conn->ping_id != 0 && mono_time_is_timeout(mono_time, conn->last_pinged, TCP_PING_TIMEOUT)) { |
940 | 0 | conn->status = TCP_CLIENT_DISCONNECTED; |
941 | 0 | return 0; |
942 | 0 | } |
943 | | |
944 | 48.5k | while (tcp_process_packet(logger, conn, userdata)) { |
945 | | /* Keep reading until error or out of data. */ |
946 | 8.32k | } |
947 | | |
948 | 40.2k | return 0; |
949 | 40.2k | } |
950 | | |
951 | | /** Run the TCP connection */ |
952 | | void do_tcp_connection(const Logger *logger, const Mono_Time *mono_time, |
953 | | TCP_Client_Connection *tcp_connection, void *userdata) |
954 | 40.9k | { |
955 | 40.9k | if (tcp_connection->status == TCP_CLIENT_DISCONNECTED) { |
956 | 0 | return; |
957 | 0 | } |
958 | | |
959 | 40.9k | if (tcp_connection->status == TCP_CLIENT_PROXY_HTTP_CONNECTING) { |
960 | 3 | if (send_pending_data(logger, &tcp_connection->con) == 0) { |
961 | 2 | const int ret = proxy_http_read_connection_response(logger, tcp_connection); |
962 | | |
963 | 2 | if (ret == -1) { |
964 | 0 | tcp_connection->kill_at = 0; |
965 | 0 | tcp_connection->status = TCP_CLIENT_DISCONNECTED; |
966 | 0 | } |
967 | | |
968 | 2 | if (ret == 1) { |
969 | 1 | generate_handshake(tcp_connection); |
970 | 1 | tcp_connection->status = TCP_CLIENT_CONNECTING; |
971 | 1 | } |
972 | 2 | } |
973 | 3 | } |
974 | | |
975 | 40.9k | if (tcp_connection->status == TCP_CLIENT_PROXY_SOCKS5_CONNECTING) { |
976 | 591 | if (send_pending_data(logger, &tcp_connection->con) == 0) { |
977 | 2 | const int ret = socks5_read_handshake_response(logger, tcp_connection); |
978 | | |
979 | 2 | if (ret == -1) { |
980 | 0 | tcp_connection->kill_at = 0; |
981 | 0 | tcp_connection->status = TCP_CLIENT_DISCONNECTED; |
982 | 0 | } |
983 | | |
984 | 2 | if (ret == 1) { |
985 | 1 | proxy_socks5_generate_connection_request(tcp_connection); |
986 | 1 | tcp_connection->status = TCP_CLIENT_PROXY_SOCKS5_UNCONFIRMED; |
987 | 1 | } |
988 | 2 | } |
989 | 591 | } |
990 | | |
991 | 40.9k | if (tcp_connection->status == TCP_CLIENT_PROXY_SOCKS5_UNCONFIRMED) { |
992 | 2 | if (send_pending_data(logger, &tcp_connection->con) == 0) { |
993 | 2 | const int ret = proxy_socks5_read_connection_response(logger, tcp_connection); |
994 | | |
995 | 2 | if (ret == -1) { |
996 | 0 | tcp_connection->kill_at = 0; |
997 | 0 | tcp_connection->status = TCP_CLIENT_DISCONNECTED; |
998 | 0 | } |
999 | | |
1000 | 2 | if (ret == 1) { |
1001 | 1 | generate_handshake(tcp_connection); |
1002 | 1 | tcp_connection->status = TCP_CLIENT_CONNECTING; |
1003 | 1 | } |
1004 | 2 | } |
1005 | 2 | } |
1006 | | |
1007 | 40.9k | if (tcp_connection->status == TCP_CLIENT_CONNECTING) { |
1008 | 70 | if (send_pending_data(logger, &tcp_connection->con) == 0) { |
1009 | 63 | tcp_connection->status = TCP_CLIENT_UNCONFIRMED; |
1010 | 63 | } |
1011 | 70 | } |
1012 | | |
1013 | 40.9k | if (tcp_connection->status == TCP_CLIENT_UNCONFIRMED) { |
1014 | 132 | uint8_t data[TCP_SERVER_HANDSHAKE_SIZE]; |
1015 | 132 | const TCP_Connection *con = &tcp_connection->con; |
1016 | 132 | const int len = read_tcp_packet(logger, con->mem, con->ns, con->sock, data, sizeof(data), &con->ip_port); |
1017 | | |
1018 | 132 | if (sizeof(data) == len) { |
1019 | 64 | if (handle_handshake(tcp_connection, data) == 0) { |
1020 | 64 | tcp_connection->kill_at = UINT64_MAX; |
1021 | 64 | tcp_connection->status = TCP_CLIENT_CONFIRMED; |
1022 | 64 | } else { |
1023 | 0 | tcp_connection->kill_at = 0; |
1024 | 0 | tcp_connection->status = TCP_CLIENT_DISCONNECTED; |
1025 | 0 | } |
1026 | 64 | } |
1027 | 132 | } |
1028 | | |
1029 | 40.9k | if (tcp_connection->status == TCP_CLIENT_CONFIRMED) { |
1030 | 40.2k | do_confirmed_tcp(logger, tcp_connection, mono_time, userdata); |
1031 | 40.2k | } |
1032 | | |
1033 | 40.9k | if (tcp_connection->kill_at <= mono_time_get(mono_time)) { |
1034 | 13 | tcp_connection->status = TCP_CLIENT_DISCONNECTED; |
1035 | 13 | } |
1036 | 40.9k | } |
1037 | | |
1038 | | /** Kill the TCP connection */ |
1039 | | void kill_tcp_connection(TCP_Client_Connection *tcp_connection) |
1040 | 99 | { |
1041 | 99 | if (tcp_connection == nullptr) { |
1042 | 1 | return; |
1043 | 1 | } |
1044 | | |
1045 | 98 | const Memory *mem = tcp_connection->con.mem; |
1046 | | |
1047 | 98 | wipe_priority_list(tcp_connection->con.mem, tcp_connection->con.priority_queue_start); |
1048 | 98 | kill_sock(tcp_connection->con.ns, tcp_connection->con.sock); |
1049 | 98 | crypto_memzero(tcp_connection, sizeof(TCP_Client_Connection)); |
1050 | 98 | mem_delete(mem, tcp_connection); |
1051 | 98 | } |