Coverage Report

Created: 2025-08-05 10:35

/src/c-toxcore/toxcore/announce.c
Line
Count
Source (jump to first uncovered line)
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.96k
#define MAX_KEYS_PER_SLOT 4
30
1.96k
#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 *data;
55
    uint32_t length;
56
} Announce_Entry;
57
58
struct Announcements {
59
    const Logger *log;
60
    const Memory *mem;
61
    const Random *rng;
62
    Forwarding *forwarding;
63
    const Mono_Time *mono_time;
64
    DHT *dht;
65
    Networking_Core *net;
66
    const uint8_t *public_key;
67
    const uint8_t *secret_key;
68
69
    Shared_Key_Cache *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
        crypto_sha256(p, stored->data, stored->length);
332
0
        p += CRYPTO_SHA256_SIZE;
333
0
    }
334
335
0
    generate_timed_auth(announce->mono_time, DATA_SEARCH_TIMEOUT, announce->hmac_key,
336
0
                        to_auth, to_auth_length, p);
337
0
    p += TIMED_AUTH_SIZE;
338
339
0
    *p = would_accept_store_request(announce, data_public_key) ? 1 : 0;
340
0
    ++p;
341
342
0
    Node_format nodes_list[MAX_SENT_NODES];
343
0
    const int num_nodes = get_close_nodes(announce->dht, data_public_key, nodes_list,
344
0
                                          net_family_unspec(), ip_is_lan(&source->ip), true);
345
346
0
    if (num_nodes < 0 || num_nodes > MAX_SENT_NODES) {
347
0
        return -1;
348
0
    }
349
350
0
    *p = num_nodes;
351
0
    ++p;
352
353
0
    p += pack_nodes(announce->log, p, nodes_max_length, nodes_list, num_nodes);
354
355
0
    const uint32_t reply_len = p - reply;
356
357
0
    if (previous_hash != nullptr) {
358
0
        uint8_t hash[CRYPTO_SHA256_SIZE];
359
360
0
        crypto_sha256(hash, reply, reply_len);
361
362
0
        if (crypto_sha256_eq(hash, previous_hash)) {
363
0
            return CRYPTO_PUBLIC_KEY_SIZE;
364
0
        }
365
0
    }
366
367
0
    return reply_len;
368
0
}
369
370
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,
371
        uint8_t *_Nonnull reply, uint16_t reply_max_length, const uint8_t *_Nonnull to_auth, uint16_t to_auth_length)
372
0
{
373
0
    if (length != CRYPTO_PUBLIC_KEY_SIZE + 1 + TIMED_AUTH_SIZE) {
374
0
        return -1;
375
0
    }
376
377
0
    if (data[CRYPTO_PUBLIC_KEY_SIZE] != 0) {
378
0
        return -1;
379
0
    }
380
381
0
    const uint8_t *const data_public_key = data;
382
0
    const uint8_t *const auth = data + CRYPTO_PUBLIC_KEY_SIZE + 1;
383
384
0
    if (!check_timed_auth(announce->mono_time, DATA_SEARCH_TIMEOUT, announce->hmac_key,
385
0
                          to_auth, to_auth_length, auth)) {
386
0
        return -1;
387
0
    }
388
389
0
    const Announce_Entry *const entry = get_stored_const(announce, data_public_key);
390
391
0
    if (entry == nullptr) {
392
0
        return -1;
393
0
    }
394
395
0
    const uint16_t reply_len = CRYPTO_PUBLIC_KEY_SIZE + 1 + entry->length;
396
397
0
    if (reply_max_length < reply_len) {
398
0
        return -1;
399
0
    }
400
401
0
    memcpy(reply, data_public_key, CRYPTO_PUBLIC_KEY_SIZE);
402
0
    reply[CRYPTO_PUBLIC_KEY_SIZE] = 1;
403
0
    memcpy(reply + CRYPTO_PUBLIC_KEY_SIZE + 1, entry->data, entry->length);
404
405
0
    return reply_len;
406
0
}
407
408
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,
409
        uint16_t reply_max_length, const uint8_t *_Nonnull to_auth, uint16_t to_auth_length)
