Coverage Report

Created: 2026-10-24 08:16

/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
}