Coverage Report

Created: 2026-01-17 10:30

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/c-toxcore/toxcore/announce.c
Line
Count
Source
1
/* SPDX-License-Identifier: GPL-3.0-or-later
2
 * Copyright © 2020-2025 The TokTok team.
3
 */
4
5
/**
6
 * "Server side" of the DHT announcements protocol.
7
 */
8
9
#include "announce.h"
10
11
#include <assert.h>
12
#include <string.h>
13
14
#include "DHT.h"
15
#include "LAN_discovery.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 "network.h"
24
#include "shared_key_cache.h"
25
#include "timed_auth.h"
26
#include "util.h"
27
28
/* Settings for the shared key cache */
29
1.46k
#define MAX_KEYS_PER_SLOT 4
30
1.46k
#define KEYS_TIMEOUT 600
31
32
uint8_t announce_response_of_request_type(uint8_t request_type)
33
0
{
34
0
    switch (request_type) {
35
0
        case NET_PACKET_DATA_SEARCH_REQUEST:
36
0
            return NET_PACKET_DATA_SEARCH_RESPONSE;
37
38
0
        case NET_PACKET_DATA_RETRIEVE_REQUEST:
39
0
            return NET_PACKET_DATA_RETRIEVE_RESPONSE;
40
41
0
        case NET_PACKET_STORE_ANNOUNCE_REQUEST:
42
0
            return NET_PACKET_STORE_ANNOUNCE_RESPONSE;
43
44
0
        default: {
45
0
            assert(false);
46
0
            return NET_PACKET_MAX;
47
0
        }
48
0
    }
49
0
}
50
51
typedef struct Announce_Entry {
52
    uint64_t store_until;
53
    uint8_t data_public_key[CRYPTO_PUBLIC_KEY_SIZE];
54
    uint8_t *_Nullable data;
55
    uint32_t length;
56
} Announce_Entry;
57
58
struct Announcements {
59
    const Logger *_Nonnull log;
60
    const Memory *_Nonnull mem;
61
    const Random *_Nonnull rng;
62
    Forwarding *_Nonnull forwarding;
63
    const Mono_Time *_Nonnull mono_time;
64
    DHT *_Nonnull dht;
65
    Networking_Core *_Nonnull net;
66
    const uint8_t *_Nonnull public_key;
67
    const uint8_t *_Nonnull secret_key;
68
69
    Shared_Key_Cache *_Nonnull shared_keys;
70
    uint8_t hmac_key[CRYPTO_HMAC_KEY_SIZE];
71
72
    int32_t synch_offset;
73
74
    uint64_t start_time;
75
76
    Announce_Entry entries[ANNOUNCE_BUCKETS * ANNOUNCE_BUCKET_SIZE];
77
};
78
79
void announce_set_synch_offset(Announcements *announce, int32_t synch_offset)
80
0
{
81
0
    announce->synch_offset = synch_offset;
82
0
}
83
84
/**
85
 * An entry is considered to be "deleted" for the purposes of the protocol
86
 * once it has timed out.
87
 */
