Coverage Report

Created: 2026-10-24 08:16

/work/toxcore/TCP_common.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
#include "TCP_common.h"
7
8
#include <string.h>
9
10
#include "attributes.h"
11
#include "ccompat.h"
12
#include "crypto_core.h"
13
#include "logger.h"
14
#include "mem.h"
15
#include "network.h"
16
17
void wipe_priority_list(const Memory *mem, TCP_Priority_List *p)
18
167
{
19
170
    while (p != nullptr) {
20
3
        TCP_Priority_List *pp = p;
21
3
        p = p->next;
22
3
        mem_delete(mem, pp->data);
23
3
        mem_delete(mem, pp);
24
3
    }
25
167
}
26
27
/**
28
 * @retval 0 if pending data was sent completely
29
 * @retval -1 if it wasn't
30
 */
31
int send_pending_data_nonpriority(const Logger *logger, TCP_Connection *con)
32
59.7k
{
33
59.7k
    if (con->last_packet_length == 0) {
34
59.1k
        return 0;
35
59.1k
    }
36
37
637
    const uint16_t left = con->last_packet_length - con->last_packet_sent;
38
637
    const int len = net_send(con->ns, logger, con->sock, con->last_packet + con->last_packet_sent, left, &con->ip_port,
39
637
                             con->net_profile);
40
41
637
    if (len <= 0) {
42
596
        return -1;
43
596
    }
44
45
67
    if (len == left) {
46
67
        con->last_packet_length = 0;
47
67
        con->last_packet_sent = 0;
48
67
        return 0;
49
67
    }
50
51
18.4E
    con->last_packet_sent += len;
52
18.4E
    return -1;
53
41
}
54
55
/**
56
 * @retval 0 if pending data was sent completely
57
 * @retval -1 if it wasn't
58
 */
59
int send_pending_data(const Logger *logger, TCP_Connection *con)
60
59.7k
{
61
    /* finish sending current non-priority packet */
62
59.7k
    if (send_pending_data_nonpriority(logger, con) == -1) {
63
596
        return -1;
64
596
    }
65
66
59.1k
    TCP_Priority_List *p = con->priority_queue_start;
67
68
59.1k
    while (p != nullptr) {
69
2
        const uint16_t left = p->size - p->sent;
70
2
        const int len = net_send(con->ns, logger, con->sock, p->data + p->sent, left, &con->ip_port, con->net_profile);
71
72
2
        if (len != left) {
73
2
            if (len > 0) {
74
0
                p->sent += len;
75
0
            }
76
77
2
            break;
78
2
        }
79
80
0
        TCP_Priority_List *pp = p;
81
0
        p = p->next;
82
0
        mem_delete(con->mem, pp->data);
83
0
        mem_delete(con->mem, pp);
84
0
    }
85
86
59.1k
    con->priority_queue_start = p;
87
88
59.1k
    if (p == nullptr) {
89
59.1k
        con->priority_queue_end = nullptr;
90
59.1k
        return 0;
91
59.1k
    }
92
93
18.4E
    return -1;
94
59.1k
}
95
96
/**
97
 * @retval false on failure (only if mem_alloc fails)
98
 * @retval true on success
99
 */
100
static bool add_priority(TCP_Connection *_Nonnull con, const uint8_t *_Nonnull packet, uint16_t size, uint16_t sent)
101
3
{
102
3
    TCP_Priority_List *p = con->priority_queue_end;
103
3
    TCP_Priority_List *new_list = (TCP_Priority_List *)mem_alloc(con->mem, sizeof(TCP_Priority_List));
104
105
3
    if (new_list == nullptr) {
106
0
        return false;
107
0
    }
108
109
3
    uint8_t *data = (uint8_t *)mem_balloc(con->mem, size);
110
111
3
    if (data == nullptr) {
112
0
        mem_delete(con->mem, new_list);
113
0
        return false;
114
0
    }
115
116
3
    memcpy(data, packet, size);
117
3
    new_list->data = data;
118
3
    new_list->size = size;
119
120
3
    new_list->next = nullptr;
121
3
    new_list->sent = sent;
122
123
3
    if (p != nullptr) {
124
2
        p->next = new_list;
125
2
    } else {
126
1
        con->priority_queue_start = new_list;
127
1
    }
128
129
3
    con->priority_queue_end = new_list;
130
3
    return true;
131
3
}
132
133
/**
134
 * @retval 1 on success.
135
 * @retval 0 if could not send packet.
136
 * @retval -1 on failure (connection must be killed).
137
 */
138
int write_packet_tcp_secure_connection(const Logger *logger, TCP_Connection *con, const uint8_t *data, uint16_t length,
139
                                       bool priority)
