Coverage Report

Created: 2024-01-26 01:52

/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-2018 The TokTok team.
3
 * Copyright © 2014 Tox project.
4
 */
5
6
#include "TCP_common.h"
7
8
#include <string.h>
9
10
#include "ccompat.h"
11
#include "crypto_core.h"
12
#include "logger.h"
13
#include "mem.h"
14
#include "network.h"
15
16
void wipe_priority_list(const Memory *mem, TCP_Priority_List *p)
17
3.29k
{
18
3.29k
    while (p != nullptr) {
19
3
        TCP_Priority_List *pp = p;
20
3
        p = p->next;
21
3
        mem_delete(mem, pp->data);
22
3
        mem_delete(mem, pp);
23
3
    }
24
3.29k
}
25
26
/**
27
 * @retval 0 if pending data was sent completely
28
 * @retval -1 if it wasn't
29
 */
30
int send_pending_data_nonpriority(const Logger *logger, TCP_Connection *con)
31
36.1k
{
32
36.1k
    if (con->last_packet_length == 0) {
33
35.5k
        return 0;
34
35.5k
    }
35
36
622
    const uint16_t left = con->last_packet_length - con->last_packet_sent;
37
622
    const int len = net_send(con->ns, logger, con->sock, con->last_packet + con->last_packet_sent, left, &con->ip_port);
38
39
622
    if (len <= 0) {
40
119
        return -1;
41
119
    }
42
43
503
    if (len == left) {
44
503
        con->last_packet_length = 0;
45
503
        con->last_packet_sent = 0;
46
503
        return 0;
47
503
    }
48
49
0
    con->last_packet_sent += len;
50
0
    return -1;
51
503
}
52
53
/**
54
 * @retval 0 if pending data was sent completely
55
 * @retval -1 if it wasn't
56
 */
57
int send_pending_data(const Logger *logger, TCP_Connection *con)
58
36.1k
{
59
    /* finish sending current non-priority packet */
60
36.1k
    if (send_pending_data_nonpriority(logger, con) == -1) {
61
119
        return -1;
62
119
    }
63
64
36.0k
    TCP_Priority_List *p = con->priority_queue_start;
65
66
36.0k
    while (p != nullptr) {
67
459
        const uint16_t left = p->size - p->sent;
68
459
        const int len = net_send(con->ns, logger, con->sock, p->data + p->sent, left, &con->ip_port);
69
70
459
        if (len != left) {
71
459
            if (len > 0) {
72
0
                p->sent += len;
73
0
            }
74
75
459
            break;
76
459
        }
77
78
0
        TCP_Priority_List *pp = p;
79
0
        p = p->next;
80
0
        mem_delete(con->mem, pp->data);
81
0
        mem_delete(con->mem, pp);
82
0
    }
83
84
36.0k
    con->priority_queue_start = p;
85
86
36.0k
    if (p == nullptr) {
87
35.5k
        con->priority_queue_end = nullptr;
88
35.5k
        return 0;
89
35.5k
    }
90
91
459
    return -1;
92
36.0k
}
93
94
/**
95
 * @retval false on failure (only if mem_alloc fails)
96
 * @retval true on success
97
 */
98
non_null()
99
static bool add_priority(TCP_Connection *con, const uint8_t *packet, uint16_t size, uint16_t sent)
100
3
{
101
3
    TCP_Priority_List *p = con->priority_queue_end;
102
3
    TCP_Priority_List *new_list = (TCP_Priority_List *)mem_alloc(con->mem, sizeof(TCP_Priority_List));
103
104
3
    if (new_list == nullptr) {
105
0
        return false;
106
0
    }
107
108
3
    uint8_t *data = (uint8_t *)mem_balloc(con->mem, size);
109
110
3
    if (data == nullptr) {
111
0
        mem_delete(con->mem, new_list);
112
0
        return false;
113
0
    }
114
115
3
    memcpy(data, packet, size);
116
3
    new_list->data = data;
117
3
    new_list->size = size;
118
119
3
    new_list->next = nullptr;
120
3
    new_list->sent = sent;
121
122
3
    if (p != nullptr) {
123
1
        p->next = new_list;
124
2
    } else {
125
2
        con->priority_queue_start = new_list;
126
2
    }
127
128
3
    con->priority_queue_end = new_list;
129
3
    return true;
130
3
}
131
132
/**
133
 * @retval 1 on success.
134
 * @retval 0 if could not send packet.
135
 * @retval -1 on failure (connection must be killed).
136
 */