88
static bool entry_is_empty(const Announcements *_Nonnull announce, const Announce_Entry *_Nonnull entry)
89
0
{
90
0
    return mono_time_get(announce->mono_time) >= entry->store_until;
91
0
}
92
93
static void delete_entry(Announce_Entry *_Nonnull entry)
94
0
{
95
0
    entry->store_until = 0;
96
0
}
97
98
/** Return bits (at most 8) from pk starting at index as uint8_t */
99
static uint8_t truncate_pk_at_index(const uint8_t *_Nonnull pk, uint16_t index, uint16_t bits)
100
0
{
101
0
    assert(bits < 8);
102
0
    const uint8_t i = index / 8;
103
0
    const uint8_t j = index % 8;
104
0
    return ((uint8_t)((i < CRYPTO_PUBLIC_KEY_SIZE ? pk[i] : 0) << j) >> (8 - bits)) |
105
0
           ((i + 1 < CRYPTO_PUBLIC_KEY_SIZE ? pk[i + 1] : 0) >> (16 - bits - j));
106
0
}
107
108
uint16_t announce_get_bucketnum(const uint8_t *base, const uint8_t *pk)
109
0
{
110
0
    const uint16_t index = bit_by_bit_cmp(base, pk);
111
112
0
    return truncate_pk_at_index(base, index + 1, ANNOUNCE_BUCKET_PREFIX_LENGTH) ^
113
0
           truncate_pk_at_index(pk, index + 1, ANNOUNCE_BUCKET_PREFIX_LENGTH);
114
0
}
115
116
static Announce_Entry *bucket_of_key(Announcements *_Nonnull announce, const uint8_t *_Nonnull pk)
117
0
{
118
0
    return &announce->entries[announce_get_bucketnum(announce->public_key, pk) * ANNOUNCE_BUCKET_SIZE];
119
0
}
120
121
static Announce_Entry *get_stored(Announcements *_Nonnull announce, const uint8_t *_Nonnull data_public_key)
122
0
{
123
0
    Announce_Entry *const bucket = bucket_of_key(announce, data_public_key);
124
125
0
    for (uint32_t i = 0; i < ANNOUNCE_BUCKET_SIZE; ++i) {
126
0
        if (pk_equal(bucket[i].data_public_key, data_public_key)) {
127
0
            if (entry_is_empty(announce, &bucket[i])) {
128
0
                break;
129
0
            }
130
131
0
            return &bucket[i];
132
0
        }
133
0
    }
134
135
0
    return nullptr;
136
0
}
137
138
static const Announce_Entry *bucket_of_key_const(const Announcements *_Nonnull announce, const uint8_t *_Nonnull pk)
139
0
{
140
0
    return &announce->entries[announce_get_bucketnum(announce->public_key, pk) * ANNOUNCE_BUCKET_SIZE];
141
0
}
142
143
static const Announce_Entry *get_stored_const(const Announcements *_Nonnull announce, const uint8_t *_Nonnull data_public_key)
144
0
{
145
0
    const Announce_Entry *const bucket = bucket_of_key_const(announce, data_public_key);
146
147
0
    for (uint32_t i = 0; i < ANNOUNCE_BUCKET_SIZE; ++i) {
148
0
        if (pk_equal(bucket[i].data_public_key, data_public_key)) {
149
0
            if (entry_is_empty(announce, &bucket[i])) {
150
0
                break;
151
0
            }
152
153
0
            return &bucket[i];
154
0
        }
155
0
    }
156
157
0
    return nullptr;
158
0
}
159
160
bool announce_on_stored(const Announcements *announce, const uint8_t *data_public_key,
161
                        announce_on_retrieve_cb *on_retrieve_callback, void *object)
162
0
{
163
0
    const Announce_Entry *const entry = get_stored_const(announce, data_public_key);
164
165
0
    if (entry == nullptr || entry->data == nullptr) {
166
0
        return false;
167
0
    }
168
169
0
    if (on_retrieve_callback != nullptr) {
170
0
        on_retrieve_callback(object, entry->data, entry->length);
171
0
    }
172
173
0
    return true;
174
0
}
175
176
/**
177
 * Return existing entry for this key if it exists, else an empty
178
 * slot in the key's bucket if one exists, else an entry in the key's bucket
179
 * of greatest 2-adic distance greater than that of the key bucket if one
180
 * exists, else nullptr.
181
 */