140
16.8k
{
141
16.8k
    if (length + CRYPTO_MAC_SIZE > MAX_PACKET_SIZE) {
142
0
        return -1;
143
0
    }
144
145
16.8k
    bool sendpriority = true;
146
147
16.8k
    if (send_pending_data(logger, con) == -1) {
148
2
        if (priority) {
149
2
            sendpriority = false;
150
2
        } else {
151
0
            return 0;
152
0
        }
153
2
    }
154
155
16.8k
    const uint16_t packet_size = sizeof(uint16_t) + length + CRYPTO_MAC_SIZE;
156
16.8k
    VLA(uint8_t, packet, packet_size);
157
158
16.8k
    uint16_t c_length = net_htons(length + CRYPTO_MAC_SIZE);
159
16.8k
    memcpy(packet, &c_length, sizeof(uint16_t));
160
16.8k
    int len = encrypt_data_symmetric(con->mem, con->shared_key, con->sent_nonce, data, length, packet + sizeof(uint16_t));
161
162
16.8k
    if ((unsigned int)len != (packet_size - sizeof(uint16_t))) {
163
0
        return -1;
164
0
    }
165
166
16.8k
    if (priority) {
167
758
        len = sendpriority ? net_send(con->ns, logger, con->sock, packet, packet_size, &con->ip_port,
168
756
                                      con->net_profile) : 0;
169
170
758
        if (len <= 0) {
171
3
            len = 0;
172
3
        }
173
174
758
        increment_nonce(con->sent_nonce);
175
176
758
        if ((unsigned int)len == packet_size) {
177
755
            return 1;
178
755
        }
179
180
3
        return add_priority(con, packet, packet_size, len) ? 1 : 0;
181
758
    }
182
183
16.0k
    len = net_send(con->ns, logger, con->sock, packet, packet_size, &con->ip_port, con->net_profile);
184
185
16.0k
    if (len <= 0) {
186
0
        return 0;
187
0
    }
188
189
16.0k
    increment_nonce(con->sent_nonce);
190
191
16.0k
    if ((unsigned int)len == packet_size) {
192
16.0k
        return 1;
193
16.0k
    }
194
195
3
    memcpy(con->last_packet, packet, packet_size);
196
3
    con->last_packet_length = packet_size;
197
3
    con->last_packet_sent = len;
198
3
    return 1;
199
16.0k
}
200
201
/** @brief Read length bytes from socket.
202
 *
203
 * return length on success
204
 * return -1 on failure/no data in buffer.
205
 */
206
int read_tcp_packet(
207
    const Logger *logger, const Memory *mem, const Network *ns, Socket sock, uint8_t *data, uint16_t length, const IP_Port *ip_port)
208
16.8k
{
209
16.8k
    const uint16_t count = net_socket_data_recv_buffer(ns, sock);
210
211
16.8k
    if (count < length) {
212
94
        if (count != 0) {
213
            // Only log when there are some bytes available, as empty buffer
214
            // is a very common case and this spams our logs.
215
22
            LOGGER_TRACE(logger, "recv buffer has %d bytes, but requested %d bytes", count, length);
216
22
        }
217
94
        return -1;
218
94
    }
219
220
16.7k
    const int len = net_recv(ns, logger, sock, data, length, ip_port);
221
222
16.7k
    if (len != length) {
223
0
        LOGGER_ERROR(logger, "FAIL recv packet");
224
0
        return -1;
225
0
    }
226
227
16.7k
    return len;
228
16.7k
}
229
230
/** @brief Read the next two bytes in TCP stream then convert them to
231
 * length (host byte order).
232
 *
233
 * return length on success
234
 * return 0 if nothing has been read from socket.
235
 * return -1 on failure.
236
 */
237
static uint16_t read_tcp_length(const Logger *_Nonnull logger, const Network *_Nonnull ns, Socket sock, const IP_Port *_Nonnull ip_port)
238
60.3k
{
239
60.3k
    const uint16_t count = net_socket_data_recv_buffer(ns, sock);
240
241
60.3k
    if (count >= sizeof(uint16_t)) {
242
16.5k
        uint8_t length_buf[sizeof(uint16_t)];
243
16.5k
        const int len = net_recv(ns, logger, sock, length_buf, sizeof(length_buf), ip_port);
244
245
16.5k
        if (len != sizeof(uint16_t)) {
246
0
            LOGGER_ERROR(logger, "FAIL recv packet");
247
0
            return 0;
248
0
        }
249
250
16.5k
        uint16_t length;
251
16.5k
        net_unpack_u16(length_buf, &length);
252
253
16.5k
        if (length > MAX_PACKET_SIZE) {
254
0
            LOGGER_ERROR(logger, "TCP packet too large: %d > %d", length, MAX_PACKET_SIZE);
255
0
            return -1;
256
0
        }
257
258
16.5k
        return length;
259
16.5k
    }
260
261
43.7k
    return 0;
262
60.3k
}
263
264
/**
265
 * @return length of received packet on success.
266
 * @retval 0 if could not read any packet.
267
 * @retval -1 on failure (connection must be killed).
268
 */
269
int read_packet_tcp_secure_connection(
270
    const Logger *logger, const Memory *mem, const Network *ns,
271
    Socket sock, uint16_t *next_packet_length,
272
    const uint8_t *shared_key, uint8_t *recv_nonce, uint8_t *data,
273
    uint16_t max_len, const IP_Port *ip_port)