410
0
{
411
0
    const int plain_len = (int)length - (CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE + CRYPTO_MAC_SIZE);
412
0
    const int announcement_len = plain_len - (TIMED_AUTH_SIZE + sizeof(uint32_t) + 1);
413
414
0
    const uint8_t *const data_public_key = data;
415
416
0
    if (announcement_len < 0) {
417
0
        return -1;
418
0
    }
419
420
0
    VLA(uint8_t, plain, plain_len);
421
422
0
    const uint8_t *shared_key = shared_key_cache_lookup(announce->shared_keys, data_public_key);
423
424
0
    if (shared_key == nullptr) {
425
        /* Error looking up/deriving the shared key */
426
0
        return -1;
427
0
    }
428
429
0
    if (decrypt_data_symmetric(announce->mem, shared_key,
430
0
                               data + CRYPTO_PUBLIC_KEY_SIZE,
431
0
                               data + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE,
432
0
                               plain_len + CRYPTO_MAC_SIZE,
433
0
                               plain) != plain_len) {
434
0
        return -1;
435
0
    }
436
437
0
    const uint8_t *const auth = plain;
438
0
    uint32_t requested_timeout;
439
0
    net_unpack_u32(plain + TIMED_AUTH_SIZE, &requested_timeout);
440
0
    const uint32_t timeout = calculate_timeout(announce, requested_timeout);
441
0
    const uint8_t announcement_type = plain[TIMED_AUTH_SIZE + sizeof(uint32_t)];
442
0
    const uint8_t *announcement = plain + TIMED_AUTH_SIZE + sizeof(uint32_t) + 1;
443
444
0
    if (!check_timed_auth(announce->mono_time, DATA_SEARCH_TIMEOUT, announce->hmac_key,
445
0
                          to_auth, to_auth_length, auth)) {
446
0
        return -1;
447
0
    }
448
449
0
    if (announcement_type > 1) {
450
0
        return -1;
451
0
    }
452
453
0
    if (announcement_type == 1) {
454
0
        if (announcement_len != CRYPTO_SHA256_SIZE) {
455
0
            return -1;
456
0
        }
457
458
0
        Announce_Entry *stored = get_stored(announce, data_public_key);
459
460
0
        if (stored == nullptr) {
461
0
            return -1;
462
0
        }
463
464
0
        uint8_t stored_hash[CRYPTO_SHA256_SIZE];
465
0
        crypto_sha256(stored_hash, stored->data, stored->length);
466
467
0
        if (!crypto_sha256_eq(announcement, stored_hash)) {
468
0
            delete_entry(stored);
469
0
            return -1;
470
0
        } else {
471
0
            stored->store_until = mono_time_get(announce->mono_time) + timeout;
472
0
        }
473
0
    } else {
474
0
        if (!announce_store_data(announce, data_public_key, announcement, announcement_len, timeout)) {
475
0
            return -1;
476
0
        }
477
0
    }
478
479
0
    const uint16_t reply_len = CRYPTO_PUBLIC_KEY_SIZE + sizeof(uint32_t) + sizeof(uint64_t);
480
481
0
    if (reply_max_length < reply_len) {
482
0
        return -1;
483
0
    }
484
485
0
    memcpy(reply, data_public_key, CRYPTO_PUBLIC_KEY_SIZE);
486
0
    net_pack_u32(reply + CRYPTO_PUBLIC_KEY_SIZE, timeout);
487
0
    net_pack_u64(reply + CRYPTO_PUBLIC_KEY_SIZE + sizeof(uint32_t),
488
0
                 mono_time_get(announce->mono_time) + announce->synch_offset);
489
0
    return reply_len;
490
0
}
491
492
static int create_reply_plain(Announcements *_Nonnull announce,
493
                              const uint8_t *_Nonnull requester_key, const IP_Port *_Nonnull source, uint8_t type,
494
                              const uint8_t *_Nullable sendback, uint16_t sendback_length,
495
                              const uint8_t *_Nonnull data, uint16_t length,
496
                              uint8_t *_Nonnull reply, uint16_t reply_max_length)