182
static Announce_Entry *find_entry_slot(Announcements *_Nonnull announce, const uint8_t *_Nonnull data_public_key)
183
0
{
184
0
    Announce_Entry *const bucket = bucket_of_key(announce, data_public_key);
185
186
0
    Announce_Entry *slot = nullptr;
187
0
    uint16_t min_index = bit_by_bit_cmp(announce->public_key, data_public_key);
188
189
0
    for (uint32_t i = 0; i < ANNOUNCE_BUCKET_SIZE; ++i) {
190
0
        if (pk_equal(bucket[i].data_public_key, data_public_key)) {
191
0
            return &bucket[i];
192
0
        }
193
194
0
        if (entry_is_empty(announce, &bucket[i])) {
195
0
            slot = &bucket[i];
196
0
            min_index = 0;
197
0
            continue;
198
0
        }
199
200
0
        const uint16_t index = bit_by_bit_cmp(announce->public_key, bucket[i].data_public_key);
201
202
0
        if (index < min_index) {
203
0
            slot = &bucket[i];
204
0
            min_index = index;
205
0
        }
206
0
    }
207
208
0
    return slot;
209
0
}
210
211
static bool would_accept_store_request(Announcements *_Nonnull announce, const uint8_t *_Nonnull data_public_key)
212
0
{
213
0
    return find_entry_slot(announce, data_public_key) != nullptr;
214
0
}
215
216
bool announce_store_data(Announcements *announce, const uint8_t *data_public_key,
217
                         const uint8_t *data, uint32_t length, uint32_t timeout)
218
0
{
219
0
    if (length > MAX_ANNOUNCEMENT_SIZE) {
220
0
        return false;
221
0
    }
222
223
0
    Announce_Entry *entry = find_entry_slot(announce, data_public_key);
224
225
0
    if (entry == nullptr) {
226
0
        return false;
227
0
    }
228
229
0
    if (length > 0) {
230
0
        assert(data != nullptr);
231
232
0
        mem_delete(announce->mem, entry->data);
233
234
0
        uint8_t *entry_data = (uint8_t *)mem_balloc(announce->mem, length);
235
236
0
        if (entry_data == nullptr) {
237
0
            entry->data = nullptr;  // TODO(iphydf): Is this necessary?
238
0
            return false;
239
0
        }
240
241
0
        memcpy(entry_data, data, length);
242
0
        entry->data = entry_data;
243
0
    }
244
245
0
    entry->length = length;
246
0
    memcpy(entry->data_public_key, data_public_key, CRYPTO_PUBLIC_KEY_SIZE);
247
0
    entry->store_until = mono_time_get(announce->mono_time) + timeout;
248
249
0
    return true;
250
0
}
251
252
static uint32_t calculate_timeout(const Announcements *_Nonnull announce, uint32_t requested_timeout)
253
0
{
254
0
    const uint64_t uptime = mono_time_get(announce->mono_time) - announce->start_time;
255
0
    const uint32_t max_announcement_timeout = max_u32(
256
0
                (uint32_t)min_u64(
257
0
                    MAX_MAX_ANNOUNCEMENT_TIMEOUT,
258
0
                    uptime / MAX_ANNOUNCEMENT_TIMEOUT_UPTIME_RATIO),
259
0
                MIN_MAX_ANNOUNCEMENT_TIMEOUT);
260
261
0
    return min_u32(max_announcement_timeout, requested_timeout);
262
0
}
263
264
0
#define DATA_SEARCH_TO_AUTH_MAX_SIZE (CRYPTO_PUBLIC_KEY_SIZE * 2 + MAX_PACKED_IPPORT_SIZE + MAX_SENDBACK_SIZE)
265
266
static int create_data_search_to_auth(const Logger *_Nonnull logger, const uint8_t *_Nonnull data_public_key,
267
                                      const uint8_t *_Nonnull requester_key,
268
                                      const IP_Port *_Nonnull source, const uint8_t *_Nullable sendback, uint16_t sendback_length,
269
                                      uint8_t *_Nonnull dest, uint16_t max_length)
