/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-2025 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 *response_callback; |
56 | | void *response_callback_object; |
57 | | tcp_routing_status_cb *status_callback; |
58 | | void *status_callback_object; |
59 | | tcp_routing_data_cb *data_callback; |
60 | | void *data_callback_object; |
61 | | tcp_oob_data_cb *oob_data_callback; |
62 | | void *oob_data_callback_object; |
63 | | |
64 | | tcp_onion_response_cb *onion_callback; |
65 | | void *onion_callback_object; |
66 | | |
67 | | forwarded_response_cb *forwarded_response_callback; |
68 | | void *forwarded_response_callback_object; |
69 | | |
70 | | /* Can be used by user. */ |
71 | | void *custom_object; |
72 | | uint32_t custom_uint; |
73 | | }; |
74 | | |
75 | | const uint8_t *tcp_con_public_key(const TCP_Client_Connection *con) |
76 | 591 | { |
77 | 591 | return con->public_key; |
78 | 591 | } |
79 | | |
80 | | IP_Port tcp_con_ip_port(const TCP_Client_Connection *con) |
81 | 471 | { |
82 | 471 | return con->ip_port; |
83 | 471 | } |
84 | | |
85 | | TCP_Client_Status tcp_con_status(const TCP_Client_Connection *con) |
86 | 12.8k | { |
87 | 12.8k | return con->status; |
88 | 12.8k | } |
89 | | void *tcp_con_custom_object(const TCP_Client_Connection *con) |
90 | 1.23k | { |
91 | 1.23k | return con->custom_object; |
92 | 1.23k | } |
93 | | uint32_t tcp_con_custom_uint(const TCP_Client_Connection *con) |
94 | 1.23k | { |
95 | 1.23k | return con->custom_uint; |
96 | 1.23k | } |
97 | | void tcp_con_set_custom_object(TCP_Client_Connection *con, void *object) |
98 | 58 | { |
99 | 58 | con->custom_object = object; |
100 | 58 | } |
101 | | void tcp_con_set_custom_uint(TCP_Client_Connection *con, uint32_t value) |
102 | 58 | { |
103 | 58 | con->custom_uint = value; |
104 | 58 | } |
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 | 69 | { |
113 | 69 | Net_Err_Connect err; |
114 | 69 | if (proxy_info->proxy_type != TCP_PROXY_NONE) { |
115 | 10 | net_connect(ns, mem, logger, sock, &proxy_info->ip_port, &err); |
116 | 59 | } else { |
117 | 59 | net_connect(ns, mem, logger, sock, ip_port, &err); |
118 | 59 | } |
119 | 69 | switch (err) { |
120 | 69 | case NET_ERR_CONNECT_OK: |
121 | 69 | case NET_ERR_CONNECT_FAILED: { |
122 | | /* nonblocking socket, connect will never return success */ |
123 | 69 | return true; |
124 | 69 | } |
125 | 0 | case NET_ERR_CONNECT_INVALID_FAMILY: |
126 | 0 | return false; |
127 | 69 | } |
128 | 0 | LOGGER_ERROR(logger, "unexpected error code %s from net_connect", net_err_connect_to_string(err)); |
129 | 0 | return false; |
130 | 69 | } |
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 | 1 | { |
138 | 1 | const char one[] = "CONNECT "; |
139 | 1 | const char two[] = " HTTP/1.1\nHost: "; |
140 | 1 | const char three[] = "\r\n\r\n"; |
141 | | |
142 | 1 | char ip[TOX_INET6_ADDRSTRLEN]; |
143 | | |
144 | 1 | if (!ip_parse_addr(&tcp_conn->ip_port.ip, ip, sizeof(ip))) { |
145 | 0 | return 0; |
146 | 0 | } |
147 | | |
148 | 1 | const uint16_t port = net_ntohs(tcp_conn->ip_port.port); |
149 | 1 | const int written = snprintf((char *)tcp_conn->con.last_packet, MAX_PACKET_SIZE, "%s%s:%hu%s%s:%hu%s", one, ip, port, |
150 | 1 | two, ip, port, three); |
151 | | |
152 | 1 | if (written < 0 || MAX_PACKET_SIZE < written) { |
153 | 0 | return 0; |
154 | 0 | } |
155 | | |
156 | 1 | tcp_conn->con.last_packet_length = written; |
157 | 1 | tcp_conn->con.last_packet_sent = 0; |
158 | 1 | return 1; |
159 | 1 | } |
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 | 9 | { |
217 | 9 | tcp_conn->con.last_packet[0] = TCP_SOCKS5_PROXY_HS_VERSION_SOCKS5; |
218 | 9 | tcp_conn->con.last_packet[1] = TCP_SOCKS5_PROXY_HS_AUTH_METHODS_SUPPORTED; |
219 | 9 | tcp_conn->con.last_packet[2] = TCP_SOCKS5_PROXY_HS_NO_AUTH; |
220 | | |
221 | 9 | tcp_conn->con.last_packet_length = 3; |
222 | 9 | tcp_conn->con.last_packet_sent = 0; |
223 | 9 | } |
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 | 61 | { |
315 | 61 | uint8_t plain[CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE]; |
316 | 61 | crypto_new_keypair(tcp_conn->con.rng, plain, tcp_conn->temp_secret_key); |
317 | 61 | random_nonce(tcp_conn->con.rng, tcp_conn->con.sent_nonce); |
318 | 61 | memcpy(plain + CRYPTO_PUBLIC_KEY_SIZE, tcp_conn->con.sent_nonce, CRYPTO_NONCE_SIZE); |
319 | 61 | memcpy(tcp_conn->con.last_packet, tcp_conn->self_public_key, CRYPTO_PUBLIC_KEY_SIZE); |
320 | 61 | random_nonce(tcp_conn->con.rng, tcp_conn->con.last_packet + CRYPTO_PUBLIC_KEY_SIZE); |
321 | 61 | 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 | 61 | sizeof(plain), tcp_conn->con.last_packet + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE); |
323 | | |
324 | 61 | if (len != sizeof(plain) + CRYPTO_MAC_SIZE) { |
325 | 0 | return -1; |
326 | 0 | } |
327 | | |
328 | 61 | tcp_conn->con.last_packet_length = CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE + sizeof(plain) + CRYPTO_MAC_SIZE; |
329 | 61 | tcp_conn->con.last_packet_sent = 0; |
330 | 61 | return 0; |
331 | 61 | } |
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 | 60 | { |
341 | 60 | uint8_t plain[CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE]; |
342 | 60 | const int len = decrypt_data_symmetric(tcp_conn->con.mem, tcp_conn->con.shared_key, data, data + CRYPTO_NONCE_SIZE, |
343 | 60 | TCP_SERVER_HANDSHAKE_SIZE - CRYPTO_NONCE_SIZE, plain); |
344 | | |
345 | 60 | if (len != sizeof(plain)) { |
346 | 0 | return -1; |
347 | 0 | } |
348 | | |
349 | 60 | memcpy(tcp_conn->recv_nonce, plain + CRYPTO_PUBLIC_KEY_SIZE, CRYPTO_NONCE_SIZE); |
350 | 60 | encrypt_precompute(plain, tcp_conn->temp_secret_key, tcp_conn->con.shared_key); |
351 | 60 | crypto_memzero(tcp_conn->temp_secret_key, CRYPTO_SECRET_KEY_SIZE); |
352 | 60 | return 0; |
353 | 60 | } |
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 | 109 | { |
362 | 109 | uint8_t packet[1 + CRYPTO_PUBLIC_KEY_SIZE]; |
363 | 109 | packet[0] = TCP_PACKET_ROUTING_REQUEST; |
364 | 109 | memcpy(packet + 1, public_key, CRYPTO_PUBLIC_KEY_SIZE); |
365 | 109 | return write_packet_tcp_secure_connection(logger, &con->con, packet, sizeof(packet), true); |
366 | 109 | } |
367 | | |
368 | | void routing_response_handler(TCP_Client_Connection *con, tcp_routing_response_cb *response_callback, void *object) |
369 | 59 | { |
370 | 59 | con->response_callback = response_callback; |
371 | 59 | con->response_callback_object = object; |
372 | 59 | } |
373 | | |
374 | | void routing_status_handler(TCP_Client_Connection *con, tcp_routing_status_cb *status_callback, void *object) |
375 | 59 | { |
376 | 59 | con->status_callback = status_callback; |
377 | 59 | con->status_callback_object = object; |
378 | 59 | } |
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.04k | { |
390 | 1.04k | if (con_id >= NUM_CLIENT_CONNECTIONS) { |
391 | 0 | return -1; |
392 | 0 | } |
393 | | |
394 | 1.04k | if (con->connections[con_id].status != 2) { |
395 | 0 | return -1; |
396 | 0 | } |
397 | | |
398 | 1.04k | if (tcp_send_ping_response(logger, con) == 0 || tcp_send_ping_request(logger, con) == 0) { |
399 | 0 | return 0; |
400 | 0 | } |
401 | | |
402 | 1.04k | const uint16_t packet_size = 1 + length; |
403 | 1.04k | VLA(uint8_t, packet, packet_size); |
404 | 1.04k | packet[0] = con_id + NUM_RESERVED_PORTS; |
405 | 1.04k | memcpy(packet + 1, data, length); |
406 | 1.04k | return write_packet_tcp_secure_connection(logger, &con->con, packet, packet_size, false); |
407 | 1.04k | } |
408 | | |
409 | | /** |
410 | | * @retval 1 on success. |
411 | | * @retval 0 if could not send packet. |
412 | | * @retval -1 on failure. |
413 | | */ |
414 | | int send_oob_packet(const Logger *logger, TCP_Client_Connection *con, const uint8_t *public_key, const uint8_t *data, |
415 | | uint16_t length) |
416 | 173 | { |
417 | 173 | if (length == 0 || length > TCP_MAX_OOB_DATA_LENGTH) { |
418 | 0 | return -1; |
419 | 0 | } |
420 | | |
421 | 173 | const uint16_t packet_size = 1 + CRYPTO_PUBLIC_KEY_SIZE + length; |
422 | 173 | VLA(uint8_t, packet, packet_size); |
423 | 173 | packet[0] = TCP_PACKET_OOB_SEND; |
424 | 173 | memcpy(packet + 1, public_key, CRYPTO_PUBLIC_KEY_SIZE); |
425 | 173 | memcpy(packet + 1 + CRYPTO_PUBLIC_KEY_SIZE, data, length); |
426 | 173 | return write_packet_tcp_secure_connection(logger, &con->con, packet, packet_size, false); |
427 | 173 | } |
428 | | |
429 | | /** @brief Set the number that will be used as an argument in the callbacks related to con_id. |
430 | | * |
431 | | * When not set by this function, the number is -1. |
432 | | * |
433 | | * return 0 on success. |
434 | | * return -1 on failure. |
435 | | */ |
436 | | int set_tcp_connection_number(TCP_Client_Connection *con, uint8_t con_id, uint32_t number) |
437 | 108 | { |
438 | 108 | if (con_id >= NUM_CLIENT_CONNECTIONS) { |
439 | 0 | return -1; |
440 | 0 | } |
441 | | |
442 | 108 | if (con->connections[con_id].status == 0) { |
443 | 0 | return -1; |
444 | 0 | } |
445 | | |
446 | 108 | con->connections[con_id].number = number; |
447 | 108 | return 0; |
448 | 108 | } |
449 | | |
450 | | void routing_data_handler(TCP_Client_Connection *con, tcp_routing_data_cb *data_callback, void *object) |
451 | 59 | { |
452 | 59 | con->data_callback = data_callback; |
453 | 59 | con->data_callback_object = object; |
454 | 59 | } |
455 | | |
456 | | void oob_data_handler(TCP_Client_Connection *con, tcp_oob_data_cb *oob_data_callback, void *object) |
457 | 59 | { |
458 | 59 | con->oob_data_callback = oob_data_callback; |
459 | 59 | con->oob_data_callback_object = object; |
460 | 59 | } |
461 | | |
462 | | /** |
463 | | * @retval 1 on success. |
464 | | * @retval 0 if could not send packet. |
465 | | * @retval -1 on failure (connection must be killed). |
466 | | */ |
467 | | static int client_send_disconnect_notification(const Logger *_Nonnull logger, TCP_Client_Connection *_Nonnull con, uint8_t id) |
468 | 108 | { |
469 | 108 | uint8_t packet[1 + 1]; |
470 | 108 | packet[0] = TCP_PACKET_DISCONNECT_NOTIFICATION; |
471 | 108 | packet[1] = id; |
472 | 108 | return write_packet_tcp_secure_connection(logger, &con->con, packet, sizeof(packet), true); |
473 | 108 | } |
474 | | |
475 | | /** |
476 | | * @retval 1 on success. |
477 | | * @retval 0 if could not send packet. |
478 | | * @retval -1 on failure (connection must be killed). |
479 | | */ |
480 | | static int tcp_send_ping_request(const Logger *_Nonnull logger, TCP_Client_Connection *_Nonnull con) |
481 | 13.0k | { |
482 | 13.0k | if (con->ping_request_id == 0) { |
483 | 13.0k | return 1; |
484 | 13.0k | } |
485 | | |
486 | 65 | uint8_t packet[1 + sizeof(uint64_t)]; |
487 | 65 | packet[0] = TCP_PACKET_PING; |
488 | 65 | memcpy(packet + 1, &con->ping_request_id, sizeof(uint64_t)); |
489 | 65 | const int ret = write_packet_tcp_secure_connection(logger, &con->con, packet, sizeof(packet), true); |
490 | | |
491 | 65 | if (ret == 1) { |
492 | 65 | con->ping_request_id = 0; |
493 | 65 | } |
494 | | |
495 | 65 | return ret; |
496 | 13.0k | } |
497 | | |
498 | | /** |
499 | | * @retval 1 on success. |
500 | | * @retval 0 if could not send packet. |
501 | | * @retval -1 on failure (connection must be killed). |
502 | | */ |
503 | | static int tcp_send_ping_response(const Logger *_Nonnull logger, TCP_Client_Connection *_Nonnull con) |
504 | 13.0k | { |
505 | 13.0k | if (con->ping_response_id == 0) { |
506 | 13.0k | return 1; |
507 | 13.0k | } |
508 | | |
509 | 15 | uint8_t packet[1 + sizeof(uint64_t)]; |
510 | 15 | packet[0] = TCP_PACKET_PONG; |
511 | 15 | memcpy(packet + 1, &con->ping_response_id, sizeof(uint64_t)); |
512 | 15 | const int ret = write_packet_tcp_secure_connection(logger, &con->con, packet, sizeof(packet), true); |
513 | | |
514 | 15 | if (ret == 1) { |
515 | 15 | con->ping_response_id = 0; |
516 | 15 | } |
517 | | |
518 | 15 | return ret; |
519 | 13.0k | } |
520 | | |
521 | | /** |
522 | | * @retval 1 on success. |
523 | | * @retval 0 if could not send packet. |
524 | | * @retval -1 on failure (connection must be killed). |
525 | | */ |
526 | | int send_disconnect_request(const Logger *logger, TCP_Client_Connection *con, uint8_t con_id) |
527 | 108 | { |
528 | 108 | if (con_id >= NUM_CLIENT_CONNECTIONS) { |
529 | 0 | return -1; |
530 | 0 | } |
531 | | |
532 | 108 | con->connections[con_id].status = 0; |
533 | 108 | con->connections[con_id].number = 0; |
534 | 108 | return client_send_disconnect_notification(logger, con, con_id + NUM_RESERVED_PORTS); |
535 | 108 | } |
536 | | |
537 | | /** |
538 | | * @retval 1 on success. |
539 | | * @retval 0 if could not send packet. |
540 | | * @retval -1 on failure (connection must be killed). |
541 | | */ |
542 | | int send_onion_request(const Logger *logger, TCP_Client_Connection *con, const uint8_t *data, uint16_t length) |
543 | 1.00k | { |
544 | 1.00k | const uint16_t packet_size = 1 + length; |
545 | 1.00k | VLA(uint8_t, packet, packet_size); |
546 | 1.00k | packet[0] = TCP_PACKET_ONION_REQUEST; |
547 | 1.00k | memcpy(packet + 1, data, length); |
548 | 1.00k | return write_packet_tcp_secure_connection(logger, &con->con, packet, packet_size, false); |
549 | 1.00k | } |
550 | | |
551 | | void onion_response_handler(TCP_Client_Connection *con, tcp_onion_response_cb *onion_callback, void *object) |
552 | 58 | { |
553 | 58 | con->onion_callback = onion_callback; |
554 | 58 | con->onion_callback_object = object; |
555 | 58 | } |
556 | | |
557 | | /** @retval 1 on success. |
558 | | * @retval 0 if could not send packet. |
559 | | * @retval -1 on failure (connection must be killed). |
560 | | */ |
561 | | int send_forward_request_tcp(const Logger *logger, TCP_Client_Connection *con, const IP_Port *dest, const uint8_t *data, uint16_t length) |
562 | 5 | { |
563 | 5 | if (length > MAX_FORWARD_DATA_SIZE) { |
564 | 0 | return -1; |
565 | 0 | } |
566 | | |
567 | 5 | VLA(uint8_t, packet, 1 + MAX_PACKED_IPPORT_SIZE + length); |
568 | 5 | packet[0] = TCP_PACKET_FORWARD_REQUEST; |
569 | 5 | const int ipport_length = pack_ip_port(logger, packet + 1, MAX_PACKED_IPPORT_SIZE, dest); |
570 | | |
571 | 5 | if (ipport_length == -1) { |
572 | 0 | return 0; |
573 | 0 | } |
574 | | |
575 | 5 | memcpy(packet + 1 + ipport_length, data, length); |
576 | 5 | return write_packet_tcp_secure_connection(logger, &con->con, packet, 1 + ipport_length + length, false); |
577 | 5 | } |
578 | | |
579 | | void forwarding_handler(TCP_Client_Connection *con, forwarded_response_cb *forwarded_response_callback, void *object) |
580 | 58 | { |
581 | 58 | con->forwarded_response_callback = forwarded_response_callback; |
582 | 58 | con->forwarded_response_callback_object = object; |
583 | 58 | } |
584 | | |
585 | | /** Create new TCP connection to ip_port/public_key */ |
586 | | TCP_Client_Connection *new_tcp_connection( |
587 | | const Logger *logger, const Memory *mem, const Mono_Time *mono_time, const Random *rng, const Network *ns, |
588 | | const IP_Port *ip_port, const uint8_t *public_key, const uint8_t *self_public_key, const uint8_t *self_secret_key, |
589 | | const TCP_Proxy_Info *proxy_info, Net_Profile *_Nullable net_profile) |
590 | 69 | { |
591 | 69 | assert(logger != nullptr); |
592 | 69 | assert(mem != nullptr); |
593 | 69 | assert(mono_time != nullptr); |
594 | 69 | assert(rng != nullptr); |
595 | 69 | assert(ns != nullptr); |
596 | | |
597 | 69 | if (!net_family_is_ipv4(ip_port->ip.family) && !net_family_is_ipv6(ip_port->ip.family)) { |
598 | 0 | LOGGER_ERROR(logger, "Invalid IP family: %d", ip_port->ip.family.value); |
599 | 0 | return nullptr; |
600 | 0 | } |
601 | | |
602 | 69 | const TCP_Proxy_Info default_proxyinfo = {{{{0}}}}; |
603 | | |
604 | 69 | if (proxy_info == nullptr) { |
605 | 3 | proxy_info = &default_proxyinfo; |
606 | 3 | } |
607 | | |
608 | 69 | Family family = ip_port->ip.family; |
609 | | |
610 | 69 | if (proxy_info->proxy_type != TCP_PROXY_NONE) { |
611 | 10 | family = proxy_info->ip_port.ip.family; |
612 | 10 | } |
613 | | |
614 | 69 | const Socket sock = net_socket(ns, family, TOX_SOCK_STREAM, TOX_PROTO_TCP); |
615 | | |
616 | 69 | if (!sock_valid(sock)) { |
617 | 0 | LOGGER_ERROR(logger, "Failed to create TCP socket with family %d", family.value); |
618 | 0 | return nullptr; |
619 | 0 | } |
620 | | |
621 | 69 | if (!set_socket_nosigpipe(ns, sock)) { |
622 | 0 | LOGGER_ERROR(logger, "Failed to set TCP socket to ignore SIGPIPE"); |
623 | 0 | kill_sock(ns, sock); |
624 | 0 | return nullptr; |
625 | 0 | } |
626 | | |
627 | 69 | if (!set_socket_nonblock(ns, sock)) { |
628 | 0 | LOGGER_ERROR(logger, "Failed to set TCP socket to non-blocking"); |
629 | 0 | kill_sock(ns, sock); |
630 | 0 | return nullptr; |
631 | 0 | } |
632 | | |
633 | 69 | if (!connect_sock_to(ns, logger, mem, sock, ip_port, proxy_info)) { |
634 | 0 | Ip_Ntoa ip_ntoa; |
635 | 0 | LOGGER_WARNING(logger, "Failed to connect TCP socket to %s:%u", |
636 | 0 | net_ip_ntoa(&ip_port->ip, &ip_ntoa), net_ntohs(ip_port->port)); |
637 | 0 | kill_sock(ns, sock); |
638 | 0 | return nullptr; |
639 | 0 | } |
640 | | |
641 | 69 | TCP_Client_Connection *temp = (TCP_Client_Connection *)mem_alloc(mem, sizeof(TCP_Client_Connection)); |
642 | | |
643 | 69 | if (temp == nullptr) { |
644 | 0 | LOGGER_ERROR(logger, "Failed to allocate memory for TCP_Client_Connection"); |
645 | 0 | kill_sock(ns, sock); |
646 | 0 | return nullptr; |
647 | 0 | } |
648 | | |
649 | 69 | temp->con.ns = ns; |
650 | 69 | temp->con.mem = mem; |
651 | 69 | temp->con.rng = rng; |
652 | 69 | temp->con.sock = sock; |
653 | 69 | temp->con.ip_port = *ip_port; |
654 | 69 | temp->con.net_profile = net_profile; |
655 | 69 | memcpy(temp->public_key, public_key, CRYPTO_PUBLIC_KEY_SIZE); |
656 | 69 | memcpy(temp->self_public_key, self_public_key, CRYPTO_PUBLIC_KEY_SIZE); |
657 | 69 | encrypt_precompute(temp->public_key, self_secret_key, temp->con.shared_key); |
658 | 69 | temp->ip_port = *ip_port; |
659 | 69 | temp->proxy_info = *proxy_info; |
660 | | |
661 | 69 | switch (proxy_info->proxy_type) { |
662 | 1 | case TCP_PROXY_HTTP: { |
663 | 1 | temp->status = TCP_CLIENT_PROXY_HTTP_CONNECTING; |
664 | 1 | proxy_http_generate_connection_request(temp); |
665 | 1 | break; |
666 | 0 | } |
667 | | |
668 | 9 | case TCP_PROXY_SOCKS5: { |
669 | 9 | temp->status = TCP_CLIENT_PROXY_SOCKS5_CONNECTING; |
670 | 9 | proxy_socks5_generate_greetings(temp); |
671 | 9 | break; |
672 | 0 | } |
673 | | |
674 | 59 | case TCP_PROXY_NONE: { |
675 | 59 | temp->status = TCP_CLIENT_CONNECTING; |
676 | | |
677 | 59 | if (generate_handshake(temp) == -1) { |
678 | 0 | LOGGER_ERROR(logger, "Failed to generate handshake"); |
679 | 0 | kill_sock(ns, sock); |
680 | 0 | mem_delete(mem, temp); |
681 | 0 | return nullptr; |
682 | 0 | } |
683 | | |
684 | 59 | break; |
685 | 59 | } |
686 | 69 | } |
687 | | |
688 | 69 | temp->kill_at = mono_time_get(mono_time) + TCP_CONNECTION_TIMEOUT; |
689 | | |
690 | 69 | return temp; |
691 | 69 | } |
692 | | |
693 | | static int handle_tcp_client_routing_response(TCP_Client_Connection *_Nonnull conn, const uint8_t *_Nonnull data, uint16_t length) |
694 | 109 | { |
695 | 109 | if (length != 1 + 1 + CRYPTO_PUBLIC_KEY_SIZE) { |
696 | 0 | return -1; |
697 | 0 | } |
698 | | |
699 | 109 | if (data[1] < NUM_RESERVED_PORTS) { |
700 | 0 | return 0; |
701 | 0 | } |
702 | | |
703 | 109 | const uint8_t con_id = data[1] - NUM_RESERVED_PORTS; |
704 | | |
705 | 109 | if (conn->connections[con_id].status != 0) { |
706 | 0 | return 0; |
707 | 0 | } |
708 | | |
709 | 109 | conn->connections[con_id].status = 1; |
710 | 109 | conn->connections[con_id].number = -1; |
711 | 109 | memcpy(conn->connections[con_id].public_key, data + 2, CRYPTO_PUBLIC_KEY_SIZE); |
712 | | |
713 | 109 | if (conn->response_callback != nullptr) { |
714 | 108 | conn->response_callback(conn->response_callback_object, con_id, conn->connections[con_id].public_key); |
715 | 108 | } |
716 | | |
717 | 109 | return 0; |
718 | 109 | } |
719 | | |
720 | | static int handle_tcp_client_connection_notification(TCP_Client_Connection *_Nonnull conn, const uint8_t *_Nonnull data, uint16_t length) |
721 | 108 | { |
722 | 108 | if (length != 1 + 1) { |
723 | 0 | return -1; |
724 | 0 | } |
725 | | |
726 | 108 | if (data[1] < NUM_RESERVED_PORTS) { |
727 | 0 | return -1; |
728 | 0 | } |
729 | | |
730 | 108 | const uint8_t con_id = data[1] - NUM_RESERVED_PORTS; |
731 | | |
732 | 108 | if (conn->connections[con_id].status != 1) { |
733 | 0 | return 0; |
734 | 0 | } |
735 | | |
736 | 108 | conn->connections[con_id].status = 2; |
737 | | |
738 | 108 | if (conn->status_callback != nullptr) { |
739 | 107 | conn->status_callback(conn->status_callback_object, conn->connections[con_id].number, con_id, |
740 | 107 | conn->connections[con_id].status); |
741 | 107 | } |
742 | | |
743 | 108 | return 0; |
744 | 108 | } |
745 | | |
746 | | static int handle_tcp_client_disconnect_notification(TCP_Client_Connection *_Nonnull conn, const uint8_t *_Nonnull data, uint16_t length) |
747 | 2 | { |
748 | 2 | if (length != 1 + 1) { |
749 | 0 | return -1; |
750 | 0 | } |
751 | | |
752 | 2 | if (data[1] < NUM_RESERVED_PORTS) { |
753 | 0 | return -1; |
754 | 0 | } |
755 | | |
756 | 2 | const uint8_t con_id = data[1] - NUM_RESERVED_PORTS; |
757 | | |
758 | 2 | if (conn->connections[con_id].status == 0) { |
759 | 0 | return 0; |
760 | 0 | } |
761 | | |
762 | 2 | if (conn->connections[con_id].status != 2) { |
763 | 0 | return 0; |
764 | 0 | } |
765 | | |
766 | 2 | conn->connections[con_id].status = 1; |
767 | | |
768 | 2 | if (conn->status_callback != nullptr) { |
769 | 2 | conn->status_callback(conn->status_callback_object, conn->connections[con_id].number, con_id, |
770 | 2 | conn->connections[con_id].status); |
771 | 2 | } |
772 | | |
773 | 2 | return 0; |
774 | 2 | } |
775 | | |
776 | | static int handle_tcp_client_ping(const Logger *_Nonnull logger, TCP_Client_Connection *_Nonnull conn, const uint8_t *_Nonnull data, uint16_t length) |
777 | 15 | { |
778 | 15 | if (length != 1 + sizeof(uint64_t)) { |
779 | 0 | return -1; |
780 | 0 | } |
781 | | |
782 | 15 | uint64_t ping_id; |
783 | 15 | memcpy(&ping_id, data + 1, sizeof(uint64_t)); |
784 | 15 | conn->ping_response_id = ping_id; |
785 | 15 | tcp_send_ping_response(logger, conn); |
786 | 15 | return 0; |
787 | 15 | } |
788 | | |
789 | | static int handle_tcp_client_pong(TCP_Client_Connection *_Nonnull conn, const uint8_t *_Nonnull data, uint16_t length) |
790 | 65 | { |
791 | 65 | if (length != 1 + sizeof(uint64_t)) { |
792 | 0 | return -1; |
793 | 0 | } |
794 | | |
795 | 65 | uint64_t ping_id; |
796 | 65 | memcpy(&ping_id, data + 1, sizeof(uint64_t)); |
797 | | |
798 | 65 | if (ping_id != 0) { |
799 | 65 | if (ping_id == conn->ping_id) { |
800 | 65 | conn->ping_id = 0; |
801 | 65 | } |
802 | | |
803 | 65 | return 0; |
804 | 65 | } |
805 | | |
806 | 0 | return -1; |
807 | 65 | } |
808 | | |
809 | | static int handle_tcp_client_oob_recv(TCP_Client_Connection *_Nonnull conn, const uint8_t *_Nonnull data, uint16_t length, void *_Nullable userdata) |
810 | 173 | { |
811 | 173 | if (length <= 1 + CRYPTO_PUBLIC_KEY_SIZE) { |
812 | 0 | return -1; |
813 | 0 | } |
814 | | |
815 | 173 | if (conn->oob_data_callback != nullptr) { |
816 | 173 | conn->oob_data_callback(conn->oob_data_callback_object, data + 1, data + 1 + CRYPTO_PUBLIC_KEY_SIZE, |
817 | 173 | length - (1 + CRYPTO_PUBLIC_KEY_SIZE), userdata); |
818 | 173 | } |
819 | | |
820 | 173 | return 0; |
821 | 173 | } |
822 | | |
823 | | /** |
824 | | * @retval 0 on success |
825 | | * @retval -1 on failure |
826 | | */ |
827 | | static int handle_tcp_client_packet(const Logger *_Nonnull logger, TCP_Client_Connection *_Nonnull conn, const uint8_t *_Nonnull data, |
828 | | uint16_t length, void *_Nullable userdata) |
829 | 2.05k | { |
830 | 2.05k | if (length <= 1) { |
831 | 0 | return -1; |
832 | 0 | } |
833 | | |
834 | 2.05k | netprof_record_packet(conn->con.net_profile, data[0], length, PACKET_DIRECTION_RECV); |
835 | | |
836 | 2.05k | switch (data[0]) { |
837 | 109 | case TCP_PACKET_ROUTING_RESPONSE: |
838 | 109 | return handle_tcp_client_routing_response(conn, data, length); |
839 | | |
840 | 108 | case TCP_PACKET_CONNECTION_NOTIFICATION: |
841 | 108 | return handle_tcp_client_connection_notification(conn, data, length); |
842 | | |
843 | 2 | case TCP_PACKET_DISCONNECT_NOTIFICATION: |
844 | 2 | return handle_tcp_client_disconnect_notification(conn, data, length); |
845 | | |
846 | 15 | case TCP_PACKET_PING: |
847 | 15 | return handle_tcp_client_ping(logger, conn, data, length); |
848 | | |
849 | 65 | case TCP_PACKET_PONG: |
850 | 65 | return handle_tcp_client_pong(conn, data, length); |
851 | | |
852 | 173 | case TCP_PACKET_OOB_RECV: |
853 | 173 | return handle_tcp_client_oob_recv(conn, data, length, userdata); |
854 | | |
855 | 803 | case TCP_PACKET_ONION_RESPONSE: { |
856 | 803 | if (conn->onion_callback != nullptr) { |
857 | 803 | conn->onion_callback(conn->onion_callback_object, data + 1, length - 1, userdata); |
858 | 803 | } |
859 | 803 | return 0; |
860 | 0 | } |
861 | | |
862 | 5 | case TCP_PACKET_FORWARDING: { |
863 | 5 | if (conn->forwarded_response_callback != nullptr) { |
864 | 5 | conn->forwarded_response_callback(conn->forwarded_response_callback_object, data + 1, length - 1, userdata); |
865 | 5 | } |
866 | 5 | return 0; |
867 | 0 | } |
868 | | |
869 | 778 | default: { |
870 | 778 | if (data[0] < NUM_RESERVED_PORTS) { |
871 | 0 | return -1; |
872 | 0 | } |
873 | | |
874 | 778 | const uint8_t con_id = data[0] - NUM_RESERVED_PORTS; |
875 | | |
876 | 778 | if (conn->data_callback != nullptr) { |
877 | 778 | conn->data_callback(conn->data_callback_object, conn->connections[con_id].number, con_id, data + 1, length - 1, |
878 | 778 | userdata); |
879 | 778 | } |
880 | 778 | } |
881 | 2.05k | } |
882 | | |
883 | 778 | return 0; |
884 | 2.05k | } |
885 | | |
886 | | static bool tcp_process_packet(const Logger *_Nonnull logger, TCP_Client_Connection *_Nonnull conn, void *_Nullable userdata) |
887 | 14.0k | { |
888 | 14.0k | uint8_t packet[MAX_PACKET_SIZE]; |
889 | 14.0k | 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), |
890 | 14.0k | &conn->ip_port); |
891 | | |
892 | 14.0k | if (len == 0) { |
893 | 11.9k | return false; |
894 | 11.9k | } |
895 | | |
896 | 2.05k | if (len == -1) { |
897 | 0 | conn->status = TCP_CLIENT_DISCONNECTED; |
898 | 0 | return false; |
899 | 0 | } |
900 | | |
901 | 2.05k | if (handle_tcp_client_packet(logger, conn, packet, len, userdata) == -1) { |
902 | 0 | conn->status = TCP_CLIENT_DISCONNECTED; |
903 | 0 | return false; |
904 | 0 | } |
905 | | |
906 | 2.05k | return true; |
907 | 2.05k | } |
908 | | |
909 | | static int do_confirmed_tcp(const Logger *_Nonnull logger, TCP_Client_Connection *_Nonnull conn, const Mono_Time *_Nonnull mono_time, |
910 | | void *_Nullable userdata) |
911 | 11.9k | { |
912 | 11.9k | send_pending_data(logger, &conn->con); |
913 | 11.9k | tcp_send_ping_response(logger, conn); |
914 | 11.9k | tcp_send_ping_request(logger, conn); |
915 | | |
916 | 11.9k | if (mono_time_is_timeout(mono_time, conn->last_pinged, TCP_PING_FREQUENCY)) { |
917 | 65 | uint64_t ping_id = random_u64(conn->con.rng); |
918 | | |
919 | 65 | if (ping_id == 0) { |
920 | 0 | ++ping_id; |
921 | 0 | } |
922 | | |
923 | 65 | conn->ping_request_id = ping_id; |
924 | 65 | conn->ping_id = ping_id; |
925 | 65 | tcp_send_ping_request(logger, conn); |
926 | 65 | conn->last_pinged = mono_time_get(mono_time); |
927 | 65 | } |
928 | | |
929 | 11.9k | if (conn->ping_id != 0 && mono_time_is_timeout(mono_time, conn->last_pinged, TCP_PING_TIMEOUT)) { |
930 | 0 | conn->status = TCP_CLIENT_DISCONNECTED; |
931 | 0 | return 0; |
932 | 0 | } |
933 | | |
934 | 14.0k | while (tcp_process_packet(logger, conn, userdata)) { |
935 | | /* Keep reading until error or out of data. */ |
936 | 2.05k | } |
937 | | |
938 | 11.9k | return 0; |
939 | 11.9k | } |
940 | | |
941 | | /** Run the TCP connection */ |
942 | | void do_tcp_connection(const Logger *logger, const Mono_Time *mono_time, |
943 | | TCP_Client_Connection *tcp_connection, void *userdata) |
944 | 12.3k | { |
945 | 12.3k | if (tcp_connection->status == TCP_CLIENT_DISCONNECTED) { |
946 | 0 | return; |
947 | 0 | } |
948 | | |
949 | 12.3k | if (tcp_connection->status == TCP_CLIENT_PROXY_HTTP_CONNECTING) { |
950 | 2 | if (send_pending_data(logger, &tcp_connection->con) == 0) { |
951 | 2 | const int ret = proxy_http_read_connection_response(logger, tcp_connection); |
952 | | |
953 | 2 | if (ret == -1) { |
954 | 0 | tcp_connection->kill_at = 0; |
955 | 0 | tcp_connection->status = TCP_CLIENT_DISCONNECTED; |
956 | 0 | } |
957 | | |
958 | 2 | if (ret == 1) { |
959 | 1 | generate_handshake(tcp_connection); |
960 | 1 | tcp_connection->status = TCP_CLIENT_CONNECTING; |
961 | 1 | } |
962 | 2 | } |
963 | 2 | } |
964 | | |
965 | 12.3k | if (tcp_connection->status == TCP_CLIENT_PROXY_SOCKS5_CONNECTING) { |
966 | 346 | if (send_pending_data(logger, &tcp_connection->con) == 0) { |
967 | 2 | const int ret = socks5_read_handshake_response(logger, tcp_connection); |
968 | | |
969 | 2 | if (ret == -1) { |
970 | 0 | tcp_connection->kill_at = 0; |
971 | 0 | tcp_connection->status = TCP_CLIENT_DISCONNECTED; |
972 | 0 | } |
973 | | |
974 | 2 | if (ret == 1) { |
975 | 1 | proxy_socks5_generate_connection_request(tcp_connection); |
976 | 1 | tcp_connection->status = TCP_CLIENT_PROXY_SOCKS5_UNCONFIRMED; |
977 | 1 | } |
978 | 2 | } |
979 | 346 | } |
980 | | |
981 | 12.3k | if (tcp_connection->status == TCP_CLIENT_PROXY_SOCKS5_UNCONFIRMED) { |
982 | 2 | if (send_pending_data(logger, &tcp_connection->con) == 0) { |
983 | 2 | const int ret = proxy_socks5_read_connection_response(logger, tcp_connection); |
984 | | |
985 | 2 | if (ret == -1) { |
986 | 0 | tcp_connection->kill_at = 0; |
987 | 0 | tcp_connection->status = TCP_CLIENT_DISCONNECTED; |
988 | 0 | } |
989 | | |
990 | 2 | if (ret == 1) { |
991 | 1 | generate_handshake(tcp_connection); |
992 | 1 | tcp_connection->status = TCP_CLIENT_CONNECTING; |
993 | 1 | } |
994 | 2 | } |
995 | 2 | } |
996 | | |
997 | 12.3k | if (tcp_connection->status == TCP_CLIENT_CONNECTING) { |
998 | 63 | if (send_pending_data(logger, &tcp_connection->con) == 0) { |
999 | 60 | tcp_connection->status = TCP_CLIENT_UNCONFIRMED; |
1000 | 60 | } |
1001 | 63 | } |
1002 | | |
1003 | 12.3k | if (tcp_connection->status == TCP_CLIENT_UNCONFIRMED) { |
1004 | 122 | uint8_t data[TCP_SERVER_HANDSHAKE_SIZE]; |
1005 | 122 | const TCP_Connection *con = &tcp_connection->con; |
1006 | 122 | const int len = read_tcp_packet(logger, con->mem, con->ns, con->sock, data, sizeof(data), &con->ip_port); |
1007 | | |
1008 | 122 | if (sizeof(data) == len) { |
1009 | 60 | if (handle_handshake(tcp_connection, data) == 0) { |
1010 | 60 | tcp_connection->kill_at = UINT64_MAX; |
1011 | 60 | tcp_connection->status = TCP_CLIENT_CONFIRMED; |
1012 | 60 | } else { |
1013 | 0 | tcp_connection->kill_at = 0; |
1014 | 0 | tcp_connection->status = TCP_CLIENT_DISCONNECTED; |
1015 | 0 | } |
1016 | 60 | } |
1017 | 122 | } |
1018 | | |
1019 | 12.3k | if (tcp_connection->status == TCP_CLIENT_CONFIRMED) { |
1020 | 11.9k | do_confirmed_tcp(logger, tcp_connection, mono_time, userdata); |
1021 | 11.9k | } |
1022 | | |
1023 | 12.3k | if (tcp_connection->kill_at <= mono_time_get(mono_time)) { |
1024 | 9 | tcp_connection->status = TCP_CLIENT_DISCONNECTED; |
1025 | 9 | } |
1026 | 12.3k | } |
1027 | | |
1028 | | /** Kill the TCP connection */ |
1029 | | void kill_tcp_connection(TCP_Client_Connection *tcp_connection) |
1030 | 69 | { |
1031 | 69 | if (tcp_connection == nullptr) { |
1032 | 0 | return; |
1033 | 0 | } |
1034 | | |
1035 | 69 | const Memory *mem = tcp_connection->con.mem; |
1036 | | |
1037 | 69 | wipe_priority_list(tcp_connection->con.mem, tcp_connection->con.priority_queue_start); |
1038 | 69 | kill_sock(tcp_connection->con.ns, tcp_connection->con.sock); |
1039 | 69 | crypto_memzero(tcp_connection, sizeof(TCP_Client_Connection)); |
1040 | 69 | mem_delete(mem, tcp_connection); |
1041 | 69 | } |