274
60.2k
{
275
60.3k
    if (*next_packet_length == 0) {
276
60.3k
        const uint16_t len = read_tcp_length(logger, ns, sock, ip_port);
277
278
60.3k
        if (len == (uint16_t) -1) {
279
0
            return -1;
280
0
        }
281
282
60.3k
        if (len == 0) {
283
43.7k
            return 0;
284
43.7k
        }
285
286
16.6k
        *next_packet_length = len;
287
16.6k
    }
288
289
16.5k
    if (max_len + CRYPTO_MAC_SIZE < *next_packet_length) {
290
0
        LOGGER_DEBUG(logger, "packet too large");
291
0
        return -1;
292
0
    }
293
294
16.5k
    VLA(uint8_t, data_encrypted, (int) *next_packet_length);
295
16.5k
    const int len_packet = read_tcp_packet(logger, mem, ns, sock, data_encrypted, *next_packet_length, ip_port);
296
297
16.5k
    if (len_packet == -1) {
298
18
        return 0;
299
18
    }
300
301
16.5k
    if (len_packet != *next_packet_length) {
302
        // TODO(Green-Sky): this is probably unrecoverable
303
0
        LOGGER_WARNING(logger, "invalid packet length: %d, expected %d", len_packet, *next_packet_length);
304
0
        return 0;
305
0
    }
306
307
16.5k
    *next_packet_length = 0;
308
309
16.5k
    const int len = decrypt_data_symmetric(mem, shared_key, recv_nonce, data_encrypted, len_packet, data);
310
311
16.5k
    if (len + CRYPTO_MAC_SIZE != len_packet) {
312
0
        LOGGER_ERROR(logger, "decrypted length %d does not match expected length %d", len + CRYPTO_MAC_SIZE, len_packet);
313
0
        return -1;
314
0
    }
315
316
16.5k
    increment_nonce(recv_nonce);
317
318
16.5k
    return len;
319
16.5k
}
320
321
const char *tcp_packet_type_to_string(Tcp_Packet type)
322
0
{
323
0
    switch (type) {
324
0
        case TCP_PACKET_ROUTING_REQUEST:
325
0
            return "TCP_PACKET_ROUTING_REQUEST";
326
327
0
        case TCP_PACKET_ROUTING_RESPONSE:
328
0
            return "TCP_PACKET_ROUTING_RESPONSE";
329
330
0
        case TCP_PACKET_CONNECTION_NOTIFICATION:
331
0
            return "TCP_PACKET_CONNECTION_NOTIFICATION";
332
333
0
        case TCP_PACKET_DISCONNECT_NOTIFICATION:
334
0
            return "TCP_PACKET_DISCONNECT_NOTIFICATION";
335
336
0
        case TCP_PACKET_PING:
337
0
            return "TCP_PACKET_PING";
338
339
0
        case TCP_PACKET_PONG:
340
0
            return "TCP_PACKET_PONG";
341
342
0
        case TCP_PACKET_OOB_SEND:
343
0
            return "TCP_PACKET_OOB_SEND";
344
345
0
        case TCP_PACKET_OOB_RECV:
346
0
            return "TCP_PACKET_OOB_RECV";
347
348
0
        case TCP_PACKET_ONION_REQUEST:
349
0
            return "TCP_PACKET_ONION_REQUEST";
350
351
0
        case TCP_PACKET_ONION_RESPONSE:
352
0
            return "TCP_PACKET_ONION_RESPONSE";
353
354
0
        case TCP_PACKET_FORWARD_REQUEST:
355
0
            return "TCP_PACKET_FORWARD_REQUEST";
356
357
0
        case TCP_PACKET_FORWARDING:
358
0
            return "TCP_PACKET_FORWARDING";
359
0
    }
360
361
0
    return "<invalid Tcp_Packet>";
362
0
}
363
364
bool tcp_packet_from_int(uint32_t value, Tcp_Packet *out_enum)
365
0
{
366
0
    switch (value) {
367
0
        case TCP_PACKET_ROUTING_REQUEST:
368
0
        case TCP_PACKET_ROUTING_RESPONSE:
369
0
        case TCP_PACKET_CONNECTION_NOTIFICATION:
370
0
        case TCP_PACKET_DISCONNECT_NOTIFICATION:
371
0
        case TCP_PACKET_PING:
372
0
        case TCP_PACKET_PONG:
373
0
        case TCP_PACKET_OOB_SEND:
374
0
        case TCP_PACKET_OOB_RECV:
375
0
        case TCP_PACKET_ONION_REQUEST:
376
0
        case TCP_PACKET_ONION_RESPONSE:
377
0
        case TCP_PACKET_FORWARD_REQUEST:
378
0
        case TCP_PACKET_FORWARDING: {
379
0
            *out_enum = (Tcp_Packet)value;
380
0
            return true;
381
0
        }
382
0
    }
383
384
0
    return false;
385
0
}