270
0
{
271
0
    if (max_length < DATA_SEARCH_TO_AUTH_MAX_SIZE
272
0
            || sendback_length > MAX_SENDBACK_SIZE) {
273
0
        return -1;
274
0
    }
275
276
0
    memcpy(dest, data_public_key, CRYPTO_PUBLIC_KEY_SIZE);
277
0
    memcpy(dest + CRYPTO_PUBLIC_KEY_SIZE, requester_key, CRYPTO_PUBLIC_KEY_SIZE);
278
279
0
    const int ipport_length = pack_ip_port(logger, dest + CRYPTO_PUBLIC_KEY_SIZE * 2, MAX_PACKED_IPPORT_SIZE, source);
280
281
0
    if (ipport_length == -1) {
282
0
        return -1;
283
0
    }
284
285
0
    if (sendback_length > 0) {
286
0
        assert(sendback != nullptr);
287
0
        memcpy(dest + CRYPTO_PUBLIC_KEY_SIZE * 2 + ipport_length, sendback, sendback_length);
288
0
    }
289
290
0
    return CRYPTO_PUBLIC_KEY_SIZE * 2 + ipport_length + sendback_length;
291
0
}
292
293
0
#define DATA_SEARCH_TIMEOUT 60
294
295
static int create_reply_plain_data_search_request(Announcements *_Nonnull announce, const IP_Port *_Nonnull source, const uint8_t *_Nonnull data, uint16_t length, uint8_t *_Nonnull reply,
296
        uint16_t reply_max_length, const uint8_t *_Nonnull to_auth, uint16_t to_auth_length)
297
0
{
298
0
    if (length != CRYPTO_PUBLIC_KEY_SIZE &&
299
0
            length != CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_SHA256_SIZE) {
300
0
        return -1;
301
0
    }
302
303
0
    const uint8_t *const data_public_key = data;
304
305
0
    const uint8_t *previous_hash = nullptr;
306
307
0
    if (length == CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_SHA256_SIZE) {
308
0
        previous_hash = data + CRYPTO_PUBLIC_KEY_SIZE;
309
0
    }
310
311
0
    const int nodes_max_length = (int)reply_max_length -
312
0
                                 (CRYPTO_PUBLIC_KEY_SIZE + 1 + CRYPTO_SHA256_SIZE + TIMED_AUTH_SIZE + 1 + 1);
313
314
0
    if (nodes_max_length < 0) {
315
0
        return -1;
316
0
    }
317
318
0
    uint8_t *p = reply;
319
320
0
    memcpy(p, data_public_key, CRYPTO_PUBLIC_KEY_SIZE);
321
0
    p += CRYPTO_PUBLIC_KEY_SIZE;
322
323
0
    const Announce_Entry *const stored = get_stored_const(announce, data_public_key);
324
325
0
    if (stored == nullptr) {
326
0
        *p = 0;
327
0
        ++p;
328
0
    } else {
329
0
        *p = 1;
330
0
        ++p;
331
0
        if (stored->data == nullptr) {
332
0
            LOGGER_ERROR(announce->log, "Stored data is null for public key.");
333
0
            return -1;
334
0
        }
335
0
        crypto_sha256(p, stored->data, stored->length);
336
0
        p += CRYPTO_SHA256_SIZE;
337
0
    }
338
339
0
    generate_timed_auth(announce->mono_time, DATA_SEARCH_TIMEOUT, announce->hmac_key,
340
0
                        to_auth, to_auth_length, p);
341
0
    p += TIMED_AUTH_SIZE;
342
343
0
    *p = would_accept_store_request(announce, data_public_key) ? 1 : 0;
344
0
    ++p;
345
346
0
    Node_format nodes_list[MAX_SENT_NODES];
347
0
    const int num_nodes = get_close_nodes(announce->dht, data_public_key, nodes_list,
348
0
                                          net_family_unspec(), ip_is_lan(&source->ip), true);
349
350
0
    if (num_nodes < 0 || num_nodes > MAX_SENT_NODES) {
351
0
        return -1;
352
0
    }
353
354
0
    *p = num_nodes;
355
0
    ++p;
356
357
0
    p += pack_nodes(announce->log, p, nodes_max_length, nodes_list, num_nodes);
358
359
0
    const uint32_t reply_len = p - reply;
360
361
0
    if (previous_hash != nullptr) {
362
0
        uint8_t hash[CRYPTO_SHA256_SIZE];
363
364
0
        crypto_sha256(hash, reply, reply_len);
365
366
0
        if (crypto_sha256_eq(hash, previous_hash)) {
367
0
            return CRYPTO_PUBLIC_KEY_SIZE;
368
0
        }
369
0
    }
370
371
0
    return reply_len;
372
0
}
373
374
static int create_reply_plain_data_retrieve_request(const Announcements *_Nonnull announce, const IP_Port *_Nonnull source, const uint8_t *_Nonnull data, uint16_t length,
375
        uint8_t *_Nonnull reply, uint16_t reply_max_length, const uint8_t *_Nonnull to_auth, uint16_t to_auth_length)