497
0
{
498
0
    if (length < CRYPTO_PUBLIC_KEY_SIZE) {
499
0
        return -1;
500
0
    }
501
502
0
    const uint8_t *const data_public_key = data;
503
504
0
    uint8_t to_auth[DATA_SEARCH_TO_AUTH_MAX_SIZE];
505
0
    const int to_auth_length = create_data_search_to_auth(announce->log, data_public_key, requester_key, source,
506
0
                               sendback, sendback_length, to_auth, DATA_SEARCH_TO_AUTH_MAX_SIZE);
507
508
0
    if (to_auth_length == -1) {
509
0
        return -1;
510
0
    }
511
512
0
    switch (type) {
513
0
        case NET_PACKET_DATA_SEARCH_REQUEST:
514
0
            return create_reply_plain_data_search_request(announce, source, data, length, reply, reply_max_length, to_auth,
515
0
                    (uint16_t)to_auth_length);
516
517
0
        case NET_PACKET_DATA_RETRIEVE_REQUEST:
518
0
            return create_reply_plain_data_retrieve_request(announce, source, data, length, reply, reply_max_length, to_auth,
519
0
                    (uint16_t)to_auth_length);
520
521
0
        case NET_PACKET_STORE_ANNOUNCE_REQUEST:
522
0
            return create_reply_plain_store_announce_request(announce, source, data, length, reply, reply_max_length, to_auth,
523
0
                    (uint16_t)to_auth_length);
524
525
0
        default:
526
0
            return -1;
527
0
    }
528
0
}
529
530
static int create_reply(Announcements *_Nonnull announce, const IP_Port *_Nonnull source,
531
                        const uint8_t *_Nullable sendback, uint16_t sendback_length,
532
                        const uint8_t *_Nonnull data, uint16_t length,
533
                        uint8_t *_Nonnull reply, uint16_t reply_max_length)
534
0
{
535
0
    const int plain_len = (int)length - (1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE + CRYPTO_MAC_SIZE);
536
0
    if (plain_len < (int)sizeof(uint64_t)) {
537
0
        return -1;
538
0
    }
539
540
0
    VLA(uint8_t, plain, plain_len);
541
0
    const uint8_t *shared_key = dht_get_shared_key_recv(announce->dht, data + 1);
542
543
0
    if (decrypt_data_symmetric(announce->mem, shared_key,
544
0
                               data + 1 + CRYPTO_PUBLIC_KEY_SIZE,
545
0
                               data + 1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE,
546
0
                               plain_len + CRYPTO_MAC_SIZE,
547
0
                               plain) != plain_len) {
548
0
        return -1;
549
0
    }
550
551
0
    const int plain_reply_max_len = (int)reply_max_length -
552
0
                                    (1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE + CRYPTO_MAC_SIZE);
553
554
0
    if (plain_reply_max_len < (int)sizeof(uint64_t)) {
555
0
        return -1;
556
0
    }
557
558
0
    VLA(uint8_t, plain_reply, plain_reply_max_len);
559
560
0
    const int plain_reply_noping_len = create_reply_plain(announce,
561
0
                                       data + 1, source, data[0],
562
0
                                       sendback, sendback_length,
563
0
                                       plain, plain_len - sizeof(uint64_t),
564
0
                                       plain_reply, plain_reply_max_len - sizeof(uint64_t));
565
566
0
    if (plain_reply_noping_len == -1) {
567
0
        return -1;
568
0
    }
569
570
0
    memcpy(plain_reply + plain_reply_noping_len,
571
0
           plain + (plain_len - sizeof(uint64_t)), sizeof(uint64_t));
572
573
0
    const uint16_t plain_reply_len = plain_reply_noping_len + sizeof(uint64_t);
574
575
0
    const uint8_t response_type = announce_response_of_request_type(data[0]);
576
577
0
    return dht_create_packet(announce->mem, announce->rng, announce->public_key, shared_key,
578
0
                             response_type, plain_reply, plain_reply_len, reply, reply_max_length);
579
0
}
580
581
static void forwarded_request_callback(void *_Nonnull object, const IP_Port *_Nonnull forwarder,
582
                                       const uint8_t *_Nonnull sendback, uint16_t sendback_length,
583
                                       const uint8_t *_Nonnull data, uint16_t length, void *_Nullable userdata)
584
0
{
585
0
    Announcements *announce = (Announcements *) object;
586
0
    uint8_t reply[MAX_FORWARD_DATA_SIZE];
587
588
0
    const int len = create_reply(announce, forwarder,
589
0
                                 sendback, sendback_length,
590
0
                                 data, length, reply, sizeof(reply));
591
592
0
    if (len == -1) {
593
0
        return;
594
0
    }
595
596
0
    forward_reply(announce->net, forwarder, sendback, sendback_length, reply, len);
597
0
}
598
599
static int handle_dht_announce_request(
600
    void *_Nonnull object, const IP_Port *_Nonnull source, const uint8_t *_Nonnull packet, uint16_t length, void *_Nullable userdata)