137
int write_packet_tcp_secure_connection(const Logger *logger, TCP_Connection *con, const uint8_t *data, uint16_t length,
138
                                       bool priority)
139
4.93k
{
140
4.93k
    if (length + CRYPTO_MAC_SIZE > MAX_PACKET_SIZE) {
141
0
        return -1;
142
0
    }
143
144
4.93k
    bool sendpriority = true;
145
146
4.93k
    if (send_pending_data(logger, con) == -1) {
147
1
        if (priority) {
148
1
            sendpriority = false;
149
1
        } else {
150
0
            return 0;
151
0
        }
152
1
    }
153
154
4.93k
    const uint16_t packet_size = sizeof(uint16_t) + length + CRYPTO_MAC_SIZE;
155
4.93k
    VLA(uint8_t, packet, packet_size);
156
157
4.93k
    uint16_t c_length = net_htons(length + CRYPTO_MAC_SIZE);
158
4.93k
    memcpy(packet, &c_length, sizeof(uint16_t));
159
4.93k
    int len = encrypt_data_symmetric(con->shared_key, con->sent_nonce, data, length, packet + sizeof(uint16_t));
160
161
4.93k
    if ((unsigned int)len != (packet_size - sizeof(uint16_t))) {
162
0
        return -1;
163
0
    }
164
165
4.93k
    if (priority) {
166
768
        len = sendpriority ? net_send(con->ns, logger, con->sock, packet, packet_size, &con->ip_port) : 0;
167
168
768
        if (len <= 0) {
169
3
            len = 0;
170
3
        }
171
172
768
        increment_nonce(con->sent_nonce);
173
174
768
        if ((unsigned int)len == packet_size) {
175
765
            return 1;
176
765
        }
177
178
3
        return add_priority(con, packet, packet_size, len) ? 1 : 0;
179
768
    }
180
181
4.16k
    len = net_send(con->ns, logger, con->sock, packet, packet_size, &con->ip_port);
182
183
4.16k
    if (len <= 0) {
184
6
        return 0;
185
6
    }
186
187
4.15k
    increment_nonce(con->sent_nonce);
188
189
4.15k
    if ((unsigned int)len == packet_size) {
190
4.15k
        return 1;
191
4.15k
    }
192
193
0
    memcpy(con->last_packet, packet, packet_size);
194
0
    con->last_packet_length = packet_size;
195
0
    con->last_packet_sent = len;
196
0
    return 1;
197
4.15k
}
198
199
/** @brief Read length bytes from socket.
200
 *
201
 * return length on success
202
 * return -1 on failure/no data in buffer.
203
 */
204
int read_tcp_packet(
205
        const Logger *logger, const Memory *mem, const Network *ns, Socket sock, uint8_t *data, uint16_t length, const IP_Port *ip_port)
206
10.3k
{
207
10.3k
    const uint16_t count = net_socket_data_recv_buffer(ns, sock);
208
209
10.3k
    if (count < length) {
210
2.84k
        if (count != 0) {
211
            // Only log when there are some bytes available, as empty buffer
212
            // is a very common case and this spams our logs.
213
604
            LOGGER_TRACE(logger, "recv buffer has %d bytes, but requested %d bytes", count, length);
214
604
        }
215
2.84k
        return -1;
216
2.84k
    }
217
218
7.50k
    const int len = net_recv(ns, logger, sock, data, length, ip_port);
219
220
7.50k
    if (len != length) {
221
2.34k
        LOGGER_ERROR(logger, "FAIL recv packet");
222
2.34k
        return -1;
223
2.34k
    }
224
225
5.15k
    return len;
226
7.50k
}
227
228
/** @brief Read the next two bytes in TCP stream then convert them to
229
 * length (host byte order).
230
 *
231
 * return length on success
232
 * return 0 if nothing has been read from socket.
233
 * return -1 on failure.
234
 */