376
0
{
377
0
    if (length != CRYPTO_PUBLIC_KEY_SIZE + 1 + TIMED_AUTH_SIZE) {
378
0
        return -1;
379
0
    }
380
381
0
    if (data[CRYPTO_PUBLIC_KEY_SIZE] != 0) {
382
0
        return -1;
383
0
    }
384
385
0
    const uint8_t *const data_public_key = data;
386
0
    const uint8_t *const auth = data + CRYPTO_PUBLIC_KEY_SIZE + 1;
387
388
0
    if (!check_timed_auth(announce->mono_time, DATA_SEARCH_TIMEOUT, announce->hmac_key,
389
0
                          to_auth, to_auth_length, auth)) {
390
0
        return -1;
391
0
    }
392
393
0
    const Announce_Entry *const entry = get_stored_const(announce, data_public_key);
394
395
0
    if (entry == nullptr) {
396
0
        return -1;
397
0
    }
398
399
0
    const uint16_t reply_len = CRYPTO_PUBLIC_KEY_SIZE + 1 + entry->length;
400
401
0
    if (reply_max_length < reply_len) {
402
0
        return -1;
403
0
    }
404
405
0
    memcpy(reply, data_public_key, CRYPTO_PUBLIC_KEY_SIZE);
406
0
    reply[CRYPTO_PUBLIC_KEY_SIZE] = 1;
407
0
    memcpy(reply + CRYPTO_PUBLIC_KEY_SIZE + 1, entry->data, entry->length);
408
409
0
    return reply_len;
410
0
}
411
412
static int create_reply_plain_store_announce_request(Announcements *_Nonnull announce, const IP_Port *_Nonnull source, const uint8_t *_Nonnull data, uint16_t length, uint8_t *_Nonnull reply,
413
        uint16_t reply_max_length, const uint8_t *_Nonnull to_auth, uint16_t to_auth_length)