601
0
{
602
0
    Announcements *announce = (Announcements *)object;
603
0
    uint8_t reply[MAX_FORWARD_DATA_SIZE];
604
605
0
    const int len
606
0
        = create_reply(announce, source, nullptr, 0, packet, length, reply, sizeof(reply));
607
608
0
    if (len == -1) {
609
0
        return -1;
610
0
    }
611
612
0
    return sendpacket(announce->net, source, reply, len) == len ? 0 : -1;
613
0
}
614
615
Announcements *new_announcements(const Logger *log, const Memory *mem, const Random *rng, const Mono_Time *mono_time,
616
                                 Forwarding *forwarding)
617
1.96k
{
618
1.96k
    if (log == nullptr || mono_time == nullptr || forwarding == nullptr) {
619
0
        return nullptr;
620
0
    }
621
622
1.96k
    Announcements *announce = (Announcements *)mem_alloc(mem, sizeof(Announcements));
623
624
1.96k
    if (announce == nullptr) {
625
0
        return nullptr;
626
0
    }
627
628
1.96k
    announce->log = log;
629
1.96k
    announce->mem = mem;
630
1.96k
    announce->rng = rng;
631
1.96k
    announce->forwarding = forwarding;
632
1.96k
    announce->mono_time = mono_time;
633
1.96k
    announce->dht = forwarding_get_dht(forwarding);
634
1.96k
    announce->net = dht_get_net(announce->dht);
635
1.96k
    announce->public_key = dht_get_self_public_key(announce->dht);
636
1.96k
    announce->secret_key = dht_get_self_secret_key(announce->dht);
637
1.96k
    new_hmac_key(announce->rng, announce->hmac_key);
638
1.96k
    announce->shared_keys = shared_key_cache_new(log, mono_time, mem, announce->secret_key, KEYS_TIMEOUT, MAX_KEYS_PER_SLOT);
639
1.96k
    if (announce->shared_keys == nullptr) {
640
0
        mem_delete(announce->mem, announce);
641
0
        return nullptr;
642
0
    }
643
644
1.96k
    announce->start_time = mono_time_get(announce->mono_time);
645
646
1.96k
    set_callback_forwarded_request(forwarding, forwarded_request_callback, announce);
647
648
1.96k
    networking_registerhandler(announce->net, NET_PACKET_DATA_SEARCH_REQUEST, handle_dht_announce_request, announce);
649
1.96k
    networking_registerhandler(announce->net, NET_PACKET_DATA_RETRIEVE_REQUEST, handle_dht_announce_request, announce);
650
1.96k
    networking_registerhandler(announce->net, NET_PACKET_STORE_ANNOUNCE_REQUEST, handle_dht_announce_request, announce);
651
652
1.96k
    return announce;
653
1.96k
}
654
655
void kill_announcements(Announcements *announce)
656
1.96k
{
657
1.96k
    if (announce == nullptr) {
658
0
        return;
659
0
    }
660
661
1.96k
    set_callback_forwarded_request(announce->forwarding, nullptr, nullptr);
662
663
1.96k
    networking_registerhandler(announce->net, NET_PACKET_DATA_SEARCH_REQUEST, nullptr, nullptr);
664
1.96k
    networking_registerhandler(announce->net, NET_PACKET_DATA_RETRIEVE_REQUEST, nullptr, nullptr);
665
1.96k
    networking_registerhandler(announce->net, NET_PACKET_STORE_ANNOUNCE_REQUEST, nullptr, nullptr);
666
667
1.96k
    crypto_memzero(announce->hmac_key, CRYPTO_HMAC_KEY_SIZE);
668
1.96k
    shared_key_cache_free(announce->shared_keys);
669
670
505k
    for (uint32_t i = 0; i < ANNOUNCE_BUCKETS * ANNOUNCE_BUCKET_SIZE; ++i) {
671
503k
        mem_delete(announce->mem, announce->entries[i].data);
672
503k
    }
673
674
1.96k
    mem_delete(announce->mem, announce);
675
1.96k
}