235
non_null()
236
static uint16_t read_tcp_length(const Logger *logger, const Memory *mem, const Network *ns, Socket sock, const IP_Port *ip_port)
237
34.5k
{
238
34.5k
    const uint16_t count = net_socket_data_recv_buffer(ns, sock);
239
240
34.5k
    if (count >= sizeof(uint16_t)) {
241
5.53k
        uint8_t length_buf[sizeof(uint16_t)];
242
5.53k
        const int len = net_recv(ns, logger, sock, length_buf, sizeof(length_buf), ip_port);
243
244
5.53k
        if (len != sizeof(uint16_t)) {
245
926
            LOGGER_ERROR(logger, "FAIL recv packet");
246
926
            return 0;
247
926
        }
248
249
4.61k
        uint16_t length;
250
4.61k
        net_unpack_u16(length_buf, &length);
251
252
4.61k
        if (length > MAX_PACKET_SIZE) {
253
91
            LOGGER_ERROR(logger, "TCP packet too large: %d > %d", length, MAX_PACKET_SIZE);
254
91
            return -1;
255
91
        }
256
257
4.52k
        return length;
258
4.61k
    }
259
260
29.0k
    return 0;
261
34.5k
}
262
263
/**
264
 * @return length of received packet on success.
265
 * @retval 0 if could not read any packet.
266
 * @retval -1 on failure (connection must be killed).
267
 */
268
int read_packet_tcp_secure_connection(
269
        const Logger *logger, const Memory *mem, const Network *ns,
270
        Socket sock, uint16_t *next_packet_length,
271
        const uint8_t *shared_key, uint8_t *recv_nonce, uint8_t *data,
272
        uint16_t max_len, const IP_Port *ip_port)
273
34.8k
{
274
34.8k
    if (*next_packet_length == 0) {
275
34.5k
        const uint16_t len = read_tcp_length(logger, mem, ns, sock, ip_port);
276
277
34.5k
        if (len == (uint16_t) -1) {
278
91
            return -1;
279
91
        }
280
281
34.4k
        if (len == 0) {
282
29.9k
            return 0;
283
29.9k
        }
284
285
4.50k
        *next_packet_length = len;
286
4.50k
    }
287
288
4.84k
    if (max_len + CRYPTO_MAC_SIZE < *next_packet_length) {
289
0
        LOGGER_DEBUG(logger, "packet too large");
290
0
        return -1;
291
0
    }
292
293
4.84k
    VLA(uint8_t, data_encrypted, (int) *next_packet_length);
294
4.84k
    const int len_packet = read_tcp_packet(logger, mem, ns, sock, data_encrypted, *next_packet_length, ip_port);
295
296
4.84k
    if (len_packet == -1) {
297
359
        return 0;
298
359
    }
299
300
4.48k
    if (len_packet != *next_packet_length) {
301
0
        LOGGER_WARNING(logger, "invalid packet length: %d, expected %d", len_packet, *next_packet_length);
302
0
        return 0;
303
0
    }
304
305
4.48k
    *next_packet_length = 0;
306
307
4.48k
    const int len = decrypt_data_symmetric(shared_key, recv_nonce, data_encrypted, len_packet, data);
308
309
4.48k
    if (len + CRYPTO_MAC_SIZE != len_packet) {
310
1
        LOGGER_ERROR(logger, "decrypted length %d does not match expected length %d", len + CRYPTO_MAC_SIZE, len_packet);
311
1
        return -1;
312
1
    }
313
314
4.48k
    increment_nonce(recv_nonce);
315
316
4.48k
    return len;
317
4.48k
}