414
0
{
415
0
    const int plain_len = (int)length - (CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE + CRYPTO_MAC_SIZE);
416
0
    const int announcement_len = plain_len - (TIMED_AUTH_SIZE + sizeof(uint32_t) + 1);
417
418
0
    const uint8_t *const data_public_key = data;
419
420
0
    if (announcement_len < 0) {
421
0
        return -1;
422
0
    }
423
424
0
    VLA(uint8_t, plain, plain_len);
425
426
0
    const uint8_t *shared_key = shared_key_cache_lookup(announce->shared_keys, data_public_key);
427
428
0
    if (shared_key == nullptr) {
429
        /* Error looking up/deriving the shared key */
430
0
        return -1;
431
0
    }
432
433
0
    if (decrypt_data_symmetric(announce->mem, shared_key,
434
0
                               data + CRYPTO_PUBLIC_KEY_SIZE,
435
0
                               data + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE,
436
0
                               plain_len + CRYPTO_MAC_SIZE,
437
0
                               plain) != plain_len) {
438
0
        return -1;
439
0
    }
440
441
0
    const uint8_t *const auth = plain;
442
0
    uint32_t requested_timeout;
443
0
    net_unpack_u32(plain + TIMED_AUTH_SIZE, &requested_timeout);
444
0
    const uint32_t timeout = calculate_timeout(announce, requested_timeout);
445
0
    const uint8_t announcement_type = plain[TIMED_AUTH_SIZE + sizeof(uint32_t)];
446
0
    const uint8_t *announcement = plain + TIMED_AUTH_SIZE + sizeof(uint32_t) + 1;
447
448
0
    if (!check_timed_auth(announce->mono_time, DATA_SEARCH_TIMEOUT, announce->hmac_key,
449
0
                          to_auth, to_auth_length, auth)) {
450
0
        return -1;
451
0
    }
452
453
0
    if (announcement_type > 1) {
454
0
        return -1;
455
0
    }
456
457
0
    if (announcement_type == 1) {
458
0
        if (announcement_len != CRYPTO_SHA256_SIZE) {
459
0
            return -1;
460
0
        }
461
462
0
        Announce_Entry *stored = get_stored(announce, data_public_key);
463
464
0
        if (stored == nullptr) {
465
0
            return -1;
466
0
        }
467
468
0
        uint8_t stored_hash[CRYPTO_SHA256_SIZE];
469
0
        if (stored->data == nullptr) {
470
0
            LOGGER_ERROR(announce->log, "Stored data is null for public key.");
471
0
            return -1;
472
0
        }
473
0
        crypto_sha256(stored_hash, stored->data, stored->length);
474
475
0
        if (!crypto_sha256_eq(announcement, stored_hash)) {
476
0
            delete_entry(stored);
477
0
            return -1;
478
0
        } else {
479
0
            stored->store_until = mono_time_get(announce->mono_time) + timeout;
480
0
        }
481
0
    } else {
482
0
        if (!announce_store_data(announce, data_public_key, announcement, announcement_len, timeout)) {
483
0
            return -1;
484
0
        }
485
0
    }
486
487
0
    const uint16_t reply_len = CRYPTO_PUBLIC_KEY_SIZE + sizeof(uint32_t) + sizeof(uint64_t);
488
489
0
    if (reply_max_length < reply_len) {
490
0
        return -1;
491
0
    }
492
493
0
    memcpy(reply, data_public_key, CRYPTO_PUBLIC_KEY_SIZE);
494
0
    net_pack_u32(reply + CRYPTO_PUBLIC_KEY_SIZE, timeout);
495
0
    net_pack_u64(reply + CRYPTO_PUBLIC_KEY_SIZE + sizeof(uint32_t),
496
0
                 mono_time_get(announce->mono_time) + announce->synch_offset);
497
0
    return reply_len;
498
0
}
499
500
static int create_reply_plain(Announcements *_Nonnull announce,
501
                              const uint8_t *_Nonnull requester_key, const IP_Port *_Nonnull source, uint8_t type,
502
                              const uint8_t *_Nullable sendback, uint16_t sendback_length,
503
                              const uint8_t *_Nonnull data, uint16_t length,
504
                              uint8_t *_Nonnull reply, uint16_t reply_max_length)
505
0
{
506
0
    if (length < CRYPTO_PUBLIC_KEY_SIZE) {
507
0
        return -1;
508
0
    }
509
510
0
    const uint8_t *const data_public_key = data;
511
512
0
    uint8_t to_auth[DATA_SEARCH_TO_AUTH_MAX_SIZE];
513
0
    const int to_auth_length = create_data_search_to_auth(announce->log, data_public_key, requester_key, source,
514
0
                               sendback, sendback_length, to_auth, DATA_SEARCH_TO_AUTH_MAX_SIZE);
515
516
0
    if (to_auth_length == -1) {
517
0
        return -1;
518
0
    }
519
520
0
    switch (type) {
521
0
        case NET_PACKET_DATA_SEARCH_REQUEST:
522
0
            return create_reply_plain_data_search_request(announce, source, data, length, reply, reply_max_length, to_auth,
523
0
                    (uint16_t)to_auth_length);
524
525
0
        case NET_PACKET_DATA_RETRIEVE_REQUEST:
526
0
            return create_reply_plain_data_retrieve_request(announce, source, data, length, reply, reply_max_length, to_auth,
527
0
                    (uint16_t)to_auth_length);
528
529
0
        case NET_PACKET_STORE_ANNOUNCE_REQUEST:
530
0
            return create_reply_plain_store_announce_request(announce, source, data, length, reply, reply_max_length, to_auth,
531
0
                    (uint16_t)to_auth_length);
532
533
0
        default:
534
0
            return -1;
535
0
    }
536
0
}
537
538
static int create_reply(Announcements *_Nonnull announce, const IP_Port *_Nonnull source,
539
                        const uint8_t *_Nullable sendback, uint16_t sendback_length,
540
                        const uint8_t *_Nonnull data, uint16_t length,
541
                        uint8_t *_Nonnull reply, uint16_t reply_max_length)
542
0
{
543
0
    const int plain_len = (int)length - (1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE + CRYPTO_MAC_SIZE);
544
0
    if (plain_len < (int)sizeof(uint64_t)) {
545
0
        return -1;
546
0
    }
547
548
0
    VLA(uint8_t, plain, plain_len);
549
0
    const uint8_t *shared_key = dht_get_shared_key_recv(announce->dht, data + 1);
550
551
0
    if (decrypt_data_symmetric(announce->mem, shared_key,
552
0
                               data + 1 + CRYPTO_PUBLIC_KEY_SIZE,
553
0
                               data + 1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE,
554
0
                               plain_len + CRYPTO_MAC_SIZE,
555
0
                               plain) != plain_len) {
556
0
        return -1;
557
0
    }
558
559
0
    const int plain_reply_max_len = (int)reply_max_length -
560
0
                                    (1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE + CRYPTO_MAC_SIZE);
561
562
0
    if (plain_reply_max_len < (int)sizeof(uint64_t)) {
563
0
        return -1;
564
0
    }
565
566
0
    VLA(uint8_t, plain_reply, plain_reply_max_len);
567
568
0
    const int plain_reply_noping_len = create_reply_plain(announce,
569
0
                                       data + 1, source, data[0],
570
0
                                       sendback, sendback_length,
571
0
                                       plain, plain_len - sizeof(uint64_t),
572
0
                                       plain_reply, plain_reply_max_len - sizeof(uint64_t));
573
574
0
    if (plain_reply_noping_len == -1) {
575
0
        return -1;
576
0
    }
577
578
0
    memcpy(plain_reply + plain_reply_noping_len,
579
0
           plain + (plain_len - sizeof(uint64_t)), sizeof(uint64_t));
580
581
0
    const uint16_t plain_reply_len = plain_reply_noping_len + sizeof(uint64_t);
582
583
0
    const uint8_t response_type = announce_response_of_request_type(data[0]);
584
585
0
    return dht_create_packet(announce->mem, announce->rng, announce->public_key, shared_key,
586
0
                             response_type, plain_reply, plain_reply_len, reply, reply_max_length);
587
0
}
588
589
static void forwarded_request_callback(void *_Nonnull object, const IP_Port *_Nonnull forwarder,
590
                                       const uint8_t *_Nonnull sendback, uint16_t sendback_length,
591
                                       const uint8_t *_Nonnull data, uint16_t length, void *_Nullable userdata)
592
0
{
593
0
    Announcements *announce = (Announcements *) object;
594
0
    uint8_t reply[MAX_FORWARD_DATA_SIZE];
595
596
0
    const int len = create_reply(announce, forwarder,
597
0
                                 sendback, sendback_length,
598
0
                                 data, length, reply, sizeof(reply));
599
600
0
    if (len == -1) {
601
0
        return;
602
0
    }
603
604
0
    forward_reply(announce->net, forwarder, sendback, sendback_length, reply, len);
605
0
}
606
607
static int handle_dht_announce_request(
608
    void *_Nonnull object, const IP_Port *_Nonnull source, const uint8_t *_Nonnull packet, uint16_t length, void *_Nullable userdata)
609
0
{
610
0
    Announcements *announce = (Announcements *)object;
611
0
    uint8_t reply[MAX_FORWARD_DATA_SIZE];
612
613
0
    const int len
614
0
        = create_reply(announce, source, nullptr, 0, packet, length, reply, sizeof(reply));
615
616
0
    if (len == -1) {
617
0
        return -1;
618
0
    }
619
620
0
    return sendpacket(announce->net, source, reply, len) == len ? 0 : -1;
621
0
}
622
623
Announcements *new_announcements(const Logger *log, const Memory *mem, const Random *rng, const Mono_Time *mono_time,
624
                                 Forwarding *forwarding, DHT *dht, Networking_Core *net)
625
1.46k
{
626
1.46k
    if (log == nullptr || mono_time == nullptr || forwarding == nullptr) {
627
0
        return nullptr;
628
0
    }
629
630
1.46k
    Announcements *announce = (Announcements *)mem_alloc(mem, sizeof(Announcements));
631
632
1.46k
    if (announce == nullptr) {
633
1
        return nullptr;
634
1
    }
635
636
1.46k
    announce->log = log;
637
1.46k
    announce->mem = mem;
638
1.46k
    announce->rng = rng;
639
1.46k
    announce->forwarding = forwarding;
640
1.46k
    announce->mono_time = mono_time;
641
1.46k
    announce->dht = dht;
642
1.46k
    announce->net = net;
643
1.46k
    announce->public_key = dht_get_self_public_key(announce->dht);
644
1.46k
    announce->secret_key = dht_get_self_secret_key(announce->dht);
645
1.46k
    new_hmac_key(announce->rng, announce->hmac_key);
646
1.46k
    Shared_Key_Cache *const shared_keys = shared_key_cache_new(log, mono_time, mem, announce->secret_key, KEYS_TIMEOUT, MAX_KEYS_PER_SLOT);
647
1.46k
    if (shared_keys == nullptr) {
648
2
        mem_delete(announce->mem, announce);
649
2
        return nullptr;
650
2
    }
651
1.46k
    announce->shared_keys = shared_keys;
652
653
1.46k
    announce->start_time = mono_time_get(announce->mono_time);
654
655
1.46k
    set_callback_forwarded_request(forwarding, forwarded_request_callback, announce);
656
657
1.46k
    networking_registerhandler(announce->net, NET_PACKET_DATA_SEARCH_REQUEST, handle_dht_announce_request, announce);
658
1.46k
    networking_registerhandler(announce->net, NET_PACKET_DATA_RETRIEVE_REQUEST, handle_dht_announce_request, announce);
659
1.46k
    networking_registerhandler(announce->net, NET_PACKET_STORE_ANNOUNCE_REQUEST, handle_dht_announce_request, announce);
660
661
1.46k
    return announce;
662
1.46k
}
663
664
void kill_announcements(Announcements *announce)
665
1.48k
{
666
1.48k
    if (announce == nullptr) {
667
20
        return;
668
20
    }
669
670
1.46k
    set_callback_forwarded_request(announce->forwarding, nullptr, nullptr);
671
672
1.46k
    networking_registerhandler(announce->net, NET_PACKET_DATA_SEARCH_REQUEST, nullptr, nullptr);
673
1.46k
    networking_registerhandler(announce->net, NET_PACKET_DATA_RETRIEVE_REQUEST, nullptr, nullptr);
674
1.46k
    networking_registerhandler(announce->net, NET_PACKET_STORE_ANNOUNCE_REQUEST, nullptr, nullptr);
675
676
1.46k
    crypto_memzero(announce->hmac_key, CRYPTO_HMAC_KEY_SIZE);
677
1.46k
    shared_key_cache_free(announce->shared_keys);
678
679
375k
    for (uint32_t i = 0; i < ANNOUNCE_BUCKETS * ANNOUNCE_BUCKET_SIZE; ++i) {
680
374k
        mem_delete(announce->mem, announce->entries[i].data);
681
374k
    }
682
683
1.46k
    mem_delete(announce->mem, announce);
684
1.46k
}