Coverage Report

Created: 2026-02-01 10:37

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/c-toxcore/toxcore/DHT.c
Line
Count
Source
1
/* SPDX-License-Identifier: GPL-3.0-or-later
2
 * Copyright © 2016-2025 The TokTok team.
3
 * Copyright © 2013 Tox project.
4
 */
5
6
/**
7
 * An implementation of the DHT as seen in docs/updates/DHT.md
8
 */
9
#include "DHT.h"
10
11
#include <assert.h>
12
#include <string.h>
13
14
#include "LAN_discovery.h"
15
#include "attributes.h"
16
#include "bin_pack.h"
17
#include "ccompat.h"
18
#include "crypto_core.h"
19
#include "logger.h"
20
#include "mem.h"
21
#include "mono_time.h"
22
#include "network.h"
23
#include "ping.h"
24
#include "ping_array.h"
25
#include "shared_key_cache.h"
26
#include "sort.h"
27
#include "state.h"
28
29
/** The timeout after which a node is discarded completely. */
30
0
#define KILL_NODE_TIMEOUT (BAD_NODE_TIMEOUT + PING_INTERVAL)
31
32
/** Ping interval in seconds for each random sending of a nodes request. */
33
0
#define NODES_REQUEST_INTERVAL 20
34
35
0
#define MAX_PUNCHING_PORTS 48
36
37
/** Interval in seconds between punching attempts*/
38
0
#define PUNCH_INTERVAL 3
39
40
/** Time in seconds after which punching parameters will be reset */
41
0
#define PUNCH_RESET_TIME 40
42
43
0
#define MAX_NORMAL_PUNCHING_TRIES 5
44
45
0
#define NAT_PING_REQUEST    0
46
0
#define NAT_PING_RESPONSE   1
47
48
/** Number of node requests to send to quickly find close nodes. */
49
0
#define MAX_BOOTSTRAP_TIMES 5
50
51
// TODO(sudden6): find out why we need multiple callbacks and if we really need 32
52
6.36k
#define DHT_FRIEND_MAX_LOCKS 32
53
54
/* Settings for the shared key cache */
55
3.20k
#define MAX_KEYS_PER_SLOT 4
56
3.20k
#define KEYS_TIMEOUT 600
57
58
typedef struct NAT {
59
    /* true if currently hole punching */
60
    bool        hole_punching;
61
    uint32_t    punching_index;
62
    uint32_t    tries;
63
    uint32_t    punching_index2;
64
65
    uint64_t    punching_timestamp;
66
    uint64_t    recv_nat_ping_timestamp;
67
    uint64_t    nat_ping_id;
68
    uint64_t    nat_ping_timestamp;
69
} NAT;
70
71
typedef struct DHT_Friend_Callback {
72
    dht_ip_cb *_Nullable ip_callback;
73
    void *_Nullable data;
74
    int32_t number;
75
} DHT_Friend_Callback;
76
77
struct DHT_Friend {
78
    uint8_t     public_key[CRYPTO_PUBLIC_KEY_SIZE];
79
    Client_data client_list[MAX_FRIEND_CLIENTS];
80
81
    /* Time at which the last nodes request was sent. */
82
    uint64_t    last_nodes_request;
83
    /* number of times nodes request packets were sent. */
84
    uint32_t    bootstrap_times;
85
86
    /* Symmetric NAT hole punching stuff. */
87
    NAT         nat;
88
89
    /* Each set bit represents one installed callback */
90
    uint32_t lock_flags;
91
    DHT_Friend_Callback callbacks[DHT_FRIEND_MAX_LOCKS];
92
93
    Node_format to_bootstrap[MAX_SENT_NODES];
94
    unsigned int num_to_bootstrap;
95
};
96
97
static const DHT_Friend empty_dht_friend = {{0}};
98
const Node_format empty_node_format = {{0}};
99
100
static_assert(sizeof(empty_dht_friend.lock_flags) * 8 == DHT_FRIEND_MAX_LOCKS, "Bitfield size and number of locks don't match");
101
102
typedef struct Cryptopacket_Handler {
103
    cryptopacket_handler_cb *_Nullable function;
104
    void *_Nullable object;
105
} Cryptopacket_Handler;
106
107
struct DHT {
108
    const Logger *_Nonnull log;
109
    const Network *_Nonnull ns;
110
    Mono_Time *_Nonnull mono_time;
111
    const Memory *_Nonnull mem;
112
    const Random *_Nonnull rng;
113
    Networking_Core *_Nonnull net;
114
115
    bool hole_punching_enabled;
116
    bool lan_discovery_enabled;
117
118
    Client_data    close_clientlist[LCLIENT_LIST];
119
    uint64_t       close_last_nodes_request;
120
    uint32_t       close_bootstrap_times;
121
122
    /* DHT keypair */
123
    uint8_t self_public_key[CRYPTO_PUBLIC_KEY_SIZE];
124
    uint8_t self_secret_key[CRYPTO_SECRET_KEY_SIZE];
125
126
    DHT_Friend    *_Nullable friends_list;
127
    uint16_t       num_friends;
128
129
    Node_format   *_Nullable loaded_nodes_list;
130
    uint32_t       loaded_num_nodes;
131
    unsigned int   loaded_nodes_index;
132
133
    Shared_Key_Cache *_Nonnull shared_keys_recv;
134
    Shared_Key_Cache *_Nonnull shared_keys_sent;
135
136
    struct Ping   *_Nonnull ping;
137
    Ping_Array    *_Nonnull dht_ping_array;
138
    uint64_t       cur_time;
139
140
    Cryptopacket_Handler cryptopackethandlers[256];
141
142
    Node_format to_bootstrap[MAX_CLOSE_TO_BOOTSTRAP_NODES];
143
    unsigned int num_to_bootstrap;
144
145
    dht_nodes_response_cb *_Nullable nodes_response_callback;
146
};
147
148
const uint8_t *dht_friend_public_key(const DHT_Friend *dht_friend)
149
0
{
150
0
    return dht_friend->public_key;
151
0
}
152
153
const Client_data *dht_friend_client(const DHT_Friend *dht_friend, size_t index)
154
224
{
155
224
    return &dht_friend->client_list[index];
156
224
}
157
158
const uint8_t *dht_get_self_public_key(const DHT *dht)
159
9.81k
{
160
9.81k
    return dht->self_public_key;
161
9.81k
}
162
const uint8_t *dht_get_self_secret_key(const DHT *dht)
163
6.33k
{
164
6.33k
    return dht->self_secret_key;
165
6.33k
}
166
167
void dht_set_self_public_key(DHT *dht, const uint8_t *key)
168
0
{
169
0
    memcpy(dht->self_public_key, key, CRYPTO_PUBLIC_KEY_SIZE);
170
0
}
171
void dht_set_self_secret_key(DHT *dht, const uint8_t *key)
172
0
{
173
0
    memcpy(dht->self_secret_key, key, CRYPTO_SECRET_KEY_SIZE);
174
0
}
175
176
struct Ping *dht_get_ping(const DHT *dht)
177
0
{
178
0
    return dht->ping;
179
0
}
180
const Client_data *dht_get_close_clientlist(const DHT *dht)
181
0
{
182
0
    return dht->close_clientlist;
183
0
}
184
const Client_data *dht_get_close_client(const DHT *dht, uint32_t client_num)
185
14.3k
{
186
14.3k
    assert(client_num < sizeof(dht->close_clientlist) / sizeof(dht->close_clientlist[0]));
187
14.3k
    return &dht->close_clientlist[client_num];
188
14.3k
}
189
uint16_t dht_get_num_friends(const DHT *dht)
190
28
{
191
28
    return dht->num_friends;
192
28
}
193
194
DHT_Friend *dht_get_friend(DHT *dht, uint32_t friend_num)
195
28
{
196
28
    assert(friend_num < dht->num_friends);
197
28
    return &dht->friends_list[friend_num];
198
28
}
199
const uint8_t *dht_get_friend_public_key(const DHT *dht, uint32_t friend_num)
200
0
{
201
0
    assert(friend_num < dht->num_friends);
202
0
    return dht->friends_list[friend_num].public_key;
203
0
}
204
205
static bool assoc_timeout(uint64_t cur_time, const IPPTsPng *_Nonnull assoc)
206
3.32M
{
207
3.32M
    return (assoc->timestamp + BAD_NODE_TIMEOUT) <= cur_time;
208
3.32M
}
209
210
/** @brief Converts an IPv4-in-IPv6 to IPv4 and returns the new IP_Port.
211
 *
212
 * If the ip_port is already IPv4 this function returns a copy of the original ip_port.
213
 */
214
static IP_Port ip_port_normalize(const IP_Port *_Nonnull ip_port)
215
0
{
216
0
    IP_Port res = *ip_port;
217
218
0
    if (net_family_is_ipv6(res.ip.family) && ipv6_ipv4_in_v6(&res.ip.ip.v6)) {
219
0
        res.ip.family = net_family_ipv4();
220
0
        res.ip.ip.v4.uint32 = res.ip.ip.v6.uint32[3];
221
0
    }
222
223
0
    return res;
224
0
}
225
226
int id_closest(const uint8_t *pk, const uint8_t *pk1, const uint8_t *pk2)
227
142
{
228
4.68k
    for (size_t i = 0; i < CRYPTO_PUBLIC_KEY_SIZE; ++i) {
229
4.54k
        const uint8_t distance1 = pk[i] ^ pk1[i];
230
4.54k
        const uint8_t distance2 = pk[i] ^ pk2[i];
231
232
4.54k
        if (distance1 < distance2) {
233
0
            return 1;
234
0
        }
235
236
4.54k
        if (distance1 > distance2) {
237
0
            return 2;
238
0
        }
239
4.54k
    }
240
241
142
    return 0;
242
142
}
243
244
/** Return index of first unequal bit number between public keys pk1 and pk2. */
245
unsigned int bit_by_bit_cmp(const uint8_t *pk1, const uint8_t *pk2)
246
0
{
247
0
    unsigned int i;
248
0
    unsigned int j = 0;
249
250
0
    for (i = 0; i < CRYPTO_PUBLIC_KEY_SIZE; ++i) {
251
0
        if (pk1[i] == pk2[i]) {
252
0
            continue;
253
0
        }
254
255
0
        for (j = 0; j < 8; ++j) {
256
0
            const uint8_t mask = 1 << (7 - j);
257
258
0
            if ((pk1[i] & mask) != (pk2[i] & mask)) {
259
0
                break;
260
0
            }
261
0
        }
262
263
0
        break;
264
0
    }
265
266
0
    return i * 8 + j;
267
0
}
268
269
/**
270
 * Copy shared_key to encrypt/decrypt DHT packet from public_key into shared_key
271
 * for packets that we receive.
272
 */
273
const uint8_t *dht_get_shared_key_recv(DHT *dht, const uint8_t *public_key)
274
0
{
275
0
    return shared_key_cache_lookup(dht->shared_keys_recv, public_key);
276
0
}
277
278
/**
279
 * Copy shared_key to encrypt/decrypt DHT packet from public_key into shared_key
280
 * for packets that we send.
281
 */
282
const uint8_t *dht_get_shared_key_sent(DHT *dht, const uint8_t *public_key)
283
9
{
284
9
    return shared_key_cache_lookup(dht->shared_keys_sent, public_key);
285
9
}
286
287
6
#define CRYPTO_SIZE (1 + CRYPTO_PUBLIC_KEY_SIZE * 2 + CRYPTO_NONCE_SIZE)
288
289
int create_request(const Memory *mem, const Random *rng, const uint8_t *send_public_key, const uint8_t *send_secret_key,
290
                   uint8_t *packet, const uint8_t *recv_public_key,
291
                   const uint8_t *data, uint32_t data_length, uint8_t request_id)
292
0
{
293
0
    if (send_public_key == nullptr || packet == nullptr || recv_public_key == nullptr || data == nullptr) {
294
0
        return -1;
295
0
    }
296
297
0
    if (MAX_CRYPTO_REQUEST_SIZE < data_length + CRYPTO_SIZE + 1 + CRYPTO_MAC_SIZE) {
298
0
        return -1;
299
0
    }
300
301
0
    uint8_t *const nonce = packet + 1 + CRYPTO_PUBLIC_KEY_SIZE * 2;
302
0
    random_nonce(rng, nonce);
303
0
    uint8_t temp[MAX_CRYPTO_REQUEST_SIZE] = {0};
304
0
    temp[0] = request_id;
305
0
    memcpy(temp + 1, data, data_length);
306
0
    const int len = encrypt_data(mem, recv_public_key, send_secret_key, nonce, temp, data_length + 1,
307
0
                                 packet + CRYPTO_SIZE);
308
309
0
    if (len == -1) {
310
0
        crypto_memzero(temp, MAX_CRYPTO_REQUEST_SIZE);
311
0
        return -1;
312
0
    }
313
314
0
    packet[0] = NET_PACKET_CRYPTO;
315
0
    memcpy(packet + 1, recv_public_key, CRYPTO_PUBLIC_KEY_SIZE);
316
0
    memcpy(packet + 1 + CRYPTO_PUBLIC_KEY_SIZE, send_public_key, CRYPTO_PUBLIC_KEY_SIZE);
317
318
0
    crypto_memzero(temp, MAX_CRYPTO_REQUEST_SIZE);
319
0
    return len + CRYPTO_SIZE;
320
0
}
321
322
int handle_request(const Memory *mem, const uint8_t *self_public_key, const uint8_t *self_secret_key, uint8_t *public_key, uint8_t *data,
323
                   uint8_t *request_id, const uint8_t *packet, uint16_t packet_length)
324
4
{
325
4
    if (self_public_key == nullptr || public_key == nullptr || data == nullptr || request_id == nullptr
326
4
            || packet == nullptr) {
327
0
        return -1;
328
0
    }
329
330
4
    if (packet_length <= CRYPTO_SIZE + CRYPTO_MAC_SIZE || packet_length > MAX_CRYPTO_REQUEST_SIZE) {
331
2
        return -1;
332
2
    }
333
334
2
    if (!pk_equal(packet + 1, self_public_key)) {
335
1
        return -1;
336
1
    }
337
338
1
    memcpy(public_key, packet + 1 + CRYPTO_PUBLIC_KEY_SIZE, CRYPTO_PUBLIC_KEY_SIZE);
339
1
    const uint8_t *const nonce = packet + 1 + CRYPTO_PUBLIC_KEY_SIZE * 2;
340
1
    uint8_t temp[MAX_CRYPTO_REQUEST_SIZE];
341
1
    int32_t len1 = decrypt_data(mem, public_key, self_secret_key, nonce,
342
1
                                packet + CRYPTO_SIZE, packet_length - CRYPTO_SIZE, temp);
343
344
1
    if (len1 == -1 || len1 == 0) {
345
0
        crypto_memzero(temp, MAX_CRYPTO_REQUEST_SIZE);
346
0
        return -1;
347
0
    }
348
349
1
    assert(len1 == packet_length - CRYPTO_SIZE - CRYPTO_MAC_SIZE);
350
    // Because coverity can't figure out this equation:
351
1
    assert(len1 <= MAX_CRYPTO_REQUEST_SIZE - CRYPTO_SIZE - CRYPTO_MAC_SIZE);
352
353
1
    request_id[0] = temp[0];
354
1
    --len1;
355
1
    memcpy(data, temp + 1, len1);
356
1
    crypto_memzero(temp, MAX_CRYPTO_REQUEST_SIZE);
357
1
    return len1;
358
1
}
359
360
int packed_node_size(Family ip_family)
361
11.7k
{
362
11.7k
    if (net_family_is_ipv4(ip_family) || net_family_is_tcp_ipv4(ip_family)) {
363
2.94k
        return PACKED_NODE_SIZE_IP4;
364
2.94k
    }
365
366
8.83k
    if (net_family_is_ipv6(ip_family) || net_family_is_tcp_ipv6(ip_family)) {
367
8.83k
        return PACKED_NODE_SIZE_IP6;
368
8.83k
    }
369
370
0
    return -1;
371
8.83k
}
372
373
int dht_create_packet(const Memory *mem, const Random *rng,
374
                      const uint8_t public_key[CRYPTO_PUBLIC_KEY_SIZE],
375
                      const uint8_t *shared_key, const uint8_t type,
376
                      const uint8_t *plain, size_t plain_length,
377
                      uint8_t *packet, size_t length)
378
9
{
379
9
    uint8_t nonce[CRYPTO_NONCE_SIZE];
380
9
    uint8_t *encrypted = (uint8_t *)mem_balloc(mem, plain_length + CRYPTO_MAC_SIZE);
381
382
9
    if (encrypted == nullptr) {
383
1
        return -1;
384
1
    }
385
386
8
    random_nonce(rng, nonce);
387
388
8
    const int encrypted_length = encrypt_data_symmetric(mem, shared_key, nonce, plain, plain_length, encrypted);
389
390
8
    if (encrypted_length < 0) {
391
0
        mem_delete(mem, encrypted);
392
0
        return -1;
393
0
    }
394
395
8
    if (length < 1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE + (size_t)encrypted_length) {
396
0
        mem_delete(mem, encrypted);
397
0
        return -1;
398
0
    }
399
400
8
    packet[0] = type;
401
8
    memcpy(packet + 1, public_key, CRYPTO_PUBLIC_KEY_SIZE);
402
8
    memcpy(packet + 1 + CRYPTO_PUBLIC_KEY_SIZE, nonce, CRYPTO_NONCE_SIZE);
403
8
    memcpy(packet + 1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE, encrypted, encrypted_length);
404
405
8
    mem_delete(mem, encrypted);
406
8
    return 1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE + encrypted_length;
407
8
}
408
409
/** @brief Pack a single node from a node array.
410
 *
411
 * @retval true on success.
412
 */
413
static bool bin_pack_node_handler(const void *_Nonnull arr, uint32_t index, const Logger *_Nonnull logger, Bin_Pack *_Nonnull bp)
414
9.75k
{
415
9.75k
    const Node_format *nodes = (const Node_format *)arr;
416
9.75k
    return bin_pack_ip_port(bp, logger, &nodes[index].ip_port)
417
9.75k
           && bin_pack_bin_b(bp, nodes[index].public_key, CRYPTO_PUBLIC_KEY_SIZE);
418
9.75k
}
419
420
int pack_nodes(const Logger *logger, uint8_t *data, uint16_t length, const Node_format *nodes, uint16_t number)
421
4.26k
{
422
4.26k
    const uint32_t size = bin_pack_obj_array_b_size(bin_pack_node_handler, nodes, number, logger);
423
4.26k
    if (!bin_pack_obj_array_b(bin_pack_node_handler, nodes, number, logger, data, length)) {
424
0
        return -1;
425
0
    }
426
4.26k
    return size;
427
4.26k
}
428
429
int unpack_nodes(Node_format *nodes, uint16_t max_num_nodes, uint16_t *processed_data_len, const uint8_t *data,
430
                 uint16_t length, bool tcp_enabled)
431
4.10k
{
432
4.10k
    uint32_t num = 0;
433
4.10k
    uint32_t len_processed = 0;
434
435
15.6k
    while (num < max_num_nodes && len_processed < length) {
436
12.5k
        const int ipp_size = unpack_ip_port(&nodes[num].ip_port, data + len_processed, length - len_processed, tcp_enabled);
437
438
12.5k
        if (ipp_size == -1) {
439
853
            break;
440
853
        }
441
442
11.6k
        len_processed += ipp_size;
443
444
11.6k
        if (len_processed + CRYPTO_PUBLIC_KEY_SIZE > length) {
445
177
            return -1;
446
177
        }
447
448
11.5k
        memcpy(nodes[num].public_key, data + len_processed, CRYPTO_PUBLIC_KEY_SIZE);
449
11.5k
        len_processed += CRYPTO_PUBLIC_KEY_SIZE;
450
11.5k
        ++num;
451
452
11.5k
#ifndef NDEBUG
453
11.5k
        const uint32_t increment = ipp_size + CRYPTO_PUBLIC_KEY_SIZE;
454
11.5k
        assert(increment == PACKED_NODE_SIZE_IP4 || increment == PACKED_NODE_SIZE_IP6);
455
11.5k
#endif /* NDEBUG */
456
11.5k
    }
457
458
3.92k
    if (num == 0 && max_num_nodes > 0 && length > 0) {
459
380
        return -1;
460
380
    }
461
462
3.54k
    if (processed_data_len != nullptr) {
463
2.20k
        *processed_data_len = len_processed;
464
2.20k
    }
465
466
3.54k
    return num;
467
3.92k
}
468
469
/** @brief Find index in an array with public_key equal to pk.
470
 *
471
 * @return index or UINT32_MAX if not found.
472
 */
473
static uint32_t index_of_client_pk(const Client_data *_Nullable array, uint32_t size, const uint8_t *_Nonnull pk)
474
0
{
475
0
    assert(size == 0 || array != nullptr);
476
0
    for (uint32_t i = 0; i < size; ++i) {
477
0
        if (pk_equal(array[i].public_key, pk)) {
478
0
            return i;
479
0
        }
480
0
    }
481
482
0
    return UINT32_MAX;
483
0
}
484
485
static uint32_t index_of_friend_pk(const DHT_Friend *_Nullable array, uint32_t size, const uint8_t *_Nonnull pk)
486
3.18k
{
487
3.18k
    assert(size == 0 || array != nullptr);
488
4.78k
    for (uint32_t i = 0; i < size; ++i) {
489
1.59k
        if (pk_equal(array[i].public_key, pk)) {
490
0
            return i;
491
0
        }
492
1.59k
    }
493
494
3.18k
    return UINT32_MAX;
495
3.18k
}
496
497
static uint32_t index_of_node_pk(const Node_format *_Nullable array, uint32_t size, const uint8_t *_Nonnull pk)
498
0
{
499
0
    assert(size == 0 || array != nullptr);
500
0
    for (uint32_t i = 0; i < size; ++i) {
501
0
        if (pk_equal(array[i].public_key, pk)) {
502
0
            return i;
503
0
        }
504
0
    }
505
506
0
    return UINT32_MAX;
507
0
}
508
509
/** @brief Find index of Client_data with ip_port equal to param ip_port.
510
 *
511
 * @return index or UINT32_MAX if not found.
512
 */
513
static uint32_t index_of_client_ip_port(const Client_data *_Nullable array, uint32_t size, const IP_Port *_Nonnull ip_port)
514
0
{
515
0
    assert(size == 0 || array != nullptr);
516
0
    for (uint32_t i = 0; i < size; ++i) {
517
0
        if ((net_family_is_ipv4(ip_port->ip.family) && ipport_equal(&array[i].assoc4.ip_port, ip_port)) ||
518
0
                (net_family_is_ipv6(ip_port->ip.family) && ipport_equal(&array[i].assoc6.ip_port, ip_port))) {
519
0
            return i;
520
0
        }
521
0
    }
522
523
0
    return UINT32_MAX;
524
0
}
525
526
/** Update ip_port of client if it's needed. */
527
static void update_client(const Logger *_Nonnull log, const Mono_Time *_Nonnull mono_time, int index, Client_data *_Nonnull client, const IP_Port *_Nonnull ip_port)
528
0
{
529
0
    IPPTsPng *assoc;
530
0
    int ip_version;
531
532
0
    if (net_family_is_ipv4(ip_port->ip.family)) {
533
0
        assoc = &client->assoc4;
534
0
        ip_version = 4;
535
0
    } else if (net_family_is_ipv6(ip_port->ip.family)) {
536
0
        assoc = &client->assoc6;
537
0
        ip_version = 6;
538
0
    } else {
539
0
        return;
540
0
    }
541
542
0
    if (!ipport_equal(&assoc->ip_port, ip_port)) {
543
0
        Ip_Ntoa ip_str_from;
544
0
        Ip_Ntoa ip_str_to;
545
0
        LOGGER_TRACE(log, "coipil[%u]: switching ipv%d from %s:%u to %s:%u",
546
0
                     (unsigned int)index, ip_version,
547
0
                     net_ip_ntoa(&assoc->ip_port.ip, &ip_str_from),
548
0
                     net_ntohs(assoc->ip_port.port),
549
0
                     net_ip_ntoa(&ip_port->ip, &ip_str_to),
550
0
                     net_ntohs(ip_port->port));
551
0
    }
552
553
0
    if (!ip_is_lan(&assoc->ip_port.ip) && ip_is_lan(&ip_port->ip)) {
554
0
        return;
555
0
    }
556
557
0
    assoc->ip_port = *ip_port;
558
0
    assoc->timestamp = mono_time_get(mono_time);
559
0
}
560
561
/** @brief Check if client with public_key is already in list of length length.
562
 *
563
 * If it is then set its corresponding timestamp to current time.
564
 * If the id is already in the list with a different ip_port, update it.
565
 * TODO(irungentoo): Maybe optimize this.
566
 */
567
static bool client_or_ip_port_in_list(const Logger *_Nonnull log, const Mono_Time *_Nonnull mono_time, Client_data *_Nonnull list, uint16_t length, const uint8_t *_Nonnull public_key,
568
                                      const IP_Port *_Nonnull ip_port)
569
0
{
570
0
    const uint64_t temp_time = mono_time_get(mono_time);
571
0
    uint32_t index = index_of_client_pk(list, length, public_key);
572
573
    /* if public_key is in list, find it and maybe overwrite ip_port */
574
0
    if (index != UINT32_MAX) {
575
0
        update_client(log, mono_time, index, &list[index], ip_port);
576
0
        return true;
577
0
    }
578
579
    /* public_key not in list yet: see if we can find an identical ip_port, in
580
     * that case we kill the old public_key by overwriting it with the new one
581
     * TODO(irungentoo): maybe we SHOULDN'T do that if that public_key is in a friend_list
582
     * and the one who is the actual friend's public_key/address set?
583
     * MAYBE: check the other address, if valid, don't nuke? */
584
0
    index = index_of_client_ip_port(list, length, ip_port);
585
586
0
    if (index == UINT32_MAX) {
587
0
        return false;
588
0
    }
589
590
0
    IPPTsPng *assoc;
591
0
    int ip_version;
592
593
0
    if (net_family_is_ipv4(ip_port->ip.family)) {
594
0
        assoc = &list[index].assoc4;
595
0
        ip_version = 4;
596
0
    } else {
597
0
        assoc = &list[index].assoc6;
598
0
        ip_version = 6;
599
0
    }
600
601
    /* Initialize client timestamp. */
602
0
    assoc->timestamp = temp_time;
603
0
    memcpy(list[index].public_key, public_key, CRYPTO_PUBLIC_KEY_SIZE);
604
605
0
    LOGGER_DEBUG(log, "coipil[%u]: switching public_key (ipv%d)", index, ip_version);
606
607
    /* kill the other address, if it was set.
608
     * We just updated `assoc` (which is either assoc4 or assoc6) with the new public_key.
609
     * If there was an association for the other IP version, it's now invalid for this new identity.
610
     */
611
0
    if (ip_version == 4) {
612
0
        const IPPTsPng empty_ipptspng = {{{{0}}}};
613
0
        list[index].assoc6 = empty_ipptspng;
614
0
    } else {
615
0
        const IPPTsPng empty_ipptspng = {{{{0}}}};
616
0
        list[index].assoc4 = empty_ipptspng;
617
0
    }
618
619
0
    return true;
620
0
}
621
622
bool add_to_list(
623
    Node_format *nodes_list, uint32_t length, const uint8_t pk[CRYPTO_PUBLIC_KEY_SIZE],
624
    const IP_Port *ip_port, const uint8_t cmp_pk[CRYPTO_PUBLIC_KEY_SIZE])
625
0
{
626
0
    uint8_t pk_cur[CRYPTO_PUBLIC_KEY_SIZE];
627
0
    memcpy(pk_cur, pk, CRYPTO_PUBLIC_KEY_SIZE);
628
0
    IP_Port ip_port_cur = *ip_port;
629
630
0
    bool inserted = false;
631
632
0
    for (uint32_t i = 0; i < length; ++i) {
633
0
        Node_format *node = &nodes_list[i];
634
635
0
        if (id_closest(cmp_pk, node->public_key, pk_cur) == 2) {
636
0
            uint8_t pk_bak[CRYPTO_PUBLIC_KEY_SIZE];
637
0
            memcpy(pk_bak, node->public_key, CRYPTO_PUBLIC_KEY_SIZE);
638
0
            const IP_Port ip_port_bak = node->ip_port;
639
640
0
            memcpy(node->public_key, pk_cur, CRYPTO_PUBLIC_KEY_SIZE);
641
0
            node->ip_port = ip_port_cur;
642
643
0
            memcpy(pk_cur, pk_bak, CRYPTO_PUBLIC_KEY_SIZE);
644
0
            ip_port_cur = ip_port_bak;
645
0
            inserted = true;
646
0
        }
647
0
    }
648
649
0
    return inserted;
650
0
}
651
652
/**
653
 * helper for `get_close_nodes()`. argument list is a monster :D
654
 */
655
static void get_close_nodes_inner(uint64_t cur_time, const uint8_t *_Nonnull public_key, Node_format *_Nonnull nodes_list, uint32_t *_Nonnull num_nodes_ptr, Family sa_family,
656
                                  const Client_data *_Nonnull client_list, uint32_t client_list_length, bool is_lan, bool want_announce)
657
7.95k
{
658
7.95k
    if (!net_family_is_ipv4(sa_family) && !net_family_is_ipv6(sa_family) && !net_family_is_unspec(sa_family)) {
659
0
        return;
660
0
    }
661
662
7.95k
    uint32_t num_nodes = *num_nodes_ptr;
663
664
3.30M
    for (uint32_t i = 0; i < client_list_length; ++i) {
665
3.29M
        const Client_data *const client = &client_list[i];
666
3.29M
        const IPPTsPng *ipptp;
667
668
3.29M
        if (net_family_is_ipv4(sa_family)) {
669
0
            ipptp = &client->assoc4;
670
3.29M
        } else if (net_family_is_ipv6(sa_family)) {
671
0
            ipptp = &client->assoc6;
672
3.29M
        } else if (client->assoc4.timestamp >= client->assoc6.timestamp) {
673
3.29M
            ipptp = &client->assoc4;
674
3.29M
        } else {
675
0
            ipptp = &client->assoc6;
676
0
        }
677
678
        /* node not in a good condition? */
679
3.29M
        if (assoc_timeout(cur_time, ipptp)) {
680
3.29M
            continue;
681
3.29M
        }
682
683
        /* don't send LAN ips to non LAN peers */
684
0
        if (ip_is_lan(&ipptp->ip_port.ip) && !is_lan) {
685
0
            continue;
686
0
        }
687
688
0
#ifdef CHECK_ANNOUNCE_NODE
689
690
0
        if (want_announce && !client->announce_node) {
691
0
            continue;
692
0
        }
693
694
0
#endif /* CHECK_ANNOUNCE_NODE */
695
696
        /* node already in list? */
697
0
        if (index_of_node_pk(nodes_list, num_nodes, client->public_key) != UINT32_MAX) {
698
0
            continue;
699
0
        }
700
701
0
        if (num_nodes < MAX_SENT_NODES) {
702
0
            memcpy(nodes_list[num_nodes].public_key, client->public_key, CRYPTO_PUBLIC_KEY_SIZE);
703
0
            nodes_list[num_nodes].ip_port = ipptp->ip_port;
704
0
            ++num_nodes;
705
0
        } else {
706
            // TODO(zugz): this could be made significantly more efficient by
707
            // using a version of add_to_list which works with a sorted list.
708
0
            add_to_list(nodes_list, MAX_SENT_NODES, client->public_key, &ipptp->ip_port, public_key);
709
0
        }
710
0
    }
711
712
7.95k
    *num_nodes_ptr = num_nodes;
713
7.95k
}
714
715
/**
716
 * Find MAX_SENT_NODES nodes closest to the public_key for the nodes request:
717
 * put them in the nodes_list and return how many were found.
718
 *
719
 * want_announce: return only nodes which implement the dht announcements protocol.
720
 */
721
static int get_somewhat_close_nodes(uint64_t cur_time, const uint8_t *_Nonnull public_key, Node_format nodes_list[_Nonnull MAX_SENT_NODES], Family sa_family,
722
                                    const Client_data *_Nonnull close_clientlist, const DHT_Friend *_Nonnull friends_list, uint16_t friends_list_size, bool is_lan, bool want_announce)
723
3.18k
{
724
15.9k
    for (uint16_t i = 0; i < MAX_SENT_NODES; ++i) {
725
12.7k
        nodes_list[i] = empty_node_format;
726
12.7k
    }
727
728
3.18k
    uint32_t num_nodes = 0;
729
3.18k
    get_close_nodes_inner(
730
3.18k
        cur_time, public_key,
731
3.18k
        nodes_list, &num_nodes,
732
3.18k
        sa_family, close_clientlist, LCLIENT_LIST,
733
3.18k
        is_lan, want_announce);
734
735
7.95k
    for (uint16_t i = 0; i < friends_list_size; ++i) {
736
4.77k
        const DHT_Friend *dht_friend = &friends_list[i];
737
738
4.77k
        get_close_nodes_inner(
739
4.77k
            cur_time, public_key,
740
4.77k
            nodes_list, &num_nodes,
741
4.77k
            sa_family, dht_friend->client_list, MAX_FRIEND_CLIENTS,
742
4.77k
            is_lan, want_announce);
743
4.77k
    }
744
745
3.18k
    return num_nodes;
746
3.18k
}
747
748
int get_close_nodes(
749
    const DHT *dht, const uint8_t *public_key,
750
    Node_format nodes_list[MAX_SENT_NODES], Family sa_family,
751
    bool is_lan, bool want_announce)
752
3.18k
{
753
3.18k
    return get_somewhat_close_nodes(
754
3.18k
               dht->cur_time, public_key, nodes_list,
755
3.18k
               sa_family, dht->close_clientlist,
756
3.18k
               dht->friends_list, dht->num_friends,
757
3.18k
               is_lan, want_announce);
758
3.18k
}
759
760
#ifdef CHECK_ANNOUNCE_NODE
761
static void set_announce_node_in_list(Client_data *_Nonnull list, uint32_t list_len, const uint8_t *_Nonnull public_key)
762
0
{
763
0
    const uint32_t index = index_of_client_pk(list, list_len, public_key);
764
765
0
    if (index != UINT32_MAX) {
766
0
        list[index].announce_node = true;
767
0
    }
768
0
}
769
770
void set_announce_node(DHT *dht, const uint8_t *public_key)
771
0
{
772
0
    unsigned int index = bit_by_bit_cmp(public_key, dht->self_public_key);
773
774
0
    if (index >= LCLIENT_LENGTH) {
775
0
        index = LCLIENT_LENGTH - 1;
776
0
    }
777
778
0
    set_announce_node_in_list(dht->close_clientlist + index * LCLIENT_NODES, LCLIENT_NODES, public_key);
779
780
0
    for (int32_t i = 0; i < dht->num_friends; ++i) {
781
0
        set_announce_node_in_list(dht->friends_list[i].client_list, MAX_FRIEND_CLIENTS, public_key);
782
0
    }
783
0
}
784
785
/** @brief Send data search request, searching for a random key. */
786
static bool send_announce_ping(DHT *_Nonnull dht, const uint8_t *_Nonnull public_key, const IP_Port *_Nonnull ip_port)
787
0
{
788
0
    uint8_t plain[CRYPTO_PUBLIC_KEY_SIZE + sizeof(uint64_t)];
789
790
0
    uint8_t unused_secret_key[CRYPTO_SECRET_KEY_SIZE];
791
0
    crypto_new_keypair(dht->rng, plain, unused_secret_key);
792
793
0
    const uint64_t ping_id = ping_array_add(dht->dht_ping_array,
794
0
                                            dht->mono_time,
795
0
                                            dht->rng,
796
0
                                            public_key, CRYPTO_PUBLIC_KEY_SIZE);
797
0
    memcpy(plain + CRYPTO_PUBLIC_KEY_SIZE, &ping_id, sizeof(ping_id));
798
799
0
    const uint8_t *shared_key = dht_get_shared_key_sent(dht, public_key);
800
801
0
    uint8_t request[1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE + sizeof(plain) + CRYPTO_MAC_SIZE];
802
803
0
    if (dht_create_packet(dht->mem, dht->rng,
804
0
                          dht->self_public_key, shared_key, NET_PACKET_DATA_SEARCH_REQUEST,
805
0
                          plain, sizeof(plain), request, sizeof(request)) != sizeof(request)) {
806
0
        return false;
807
0
    }
808
809
0
    return sendpacket(dht->net, ip_port, request, sizeof(request)) == sizeof(request);
810
0
}
811
812
/** @brief If the response is valid, set the sender as an announce node. */
813
static int handle_data_search_response(void *_Nonnull object, const IP_Port *_Nonnull source,
814
                                       const uint8_t *_Nonnull packet, uint16_t length,
815
                                       void *_Nullable userdata)
816
0
{
817
0
    DHT *dht = (DHT *) object;
818
0
    const int32_t plain_len = (int32_t)length - (1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE + CRYPTO_MAC_SIZE);
819
820
0
    if (plain_len < (int32_t)(CRYPTO_PUBLIC_KEY_SIZE + sizeof(uint64_t))) {
821
0
        return 1;
822
0
    }
823
824
0
    VLA(uint8_t, plain, plain_len);
825
0
    const uint8_t *public_key = packet + 1;
826
0
    const uint8_t *shared_key = dht_get_shared_key_recv(dht, public_key);
827
828
0
    if (decrypt_data_symmetric(dht->mem, shared_key,
829
0
                               packet + 1 + CRYPTO_PUBLIC_KEY_SIZE,
830
0
                               packet + 1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE,
831
0
                               plain_len + CRYPTO_MAC_SIZE,
832
0
                               plain) != plain_len) {
833
0
        return 1;
834
0
    }
835
836
0
    uint64_t ping_id;
837
0
    memcpy(&ping_id, plain + (plain_len - sizeof(uint64_t)), sizeof(ping_id));
838
839
0
    uint8_t ping_data[CRYPTO_PUBLIC_KEY_SIZE];
840
841
0
    if (ping_array_check(dht->dht_ping_array,
842
0
                         dht->mono_time, ping_data,
843
0
                         sizeof(ping_data), ping_id) != sizeof(ping_data)) {
844
0
        return 1;
845
0
    }
846
847
0
    if (!pk_equal(ping_data, public_key)) {
848
0
        return 1;
849
0
    }
850
851
0
    set_announce_node(dht, public_key);
852
853
0
    return 0;
854
855
0
}
856
#endif /* CHECK_ANNOUNCE_NODE */
857
858
/** @brief Is it ok to store node with public_key in client.
859
 *
860
 * return false if node can't be stored.
861
 * return true if it can.
862
 */
863
static bool store_node_ok(const Client_data *_Nonnull client, uint64_t cur_time, const uint8_t *_Nonnull public_key, const uint8_t *_Nonnull comp_public_key)
864
0
{
865
0
    return (assoc_timeout(cur_time, &client->assoc4)
866
0
            && assoc_timeout(cur_time, &client->assoc6))
867
0
           || id_closest(comp_public_key, client->public_key, public_key) == 2;
868
0
}
869
870
typedef struct Client_data_Cmp {
871
    const Memory *_Nonnull mem;
872
    uint64_t cur_time;
873
    const uint8_t *_Nonnull comp_public_key;
874
} Client_data_Cmp;
875
876
static int client_data_cmp(const Client_data_Cmp *_Nonnull cmp, const Client_data *_Nonnull entry1, const Client_data *_Nonnull entry2)
877
0
{
878
0
    const bool t1 = assoc_timeout(cmp->cur_time, &entry1->assoc4) && assoc_timeout(cmp->cur_time, &entry1->assoc6);
879
0
    const bool t2 = assoc_timeout(cmp->cur_time, &entry2->assoc4) && assoc_timeout(cmp->cur_time, &entry2->assoc6);
880
881
0
    if (t1 && t2) {
882
0
        return 0;
883
0
    }
884
885
0
    if (t1) {
886
0
        return -1;
887
0
    }
888
889
0
    if (t2) {
890
0
        return 1;
891
0
    }
892
893
0
    const int closest = id_closest(cmp->comp_public_key, entry1->public_key, entry2->public_key);
894
895
0
    if (closest == 1) {
896
0
        return 1;
897
0
    }
898
899
0
    if (closest == 2) {
900
0
        return -1;
901
0
    }
902
903
0
    return 0;
904
0
}
905
906
static bool client_data_less_handler(const void *_Nonnull object, const void *_Nonnull a, const void *_Nonnull b)
907
0
{
908
0
    const Client_data_Cmp *cmp = (const Client_data_Cmp *)object;
909
0
    const Client_data *entry1 = (const Client_data *)a;
910
0
    const Client_data *entry2 = (const Client_data *)b;
911
912
0
    return client_data_cmp(cmp, entry1, entry2) < 0;
913
0
}
914
915
static const void *client_data_get_handler(const void *_Nonnull arr, uint32_t index)
916
0
{
917
0
    const Client_data *entries = (const Client_data *)arr;
918
0
    return &entries[index];
919
0
}
920
921
static void client_data_set_handler(void *_Nonnull arr, uint32_t index, const void *_Nonnull val)
922
0
{
923
0
    Client_data *entries = (Client_data *)arr;
924
0
    const Client_data *entry = (const Client_data *)val;
925
0
    entries[index] = *entry;
926
0
}
927
928
static void *client_data_subarr_handler(void *_Nonnull arr, uint32_t index, uint32_t size)
929
0
{
930
0
    Client_data *entries = (Client_data *)arr;
931
0
    return &entries[index];
932
0
}
933
934
static void *client_data_alloc_handler(const void *_Nonnull object, uint32_t size)
935
0
{
936
0
    const Client_data_Cmp *cmp = (const Client_data_Cmp *)object;
937
0
    Client_data *tmp = (Client_data *)mem_valloc(cmp->mem, size, sizeof(Client_data));
938
939
0
    if (tmp == nullptr) {
940
0
        return nullptr;
941
0
    }
942
943
0
    return tmp;
944
0
}
945
946
static void client_data_delete_handler(const void *_Nonnull object, void *_Nonnull arr, uint32_t size)
947
0
{
948
0
    const Client_data_Cmp *cmp = (const Client_data_Cmp *)object;
949
0
    mem_delete(cmp->mem, arr);
950
0
}
951
952
static const Sort_Funcs client_data_cmp_funcs = {
953
    client_data_less_handler,
954
    client_data_get_handler,
955
    client_data_set_handler,
956
    client_data_subarr_handler,
957
    client_data_alloc_handler,
958
    client_data_delete_handler,
959
};
960
961
static void sort_client_list(const Memory *_Nonnull mem, Client_data *_Nonnull list, uint64_t cur_time, unsigned int length, const uint8_t *_Nonnull comp_public_key)
962
0
{
963
    // Pass comp_public_key to merge_sort with each Client_data entry, so the
964
    // comparison function can use it as the base of comparison.
965
0
    const Client_data_Cmp cmp = {
966
0
        mem,
967
0
        cur_time,
968
0
        comp_public_key,
969
0
    };
970
971
0
    merge_sort(list, length, &cmp, &client_data_cmp_funcs);
972
0
}
973
974
static void update_client_with_reset(const Mono_Time *_Nonnull mono_time, Client_data *_Nonnull client, const IP_Port *_Nonnull ip_port)
975
0
{
976
0
    IPPTsPng *ipptp_write = nullptr;
977
0
    IPPTsPng *ipptp_clear = nullptr;
978
979
0
    if (net_family_is_ipv4(ip_port->ip.family)) {
980
0
        ipptp_write = &client->assoc4;
981
0
        ipptp_clear = &client->assoc6;
982
0
    } else {
983
0
        ipptp_write = &client->assoc6;
984
0
        ipptp_clear = &client->assoc4;
985
0
    }
986
987
0
    ipptp_write->ip_port = *ip_port;
988
0
    ipptp_write->timestamp = mono_time_get(mono_time);
989
990
0
    ip_reset(&ipptp_write->ret_ip_port.ip);
991
0
    ipptp_write->ret_ip_port.port = 0;
992
0
    ipptp_write->ret_timestamp = 0;
993
0
    ipptp_write->ret_ip_self = false;
994
995
    /* zero out other address */
996
0
    const IPPTsPng empty_ipptp = {{{{0}}}};
997
0
    *ipptp_clear = empty_ipptp;
998
0
}
999
1000
/**
1001
 * Replace a first bad (or empty) node with this one
1002
 * or replace a possibly bad node (tests failed or not done yet)
1003
 * that is further than any other in the list
1004
 * from the comp_public_key
1005
 * or replace a good node that is further
1006
 * than any other in the list from the comp_public_key
1007
 * and further than public_key.
1008
 *
1009
 * Do not replace any node if the list has no bad or possibly bad nodes
1010
 * and all nodes in the list are closer to comp_public_key
1011
 * than public_key.
1012
 *
1013
 * @return true when the item was stored, false otherwise
1014
 */
1015
static bool replace_all(const DHT *_Nonnull dht, Client_data *_Nonnull list, uint16_t length, const uint8_t *_Nonnull public_key, const IP_Port *_Nonnull ip_port,
1016
                        const uint8_t *_Nonnull comp_public_key)
1017
0
{
1018
0
    if (!net_family_is_ipv4(ip_port->ip.family) && !net_family_is_ipv6(ip_port->ip.family)) {
1019
0
        return false;
1020
0
    }
1021
1022
0
    if (!store_node_ok(&list[1], dht->cur_time, public_key, comp_public_key) &&
1023
0
            !store_node_ok(&list[0], dht->cur_time, public_key, comp_public_key)) {
1024
0
        return false;
1025
0
    }
1026
1027
0
    sort_client_list(dht->mem, list, dht->cur_time, length, comp_public_key);
1028
1029
0
    Client_data *const client = &list[0];
1030
0
    pk_copy(client->public_key, public_key);
1031
1032
0
    update_client_with_reset(dht->mono_time, client, ip_port);
1033
0
    return true;
1034
0
}
1035
1036
/** @brief Add node to close list.
1037
 *
1038
 * simulate is set to 1 if we want to check if a node can be added to the list without adding it.
1039
 *
1040
 * return false on failure.
1041
 * return true on success.
1042
 */
1043
static bool add_to_close(DHT *_Nonnull dht, const uint8_t *_Nonnull public_key, const IP_Port *_Nonnull ip_port, bool simulate)
1044
0
{
1045
0
    unsigned int index = bit_by_bit_cmp(public_key, dht->self_public_key);
1046
1047
0
    if (index >= LCLIENT_LENGTH) {
1048
0
        index = LCLIENT_LENGTH - 1;
1049
0
    }
1050
1051
0
    for (uint32_t i = 0; i < LCLIENT_NODES; ++i) {
1052
        /* TODO(iphydf): write bounds checking test to catch the case that
1053
         * index is left as >= LCLIENT_LENGTH */
1054
0
        Client_data *const client = &dht->close_clientlist[(index * LCLIENT_NODES) + i];
1055
1056
0
        if (!assoc_timeout(dht->cur_time, &client->assoc4) ||
1057
0
                !assoc_timeout(dht->cur_time, &client->assoc6)) {
1058
0
            continue;
1059
0
        }
1060
1061
0
        if (simulate) {
1062
0
            return true;
1063
0
        }
1064
1065
0
        pk_copy(client->public_key, public_key);
1066
0
        update_client_with_reset(dht->mono_time, client, ip_port);
1067
0
#ifdef CHECK_ANNOUNCE_NODE
1068
0
        client->announce_node = false;
1069
0
        send_announce_ping(dht, public_key, ip_port);
1070
0
#endif /* CHECK_ANNOUNCE_NODE */
1071
0
        return true;
1072
0
    }
1073
1074
0
    return false;
1075
0
}
1076
1077
/** Return 1 if node can be added to close list, 0 if it can't. */
1078
bool node_addable_to_close_list(DHT *dht, const uint8_t *public_key, const IP_Port *ip_port)
1079
0
{
1080
0
    return add_to_close(dht, public_key, ip_port, true);
1081
0
}
1082
1083
static bool is_pk_in_client_list(const Client_data *_Nonnull list, unsigned int client_list_length, uint64_t cur_time, const uint8_t *_Nonnull public_key, const IP_Port *_Nonnull ip_port)
1084
0
{
1085
0
    const uint32_t index = index_of_client_pk(list, client_list_length, public_key);
1086
1087
0
    if (index == UINT32_MAX) {
1088
0
        return false;
1089
0
    }
1090
1091
0
    const IPPTsPng *assoc = net_family_is_ipv4(ip_port->ip.family)
1092
0
                            ? &list[index].assoc4
1093
0
                            : &list[index].assoc6;
1094
1095
0
    return !assoc_timeout(cur_time, assoc);
1096
0
}
1097
1098
static bool is_pk_in_close_list(const DHT *_Nonnull dht, const uint8_t *_Nonnull public_key, const IP_Port *_Nonnull ip_port)
1099
0
{
1100
0
    unsigned int index = bit_by_bit_cmp(public_key, dht->self_public_key);
1101
1102
0
    if (index >= LCLIENT_LENGTH) {
1103
0
        index = LCLIENT_LENGTH - 1;
1104
0
    }
1105
1106
0
    return is_pk_in_client_list(dht->close_clientlist + index * LCLIENT_NODES, LCLIENT_NODES, dht->cur_time, public_key,
1107
0
                                ip_port);
1108
0
}
1109
1110
/** @brief Check if the node obtained from a nodes response with public_key should be pinged.
1111
 *
1112
 * NOTE: for best results call it after addto_lists.
1113
 *
1114
 * return false if the node should not be pinged.
1115
 * return true if it should.
1116
 */
1117
static bool ping_node_from_nodes_response_ok(DHT *_Nonnull dht, const uint8_t *_Nonnull public_key, const IP_Port *_Nonnull ip_port)
1118
0
{
1119
0
    bool ret = false;
1120
1121
0
    if (add_to_close(dht, public_key, ip_port, true)) {
1122
0
        ret = true;
1123
0
    }
1124
1125
0
    {
1126
0
        unsigned int *const num = &dht->num_to_bootstrap;
1127
0
        const uint32_t index = index_of_node_pk(dht->to_bootstrap, *num, public_key);
1128
0
        const bool in_close_list = is_pk_in_close_list(dht, public_key, ip_port);
1129
1130
0
        if (ret && index == UINT32_MAX && !in_close_list) {
1131
0
            if (*num < MAX_CLOSE_TO_BOOTSTRAP_NODES) {
1132
0
                memcpy(dht->to_bootstrap[*num].public_key, public_key, CRYPTO_PUBLIC_KEY_SIZE);
1133
0
                dht->to_bootstrap[*num].ip_port = *ip_port;
1134
0
                ++*num;
1135
0
            } else {
1136
                // TODO(irungentoo): ipv6 vs v4
1137
0
                add_to_list(dht->to_bootstrap, MAX_CLOSE_TO_BOOTSTRAP_NODES, public_key, ip_port, dht->self_public_key);
1138
0
            }
1139
0
        }
1140
0
    }
1141
1142
0
    for (uint32_t i = 0; i < dht->num_friends; ++i) {
1143
0
        DHT_Friend *dht_friend = &dht->friends_list[i];
1144
1145
0
        bool store_ok = false;
1146
1147
0
        if (store_node_ok(&dht_friend->client_list[1], dht->cur_time, public_key, dht_friend->public_key)) {
1148
0
            store_ok = true;
1149
0
        }
1150
1151
0
        if (store_node_ok(&dht_friend->client_list[0], dht->cur_time, public_key, dht_friend->public_key)) {
1152
0
            store_ok = true;
1153
0
        }
1154
1155
0
        unsigned int *const friend_num = &dht_friend->num_to_bootstrap;
1156
0
        const uint32_t index = index_of_node_pk(dht_friend->to_bootstrap, *friend_num, public_key);
1157
0
        const bool pk_in_list = is_pk_in_client_list(dht_friend->client_list, MAX_FRIEND_CLIENTS, dht->cur_time, public_key,
1158
0
                                ip_port);
1159
1160
0
        if (store_ok && index == UINT32_MAX && !pk_in_list) {
1161
0
            if (*friend_num < MAX_SENT_NODES) {
1162
0
                Node_format *const format = &dht_friend->to_bootstrap[*friend_num];
1163
0
                memcpy(format->public_key, public_key, CRYPTO_PUBLIC_KEY_SIZE);
1164
0
                format->ip_port = *ip_port;
1165
0
                ++*friend_num;
1166
0
            } else {
1167
0
                add_to_list(dht_friend->to_bootstrap, MAX_SENT_NODES, public_key, ip_port, dht_friend->public_key);
1168
0
            }
1169
1170
0
            ret = true;
1171
0
        }
1172
0
    }
1173
1174
0
    return ret;
1175
0
}
1176
1177
/** @brief Attempt to add client with ip_port and public_key to the friends client list
1178
 * and close_clientlist.
1179
 *
1180
 * @return 1+ if the item is used in any list, 0 else
1181
 */
1182
uint32_t addto_lists(DHT *dht, const IP_Port *ip_port, const uint8_t *public_key)
1183
0
{
1184
0
    const IP_Port ipp_copy = ip_port_normalize(ip_port);
1185
1186
0
    uint32_t used = 0;
1187
1188
    /* NOTE: Current behavior if there are two clients with the same id is
1189
     * to replace the first ip by the second.
1190
     */
1191
0
    const bool in_close_list = client_or_ip_port_in_list(dht->log, dht->mono_time, dht->close_clientlist, LCLIENT_LIST,
1192
0
                               public_key, &ipp_copy);
1193
1194
    /* add_to_close should be called only if !in_list (don't extract to variable) */
1195
0
    if (in_close_list || !add_to_close(dht, public_key, &ipp_copy, false)) {
1196
0
        ++used;
1197
0
    }
1198
1199
0
    const DHT_Friend *friend_foundip = nullptr;
1200
1201
0
    for (uint32_t i = 0; i < dht->num_friends; ++i) {
1202
0
        const bool in_list = client_or_ip_port_in_list(dht->log, dht->mono_time, dht->friends_list[i].client_list,
1203
0
                             MAX_FRIEND_CLIENTS, public_key, &ipp_copy);
1204
1205
        /* replace_all should be called only if !in_list (don't extract to variable) */
1206
0
        if (in_list
1207
0
                || replace_all(dht, dht->friends_list[i].client_list, MAX_FRIEND_CLIENTS, public_key, &ipp_copy,
1208
0
                               dht->friends_list[i].public_key)) {
1209
0
            const DHT_Friend *dht_friend = &dht->friends_list[i];
1210
1211
0
            if (pk_equal(public_key, dht_friend->public_key)) {
1212
0
                friend_foundip = dht_friend;
1213
0
            }
1214
1215
0
            ++used;
1216
0
        }
1217
0
    }
1218
1219
0
    if (friend_foundip == nullptr) {
1220
0
        return used;
1221
0
    }
1222
1223
0
    for (uint32_t i = 0; i < DHT_FRIEND_MAX_LOCKS; ++i) {
1224
0
        const bool has_lock = (friend_foundip->lock_flags & (UINT32_C(1) << i)) > 0;
1225
0
        if (has_lock && friend_foundip->callbacks[i].ip_callback != nullptr) {
1226
0
            friend_foundip->callbacks[i].ip_callback(friend_foundip->callbacks[i].data,
1227
0
                    friend_foundip->callbacks[i].number, &ipp_copy);
1228
0
        }
1229
0
    }
1230
1231
0
    return used;
1232
0
}
1233
1234
static bool update_client_data(const Mono_Time *_Nonnull mono_time, Client_data *_Nonnull array, size_t size, const IP_Port *_Nonnull ip_port, const uint8_t *_Nonnull pk, bool node_is_self)
1235
0
{
1236
0
    const uint64_t temp_time = mono_time_get(mono_time);
1237
0
    const uint32_t index = index_of_client_pk(array, size, pk);
1238
1239
0
    if (index == UINT32_MAX) {
1240
0
        return false;
1241
0
    }
1242
1243
0
    Client_data *const data = &array[index];
1244
0
    IPPTsPng *assoc;
1245
1246
0
    if (net_family_is_ipv4(ip_port->ip.family)) {
1247
0
        assoc = &data->assoc4;
1248
0
    } else if (net_family_is_ipv6(ip_port->ip.family)) {
1249
0
        assoc = &data->assoc6;
1250
0
    } else {
1251
0
        return true;
1252
0
    }
1253
1254
0
    assoc->ret_ip_port = *ip_port;
1255
0
    assoc->ret_timestamp = temp_time;
1256
0
    assoc->ret_ip_self = node_is_self;
1257
1258
0
    return true;
1259
0
}
1260
1261
/**
1262
 * If public_key is a friend or us, update ret_ip_port
1263
 * nodepublic_key is the id of the node that sent us this info.
1264
 */
1265
static void returnedip_ports(DHT *_Nonnull dht, const IP_Port *_Nonnull ip_port, const uint8_t *_Nonnull public_key, const uint8_t *_Nonnull nodepublic_key)
1266
0
{
1267
0
    const IP_Port ipp_copy = ip_port_normalize(ip_port);
1268
1269
0
    if (pk_equal(public_key, dht->self_public_key)) {
1270
0
        update_client_data(dht->mono_time, dht->close_clientlist, LCLIENT_LIST, &ipp_copy, nodepublic_key, true);
1271
0
        return;
1272
0
    }
1273
1274
0
    for (uint32_t i = 0; i < dht->num_friends; ++i) {
1275
0
        if (pk_equal(public_key, dht->friends_list[i].public_key)) {
1276
0
            Client_data *const client_list = dht->friends_list[i].client_list;
1277
1278
0
            if (update_client_data(dht->mono_time, client_list, MAX_FRIEND_CLIENTS, &ipp_copy, nodepublic_key, false)) {
1279
0
                return;
1280
0
            }
1281
0
        }
1282
0
    }
1283
0
}
1284
1285
bool dht_send_nodes_request(DHT *dht, const IP_Port *ip_port, const uint8_t *public_key, const uint8_t *client_id)
1286
11
{
1287
    /* Check if packet is going to be sent to ourself. */
1288
11
    if (pk_equal(public_key, dht->self_public_key)) {
1289
0
        return false;
1290
0
    }
1291
1292
11
    uint8_t plain_message[sizeof(Node_format) * 2] = {0};
1293
1294
11
    Node_format receiver;
1295
11
    memcpy(receiver.public_key, public_key, CRYPTO_PUBLIC_KEY_SIZE);
1296
11
    receiver.ip_port = *ip_port;
1297
1298
11
    if (pack_nodes(dht->log, plain_message, sizeof(plain_message), &receiver, 1) == -1) {
1299
0
        return false;
1300
0
    }
1301
1302
11
    uint64_t ping_id = 0;
1303
1304
11
    ping_id = ping_array_add(dht->dht_ping_array, dht->mono_time, dht->rng, plain_message, sizeof(receiver));
1305
1306
11
    if (ping_id == 0) {
1307
2
        LOGGER_ERROR(dht->log, "adding ping id failed");
1308
2
        return false;
1309
2
    }
1310
1311
9
    uint8_t plain[CRYPTO_PUBLIC_KEY_SIZE + sizeof(ping_id)];
1312
9
    uint8_t data[1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE + sizeof(plain) + CRYPTO_MAC_SIZE];
1313
1314
9
    memcpy(plain, client_id, CRYPTO_PUBLIC_KEY_SIZE);
1315
9
    memcpy(plain + CRYPTO_PUBLIC_KEY_SIZE, &ping_id, sizeof(ping_id));
1316
1317
9
    const uint8_t *shared_key = dht_get_shared_key_sent(dht, public_key);
1318
1319
9
    const int len = dht_create_packet(dht->mem, dht->rng,
1320
9
                                      dht->self_public_key, shared_key, NET_PACKET_NODES_REQUEST,
1321
9
                                      plain, sizeof(plain), data, sizeof(data));
1322
1323
9
    if (len != sizeof(data)) {
1324
1
        LOGGER_ERROR(dht->log, "nodes request packet encryption failed");
1325
1
        return false;
1326
1
    }
1327
1328
8
    return sendpacket(dht->net, ip_port, data, len) > 0;
1329
9
}
1330
1331
/** Send a nodes response */
1332
static int send_nodes_response(const DHT *_Nonnull dht, const IP_Port *_Nonnull ip_port, const uint8_t *_Nonnull public_key, const uint8_t *_Nonnull client_id,
1333
                               const uint8_t *_Nonnull sendback_data, uint16_t length, const uint8_t *_Nonnull shared_encryption_key)
1334
0
{
1335
    /* Check if packet is going to be sent to ourself. */
1336
0
    if (pk_equal(public_key, dht->self_public_key)) {
1337
0
        return -1;
1338
0
    }
1339
1340
0
    if (length != sizeof(uint64_t)) {
1341
0
        return -1;
1342
0
    }
1343
1344
0
    const size_t node_format_size = sizeof(Node_format);
1345
1346
0
    Node_format nodes_list[MAX_SENT_NODES];
1347
0
    const uint32_t num_nodes =
1348
0
        get_close_nodes(dht, client_id, nodes_list, net_family_unspec(), ip_is_lan(&ip_port->ip), false);
1349
1350
0
    VLA(uint8_t, plain, 1 + node_format_size * MAX_SENT_NODES + length);
1351
1352
0
    int nodes_length = 0;
1353
1354
0
    if (num_nodes > 0) {
1355
0
        nodes_length = pack_nodes(dht->log, plain + 1, node_format_size * MAX_SENT_NODES, nodes_list, num_nodes);
1356
1357
0
        if (nodes_length <= 0) {
1358
0
            return -1;
1359
0
        }
1360
0
    }
1361
1362
0
    plain[0] = num_nodes;
1363
0
    memcpy(plain + 1 + nodes_length, sendback_data, length);
1364
1365
0
    const uint16_t crypto_size = 1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE + CRYPTO_MAC_SIZE;
1366
0
    const uint16_t data_size = 1 + nodes_length + length + crypto_size;
1367
0
    VLA(uint8_t, data, data_size);
1368
1369
0
    const int len = dht_create_packet(dht->mem, dht->rng,
1370
0
                                      dht->self_public_key, shared_encryption_key, NET_PACKET_NODES_RESPONSE,
1371
0
                                      plain, 1 + nodes_length + length, data, data_size);
1372
1373
0
    if (len < 0 || (uint32_t)len != data_size) {
1374
0
        return -1;
1375
0
    }
1376
1377
0
    return sendpacket(dht->net, ip_port, data, len);
1378
0
}
1379
1380
0
#define CRYPTO_NODE_SIZE (CRYPTO_PUBLIC_KEY_SIZE + sizeof(uint64_t))
1381
1382
static int handle_nodes_request(void *_Nonnull object, const IP_Port *_Nonnull source, const uint8_t *_Nonnull packet, uint16_t length, void *_Nonnull userdata)
1383
0
{
1384
0
    DHT *const dht = (DHT *)object;
1385
1386
0
    if (length != (CRYPTO_SIZE + CRYPTO_MAC_SIZE + sizeof(uint64_t))) {
1387
0
        return 1;
1388
0
    }
1389
1390
    /* Check if packet is from ourself. */
1391
0
    if (pk_equal(packet + 1, dht->self_public_key)) {
1392
0
        return 1;
1393
0
    }
1394
1395
0
    uint8_t plain[CRYPTO_NODE_SIZE];
1396
0
    const uint8_t *shared_key = dht_get_shared_key_recv(dht, packet + 1);
1397
0
    const int len = decrypt_data_symmetric(
1398
0
                        dht->mem,
1399
0
                        shared_key,
1400
0
                        packet + 1 + CRYPTO_PUBLIC_KEY_SIZE,
1401
0
                        packet + 1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE,
1402
0
                        CRYPTO_NODE_SIZE + CRYPTO_MAC_SIZE,
1403
0
                        plain);
1404
1405
0
    if (len != CRYPTO_NODE_SIZE) {
1406
0
        return 1;
1407
0
    }
1408
1409
0
    send_nodes_response(dht, source, packet + 1, plain, plain + CRYPTO_PUBLIC_KEY_SIZE, sizeof(uint64_t), shared_key);
1410
1411
0
    ping_add(dht->ping, packet + 1, source);
1412
1413
0
    return 0;
1414
0
}
1415
1416
/** Return true if we sent a nodes request packet to the peer associated with the supplied info. */
1417
static bool sent_nodes_request_to_node(DHT *_Nonnull dht, const uint8_t *_Nonnull public_key, const IP_Port *_Nonnull node_ip_port, uint64_t ping_id)
1418
0
{
1419
0
    uint8_t data[sizeof(Node_format) * 2];
1420
1421
0
    if (ping_array_check(dht->dht_ping_array, dht->mono_time, data, sizeof(data), ping_id) != sizeof(Node_format)) {
1422
0
        return false;
1423
0
    }
1424
1425
0
    Node_format test;
1426
1427
0
    if (unpack_nodes(&test, 1, nullptr, data, sizeof(data), false) != 1) {
1428
0
        return false;
1429
0
    }
1430
1431
0
    return ipport_equal(&test.ip_port, node_ip_port) && pk_equal(test.public_key, public_key);
1432
0
}
1433
1434
static bool handle_nodes_response_core(void *_Nonnull object, const IP_Port *_Nonnull source, const uint8_t *_Nonnull packet, uint16_t length, Node_format *_Nonnull plain_nodes,
1435
                                       uint16_t size_plain_nodes, uint32_t *_Nonnull num_nodes_out)
1436
0
{
1437
0
    DHT *const dht = (DHT *)object;
1438
0
    const uint32_t cid_size = 1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE + 1 + sizeof(uint64_t) + CRYPTO_MAC_SIZE;
1439
1440
0
    if (length < cid_size) { /* too short */
1441
0
        return false;
1442
0
    }
1443
1444
0
    const uint32_t data_size = length - cid_size;
1445
1446
0
    if (data_size == 0) {
1447
0
        return false;
1448
0
    }
1449
1450
0
    if (data_size > sizeof(Node_format) * MAX_SENT_NODES) { /* invalid length */
1451
0
        return false;
1452
0
    }
1453
1454
0
    const uint32_t plain_size = 1 + data_size + sizeof(uint64_t);
1455
0
    VLA(uint8_t, plain, plain_size);
1456
0
    const uint8_t *shared_key = dht_get_shared_key_sent(dht, packet + 1);
1457
0
    const int len = decrypt_data_symmetric(
1458
0
                        dht->mem,
1459
0
                        shared_key,
1460
0
                        packet + 1 + CRYPTO_PUBLIC_KEY_SIZE,
1461
0
                        packet + 1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE,
1462
0
                        1 + data_size + sizeof(uint64_t) + CRYPTO_MAC_SIZE,
1463
0
                        plain);
1464
1465
0
    if ((uint32_t)len != plain_size) {
1466
0
        return false;
1467
0
    }
1468
1469
0
    if (plain[0] > size_plain_nodes) {
1470
0
        return false;
1471
0
    }
1472
1473
0
    uint64_t ping_id;
1474
0
    memcpy(&ping_id, plain + 1 + data_size, sizeof(ping_id));
1475
1476
0
    if (!sent_nodes_request_to_node(dht, packet + 1, source, ping_id)) {
1477
0
        return false;
1478
0
    }
1479
1480
0
    uint16_t length_nodes = 0;
1481
0
    const int num_nodes = unpack_nodes(plain_nodes, plain[0], &length_nodes, plain + 1, data_size, false);
1482
1483
0
    if (length_nodes != data_size) {
1484
0
        return false;
1485
0
    }
1486
1487
0
    if (num_nodes != plain[0]) {
1488
0
        return false;
1489
0
    }
1490
1491
0
    if (num_nodes < 0) {
1492
0
        return false;
1493
0
    }
1494
1495
    /* store the address the *request* was sent to */
1496
0
    addto_lists(dht, source, packet + 1);
1497
1498
0
    *num_nodes_out = num_nodes;
1499
1500
0
    return true;
1501
0
}
1502
1503
static int handle_nodes_response(void *_Nonnull object, const IP_Port *_Nonnull source, const uint8_t *_Nonnull packet, uint16_t length, void *_Nonnull userdata)
1504
0
{
1505
0
    DHT *const dht = (DHT *)object;
1506
0
    Node_format plain_nodes[MAX_SENT_NODES];
1507
0
    uint32_t num_nodes;
1508
1509
0
    if (!handle_nodes_response_core(object, source, packet, length, plain_nodes, MAX_SENT_NODES, &num_nodes)) {
1510
0
        return 1;
1511
0
    }
1512
1513
0
    if (num_nodes == 0) {
1514
0
        return 0;
1515
0
    }
1516
1517
0
    for (uint32_t i = 0; i < num_nodes; ++i) {
1518
0
        if (ipport_isset(&plain_nodes[i].ip_port)) {
1519
0
            ping_node_from_nodes_response_ok(dht, plain_nodes[i].public_key, &plain_nodes[i].ip_port);
1520
0
            returnedip_ports(dht, &plain_nodes[i].ip_port, plain_nodes[i].public_key, packet + 1);
1521
1522
0
            if (dht->nodes_response_callback != nullptr) {
1523
0
                dht->nodes_response_callback(dht, &plain_nodes[i], userdata);
1524
0
            }
1525
0
        }
1526
0
    }
1527
1528
0
    return 0;
1529
0
}
1530
1531
/*----------------------------------------------------------------------------------*/
1532
/*------------------------END of packet handling functions--------------------------*/
1533
1534
static uint32_t dht_friend_lock(DHT_Friend *_Nonnull dht_friend, dht_ip_cb *_Nullable ip_callback,
1535
                                void *_Nullable data, int32_t number)
1536
3.18k
{
1537
    // find first free slot
1538
3.18k
    uint8_t lock_num;
1539
3.18k
    uint32_t lock_token = 0;
1540
3.18k
    for (lock_num = 0; lock_num < DHT_FRIEND_MAX_LOCKS; ++lock_num) {
1541
3.18k
        lock_token = UINT32_C(1) << lock_num;
1542
3.18k
        if ((dht_friend->lock_flags & lock_token) == 0) {
1543
3.18k
            break;
1544
3.18k
        }
1545
3.18k
    }
1546
1547
    // One of the conditions would be enough, but static analyzers don't get that
1548
3.18k
    if (lock_token == 0 || lock_num == DHT_FRIEND_MAX_LOCKS) {
1549
0
        return 0;
1550
0
    }
1551
1552
    // Claim that slot
1553
3.18k
    dht_friend->lock_flags |= lock_token;
1554
1555
3.18k
    dht_friend->callbacks[lock_num].ip_callback = ip_callback;
1556
3.18k
    dht_friend->callbacks[lock_num].data = data;
1557
3.18k
    dht_friend->callbacks[lock_num].number = number;
1558
1559
3.18k
    return lock_token;
1560
3.18k
}
1561
1562
static void dht_friend_unlock(DHT_Friend *_Nonnull dht_friend, uint32_t lock_token)
1563
0
{
1564
    // If this triggers, there was a double free
1565
0
    assert((lock_token & dht_friend->lock_flags) > 0);
1566
1567
    // find used slot
1568
0
    uint8_t lock_num;
1569
0
    for (lock_num = 0; lock_num < DHT_FRIEND_MAX_LOCKS; ++lock_num) {
1570
0
        if (((UINT32_C(1) << lock_num) & lock_token) > 0) {
1571
0
            break;
1572
0
        }
1573
0
    }
1574
1575
0
    if (lock_num == DHT_FRIEND_MAX_LOCKS) {
1576
        // Gracefully handle double unlock
1577
0
        return;
1578
0
    }
1579
1580
    // Clear the slot
1581
0
    dht_friend->lock_flags &= ~lock_token;
1582
1583
0
    dht_friend->callbacks[lock_num].ip_callback = nullptr;
1584
0
    dht_friend->callbacks[lock_num].data = nullptr;
1585
0
    dht_friend->callbacks[lock_num].number = 0;
1586
0
}
1587
1588
int dht_addfriend(DHT *dht, const uint8_t *public_key, dht_ip_cb *ip_callback,
1589
                  void *data, int32_t number, uint32_t *lock_token)
1590
3.18k
{
1591
3.18k
    const uint32_t friend_num = index_of_friend_pk(dht->friends_list, dht->num_friends, public_key);
1592
1593
3.18k
    if (friend_num != UINT32_MAX) { /* Is friend already in DHT? */
1594
0
        DHT_Friend *const dht_friend = &dht->friends_list[friend_num];
1595
0
        const uint32_t tmp_lock_token = dht_friend_lock(dht_friend, ip_callback, data, number);
1596
1597
0
        if (tmp_lock_token == 0) {
1598
0
            return -1;
1599
0
        }
1600
1601
0
        return 0;
1602
0
    }
1603
1604
3.18k
    DHT_Friend *const temp = (DHT_Friend *)mem_vrealloc(dht->mem, dht->friends_list, dht->num_friends + 1, sizeof(DHT_Friend));
1605
1606
3.18k
    if (temp == nullptr) {
1607
4
        return -1;
1608
4
    }
1609
1610
3.18k
    dht->friends_list = temp;
1611
3.18k
    DHT_Friend *const dht_friend = &dht->friends_list[dht->num_friends];
1612
3.18k
    *dht_friend = empty_dht_friend;
1613
3.18k
    memcpy(dht_friend->public_key, public_key, CRYPTO_PUBLIC_KEY_SIZE);
1614
1615
3.18k
    dht_friend->nat.nat_ping_id = random_u64(dht->rng);
1616
3.18k
    ++dht->num_friends;
1617
1618
3.18k
    *lock_token = dht_friend_lock(dht_friend, ip_callback, data, number);
1619
3.18k
    assert(*lock_token != 0); // Friend was newly allocated
1620
1621
3.18k
    dht_friend->num_to_bootstrap = get_close_nodes(dht, dht_friend->public_key, dht_friend->to_bootstrap, net_family_unspec(),
1622
3.18k
                                   true, false);
1623
1624
3.18k
    return 0;
1625
3.18k
}
1626
1627
int dht_delfriend(DHT *dht, const uint8_t *public_key, uint32_t lock_token)
1628
0
{
1629
0
    const uint32_t friend_num = index_of_friend_pk(dht->friends_list, dht->num_friends, public_key);
1630
1631
0
    if (friend_num == UINT32_MAX) {
1632
0
        return -1;
1633
0
    }
1634
1635
0
    DHT_Friend *const dht_friend = &dht->friends_list[friend_num];
1636
0
    dht_friend_unlock(dht_friend, lock_token);
1637
0
    if (dht_friend->lock_flags > 0) {
1638
        /* DHT friend is still in use.*/
1639
0
        return 0;
1640
0
    }
1641
1642
0
    --dht->num_friends;
1643
1644
0
    if (dht->num_friends != friend_num) {
1645
0
        dht->friends_list[friend_num] = dht->friends_list[dht->num_friends];
1646
0
    }
1647
1648
0
    if (dht->num_friends == 0) {
1649
0
        mem_delete(dht->mem, dht->friends_list);
1650
0
        dht->friends_list = nullptr;
1651
0
        return 0;
1652
0
    }
1653
1654
0
    DHT_Friend *const temp = (DHT_Friend *)mem_vrealloc(dht->mem, dht->friends_list, dht->num_friends, sizeof(DHT_Friend));
1655
1656
0
    if (temp == nullptr) {
1657
0
        return -1;
1658
0
    }
1659
1660
0
    dht->friends_list = temp;
1661
0
    return 0;
1662
0
}
1663
1664
/* TODO(irungentoo): Optimize this. */
1665
int dht_getfriendip(const DHT *dht, const uint8_t *public_key, IP_Port *ip_port)
1666
0
{
1667
0
    ip_reset(&ip_port->ip);
1668
0
    ip_port->port = 0;
1669
1670
0
    const uint32_t friend_index = index_of_friend_pk(dht->friends_list, dht->num_friends, public_key);
1671
1672
0
    if (friend_index == UINT32_MAX) {
1673
0
        return -1;
1674
0
    }
1675
1676
0
    const DHT_Friend *const frnd = &dht->friends_list[friend_index];
1677
0
    const uint32_t client_index = index_of_client_pk(frnd->client_list, MAX_FRIEND_CLIENTS, public_key);
1678
1679
0
    if (client_index == UINT32_MAX) {
1680
0
        return 0;
1681
0
    }
1682
1683
0
    const Client_data *const client = &frnd->client_list[client_index];
1684
0
    const IPPTsPng *const assocs[] = { &client->assoc6, &client->assoc4, nullptr };
1685
1686
0
    for (const IPPTsPng * const *it = assocs; *it != nullptr; ++it) {
1687
0
        const IPPTsPng *const assoc = *it;
1688
1689
0
        if (!assoc_timeout(dht->cur_time, assoc)) {
1690
0
            *ip_port = assoc->ip_port;
1691
0
            return 1;
1692
0
        }
1693
0
    }
1694
1695
0
    return -1;
1696
0
}
1697
1698
/** returns number of nodes not in kill-timeout */
1699
static uint8_t do_ping_and_sendnode_requests(DHT *_Nonnull dht, uint64_t *_Nonnull lastgetnode, const uint8_t *_Nonnull public_key, Client_data *_Nonnull list, uint32_t list_count,
1700
        uint32_t *_Nonnull bootstrap_times, bool sortable)
1701
0
{
1702
0
    uint8_t not_kill = 0;
1703
0
    const uint64_t temp_time = mono_time_get(dht->mono_time);
1704
1705
0
    uint32_t num_nodes = 0;
1706
0
    Client_data **client_list = (Client_data **)mem_valloc(dht->mem, list_count * 2, sizeof(Client_data *));
1707
0
    IPPTsPng **assoc_list = (IPPTsPng **)mem_valloc(dht->mem, list_count * 2, sizeof(IPPTsPng *));
1708
0
    unsigned int sort = 0;
1709
0
    bool sort_ok = false;
1710
1711
0
    if (client_list == nullptr || assoc_list == nullptr) {
1712
0
        mem_delete(dht->mem, assoc_list);
1713
0
        mem_delete(dht->mem, client_list);
1714
0
        return 0;
1715
0
    }
1716
1717
0
    for (uint32_t i = 0; i < list_count; ++i) {
1718
        /* If node is not dead. */
1719
0
        Client_data *client = &list[i];
1720
1721
0
        IPPTsPng *const assocs[] = { &client->assoc6, &client->assoc4 };
1722
1723
0
        for (uint32_t j = 0; j < sizeof(assocs) / sizeof(assocs[0]); ++j) {
1724
0
            IPPTsPng *const assoc = assocs[j];
1725
1726
0
            if (!mono_time_is_timeout(dht->mono_time, assoc->timestamp, KILL_NODE_TIMEOUT)) {
1727
0
                sort = 0;
1728
0
                ++not_kill;
1729
1730
0
                if (mono_time_is_timeout(dht->mono_time, assoc->last_pinged, PING_INTERVAL)) {
1731
0
                    const IP_Port *target = &assoc->ip_port;
1732
0
                    const uint8_t *target_key = client->public_key;
1733
0
                    dht_send_nodes_request(dht, target, target_key, public_key);
1734
0
                    assoc->last_pinged = temp_time;
1735
0
                }
1736
1737
                /* If node is good. */
1738
0
                if (!assoc_timeout(dht->cur_time, assoc)) {
1739
0
                    client_list[num_nodes] = client;
1740
0
                    assoc_list[num_nodes] = assoc;
1741
0
                    ++num_nodes;
1742
0
                }
1743
0
            } else {
1744
0
                ++sort;
1745
1746
                /* Timed out should be at beginning, if they are not, sort the list. */
1747
0
                if (sort > 1 && sort < (((j + 1) * 2) - 1)) {
1748
0
                    sort_ok = true;
1749
0
                }
1750
0
            }
1751
0
        }
1752
0
    }
1753
1754
0
    if (sortable && sort_ok) {
1755
0
        sort_client_list(dht->mem, list, dht->cur_time, list_count, public_key);
1756
0
    }
1757
1758
0
    if (num_nodes > 0 && (mono_time_is_timeout(dht->mono_time, *lastgetnode, NODES_REQUEST_INTERVAL)
1759
0
                          || *bootstrap_times < MAX_BOOTSTRAP_TIMES)) {
1760
0
        uint32_t rand_node = random_range_u32(dht->rng, num_nodes);
1761
1762
0
        if ((num_nodes - 1) != rand_node) {
1763
0
            rand_node += random_range_u32(dht->rng, num_nodes - (rand_node + 1));
1764
0
        }
1765
1766
0
        const IP_Port *target = &assoc_list[rand_node]->ip_port;
1767
0
        const uint8_t *target_key = client_list[rand_node]->public_key;
1768
0
        dht_send_nodes_request(dht, target, target_key, public_key);
1769
1770
0
        *lastgetnode = temp_time;
1771
0
        ++*bootstrap_times;
1772
0
    }
1773
1774
0
    mem_delete(dht->mem, assoc_list);
1775
0
    mem_delete(dht->mem, client_list);
1776
0
    return not_kill;
1777
0
}
1778
1779
/** @brief Ping each client in the "friends" list every PING_INTERVAL seconds.
1780
 *
1781
 * Send a nodes request  every NODES_REQUEST_INTERVAL seconds to a random good
1782
 * node for each "friend" in our "friends" list.
1783
 */
1784
static void do_dht_friends(DHT *_Nonnull dht)
1785
0
{
1786
0
    for (size_t i = 0; i < dht->num_friends; ++i) {
1787
0
        DHT_Friend *const dht_friend = &dht->friends_list[i];
1788
1789
0
        for (size_t j = 0; j < dht_friend->num_to_bootstrap; ++j) {
1790
0
            dht_send_nodes_request(dht, &dht_friend->to_bootstrap[j].ip_port, dht_friend->to_bootstrap[j].public_key, dht_friend->public_key);
1791
0
        }
1792
1793
0
        dht_friend->num_to_bootstrap = 0;
1794
1795
0
        do_ping_and_sendnode_requests(dht, &dht_friend->last_nodes_request, dht_friend->public_key, dht_friend->client_list,
1796
0
                                      MAX_FRIEND_CLIENTS, &dht_friend->bootstrap_times, true);
1797
0
    }
1798
0
}
1799
1800
/** @brief Ping each client in the close nodes list every PING_INTERVAL seconds.
1801
 *
1802
 * Send a nodes request every NODES_REQUEST_INTERVAL seconds to a random good node in the list.
1803
 */
1804
static void do_close(DHT *_Nonnull dht)
1805
0
{
1806
0
    for (size_t i = 0; i < dht->num_to_bootstrap; ++i) {
1807
0
        dht_send_nodes_request(dht, &dht->to_bootstrap[i].ip_port, dht->to_bootstrap[i].public_key, dht->self_public_key);
1808
0
    }
1809
1810
0
    dht->num_to_bootstrap = 0;
1811
1812
0
    const uint8_t not_killed = do_ping_and_sendnode_requests(
1813
0
                                   dht, &dht->close_last_nodes_request, dht->self_public_key, dht->close_clientlist, LCLIENT_LIST, &dht->close_bootstrap_times,
1814
0
                                   false);
1815
1816
0
    if (not_killed != 0) {
1817
0
        return;
1818
0
    }
1819
1820
    /* all existing nodes are at least KILL_NODE_TIMEOUT,
1821
     * which means we are mute, as we only send packets to
1822
     * nodes NOT in KILL_NODE_TIMEOUT
1823
     *
1824
     * so: reset all nodes to be BAD_NODE_TIMEOUT, but not
1825
     * KILL_NODE_TIMEOUT, so we at least keep trying pings */
1826
0
    const uint64_t badonly = mono_time_get(dht->mono_time) - BAD_NODE_TIMEOUT;
1827
1828
0
    for (size_t i = 0; i < LCLIENT_LIST; ++i) {
1829
0
        Client_data *const client = &dht->close_clientlist[i];
1830
1831
0
        if (client->assoc4.timestamp != 0) {
1832
0
            client->assoc4.timestamp = badonly;
1833
0
        }
1834
0
        if (client->assoc6.timestamp != 0) {
1835
0
            client->assoc6.timestamp = badonly;
1836
0
        }
1837
0
    }
1838
0
}
1839
1840
bool dht_bootstrap(DHT *dht, const IP_Port *ip_port, const uint8_t *public_key)
1841
11
{
1842
11
    if (pk_equal(public_key, dht->self_public_key)) {
1843
        // Bootstrapping off ourselves is ok (onion paths are still set up).
1844
0
        return true;
1845
0
    }
1846
1847
11
    return dht_send_nodes_request(dht, ip_port, public_key, dht->self_public_key);
1848
11
}
1849
1850
bool dht_bootstrap_from_address(DHT *dht, const char *address, bool ipv6enabled, bool dns_enabled,
1851
                                uint16_t port, const uint8_t *public_key)
1852
0
{
1853
0
    IP_Port ip_port_v64;
1854
0
    IP *ip_extra = nullptr;
1855
0
    IP_Port ip_port_v4;
1856
0
    ip_init(&ip_port_v64.ip, ipv6enabled);
1857
1858
0
    if (ipv6enabled) {
1859
        /* setup for getting BOTH: an IPv6 AND an IPv4 address */
1860
0
        ip_port_v64.ip.family = net_family_unspec();
1861
0
        ip_reset(&ip_port_v4.ip);
1862
0
        ip_extra = &ip_port_v4.ip;
1863
0
    }
1864
1865
0
    if (addr_resolve_or_parse_ip(dht->ns, dht->mem, address, &ip_port_v64.ip, ip_extra, dns_enabled)) {
1866
0
        ip_port_v64.port = port;
1867
0
        dht_bootstrap(dht, &ip_port_v64, public_key);
1868
1869
0
        if ((ip_extra != nullptr) && ip_isset(ip_extra)) {
1870
0
            ip_port_v4.port = port;
1871
0
            dht_bootstrap(dht, &ip_port_v4, public_key);
1872
0
        }
1873
1874
0
        return true;
1875
0
    }
1876
1877
0
    return false;
1878
0
}
1879
1880
int route_packet(const DHT *dht, const uint8_t *public_key, const uint8_t *packet, uint16_t length)
1881
0
{
1882
0
    for (uint32_t i = 0; i < LCLIENT_LIST; ++i) {
1883
0
        if (pk_equal(public_key, dht->close_clientlist[i].public_key)) {
1884
0
            const Client_data *const client = &dht->close_clientlist[i];
1885
0
            const IPPTsPng *const assocs[] = { &client->assoc6, &client->assoc4, nullptr };
1886
1887
0
            for (const IPPTsPng * const *it = assocs; *it != nullptr; ++it) {
1888
0
                const IPPTsPng *const assoc = *it;
1889
1890
0
                if (ip_isset(&assoc->ip_port.ip)) {
1891
0
                    return sendpacket(dht->net, &assoc->ip_port, packet, length);
1892
0
                }
1893
0
            }
1894
1895
0
            break;
1896
0
        }
1897
0
    }
1898
1899
0
    return -1;
1900
0
}
1901
1902
/** @brief Puts all the different ips returned by the nodes for a friend_num into array ip_portlist.
1903
 *
1904
 * ip_portlist must be at least MAX_FRIEND_CLIENTS big.
1905
 *
1906
 * @return the number of ips returned.
1907
 * @retval 0 if we are connected to friend or if no ips were found.
1908
 * @retval -1 if no such friend.
1909
 */
1910
static int friend_iplist(const DHT *_Nonnull dht, IP_Port *_Nonnull ip_portlist, uint16_t friend_num)
1911
0
{
1912
0
    if (friend_num >= dht->num_friends) {
1913
0
        return -1;
1914
0
    }
1915
1916
0
    const DHT_Friend *const dht_friend = &dht->friends_list[friend_num];
1917
0
    IP_Port ipv4s[MAX_FRIEND_CLIENTS];
1918
0
    int num_ipv4s = 0;
1919
0
    IP_Port ipv6s[MAX_FRIEND_CLIENTS];
1920
0
    int num_ipv6s = 0;
1921
1922
0
    for (size_t i = 0; i < MAX_FRIEND_CLIENTS; ++i) {
1923
0
        const Client_data *const client = &dht_friend->client_list[i];
1924
1925
        /* If ip is not zero and node is good. */
1926
0
        if (ip_isset(&client->assoc4.ret_ip_port.ip)
1927
0
                && !mono_time_is_timeout(dht->mono_time, client->assoc4.ret_timestamp, BAD_NODE_TIMEOUT)) {
1928
0
            ipv4s[num_ipv4s] = client->assoc4.ret_ip_port;
1929
0
            ++num_ipv4s;
1930
0
        }
1931
1932
0
        if (ip_isset(&client->assoc6.ret_ip_port.ip)
1933
0
                && !mono_time_is_timeout(dht->mono_time, client->assoc6.ret_timestamp, BAD_NODE_TIMEOUT)) {
1934
0
            ipv6s[num_ipv6s] = client->assoc6.ret_ip_port;
1935
0
            ++num_ipv6s;
1936
0
        }
1937
1938
0
        if (pk_equal(client->public_key, dht_friend->public_key)) {
1939
0
            if (!assoc_timeout(dht->cur_time, &client->assoc6)
1940
0
                    || !assoc_timeout(dht->cur_time, &client->assoc4)) {
1941
0
                return 0; /* direct connectivity */
1942
0
            }
1943
0
        }
1944
0
    }
1945
1946
#ifdef FRIEND_IPLIST_PAD
1947
    memcpy(ip_portlist, ipv6s, num_ipv6s * sizeof(IP_Port));
1948
1949
    if (num_ipv6s == MAX_FRIEND_CLIENTS) {
1950
        return MAX_FRIEND_CLIENTS;
1951
    }
1952
1953
    int num_ipv4s_used = MAX_FRIEND_CLIENTS - num_ipv6s;
1954
1955
    if (num_ipv4s_used > num_ipv4s) {
1956
        num_ipv4s_used = num_ipv4s;
1957
    }
1958
1959
    memcpy(&ip_portlist[num_ipv6s], ipv4s, num_ipv4s_used * sizeof(IP_Port));
1960
    return num_ipv6s + num_ipv4s_used;
1961
1962
#else /* !FRIEND_IPLIST_PAD */
1963
1964
    /* there must be some secret reason why we can't pad the longer list
1965
     * with the shorter one...
1966
     */
1967
0
    if (num_ipv6s >= num_ipv4s) {
1968
0
        memcpy(ip_portlist, ipv6s, num_ipv6s * sizeof(IP_Port));
1969
0
        return num_ipv6s;
1970
0
    }
1971
1972
0
    memcpy(ip_portlist, ipv4s, num_ipv4s * sizeof(IP_Port));
1973
0
    return num_ipv4s;
1974
1975
0
#endif /* !FRIEND_IPLIST_PAD */
1976
0
}
1977
1978
/**
1979
 * Callback invoked for each IP/port of each client of a friend.
1980
 *
1981
 * For each client, the callback is invoked twice: once for IPv4 and once for
1982
 * IPv6. If the callback returns `false` after the IPv4 invocation, it will not
1983
 * be invoked for IPv6.
1984
 *
1985
 * @param dht The main DHT instance.
1986
 * @param ip_port The currently processed IP/port.
1987
 * @param n A pointer to the number that will be returned from `foreach_ip_port`.
1988
 * @param userdata The `userdata` pointer passed to `foreach_ip_port`.
1989
 */
1990
typedef bool foreach_ip_port_cb(const DHT *_Nonnull dht, const IP_Port *_Nonnull ip_port, uint32_t *_Nonnull n, void *_Nonnull userdata);
1991
1992
/**
1993
 * Runs a callback on every active connection for a given DHT friend.
1994
 *
1995
 * This iterates over the client list of a DHT friend and invokes a callback for
1996
 * every non-zero IP/port (IPv4 and IPv6) that's not timed out.
1997
 *
1998
 * @param dht The main DHT instance, passed to the callback.
1999
 * @param dht_friend The friend over whose connections we should iterate.
2000
 * @param callback The callback to invoke for each IP/port.
2001
 * @param userdata Extra pointer passed to the callback.
2002
 */
2003
static uint32_t foreach_ip_port(const DHT *_Nonnull dht, const DHT_Friend *_Nonnull dht_friend, foreach_ip_port_cb *_Nonnull callback, void *_Nonnull userdata)
2004
0
{
2005
0
    uint32_t n = 0;
2006
2007
    /* extra legwork, because having the outside allocating the space for us
2008
     * is *usually* good(tm) (bites us in the behind in this case though) */
2009
0
    for (uint32_t i = 0; i < MAX_FRIEND_CLIENTS; ++i) {
2010
0
        const Client_data *const client = &dht_friend->client_list[i];
2011
0
        const IPPTsPng *const assocs[] = { &client->assoc4, &client->assoc6, nullptr };
2012
2013
0
        for (const IPPTsPng * const *it = assocs; *it != nullptr; ++it) {
2014
0
            const IPPTsPng *const assoc = *it;
2015
2016
            /* If ip is not zero and node is good. */
2017
0
            if (!ip_isset(&assoc->ret_ip_port.ip)
2018
0
                    || mono_time_is_timeout(dht->mono_time, assoc->ret_timestamp, BAD_NODE_TIMEOUT)) {
2019
0
                continue;
2020
0
            }
2021
2022
0
            if (!callback(dht, &assoc->ip_port, &n, userdata)) {
2023
                /* If the callback is happy with just one of the assocs, we
2024
                 * don't give it the second one. */
2025
0
                break;
2026
0
            }
2027
0
        }
2028
0
    }
2029
2030
0
    return n;
2031
0
}
2032
2033
static bool send_packet_to_friend(const DHT *_Nonnull dht, const IP_Port *_Nonnull ip_port, uint32_t *_Nonnull n, void *_Nonnull userdata)
2034
0
{
2035
0
    const Net_Packet *packet = (const Net_Packet *)userdata;
2036
0
    const int retval = net_send_packet(dht->net, ip_port, *packet);
2037
2038
0
    if ((uint32_t)retval == packet->length) {
2039
0
        ++*n;
2040
        /* Send one packet per friend: stop the foreach on the first success. */
2041
0
        return false;
2042
0
    }
2043
2044
0
    return true;
2045
0
}
2046
2047
/**
2048
 * Send the following packet to everyone who tells us they are connected to friend_id.
2049
 *
2050
 * @return ip for friend.
2051
 * @return number of nodes the packet was sent to. (Only works if more than (MAX_FRIEND_CLIENTS / 4).
2052
 */
2053
uint32_t route_to_friend(const DHT *dht, const uint8_t *friend_id, const Net_Packet *packet)
2054
0
{
2055
0
    const uint32_t num = index_of_friend_pk(dht->friends_list, dht->num_friends, friend_id);
2056
2057
0
    if (num == UINT32_MAX) {
2058
0
        return 0;
2059
0
    }
2060
2061
0
    IP_Port ip_list[MAX_FRIEND_CLIENTS];
2062
0
    const int ip_num = friend_iplist(dht, ip_list, num);
2063
2064
0
    if (ip_num < MAX_FRIEND_CLIENTS / 4) {
2065
0
        return 0; /* Reason for that? */
2066
0
    }
2067
2068
0
    const DHT_Friend *const dht_friend = &dht->friends_list[num];
2069
0
    Net_Packet packet_userdata = *packet;  // Copy because it needs to be non-const.
2070
2071
0
    return foreach_ip_port(dht, dht_friend, send_packet_to_friend, &packet_userdata);
2072
0
}
2073
2074
static bool get_ip_port(const DHT *_Nonnull dht, const IP_Port *_Nonnull ip_port, uint32_t *_Nonnull n, void *_Nonnull userdata)
2075
0
{
2076
0
    IP_Port *ip_list = (IP_Port *)userdata;
2077
0
    ip_list[*n] = *ip_port;
2078
0
    ++*n;
2079
0
    return true;
2080
0
}
2081
2082
/** @brief Send the following packet to one random person who tells us they are connected to friend_id.
2083
 *
2084
 * @return number of nodes the packet was sent to.
2085
 */
2086
static uint32_t routeone_to_friend(const DHT *_Nonnull dht, const uint8_t *_Nonnull friend_id, const Net_Packet *_Nonnull packet)
2087
0
{
2088
0
    const uint32_t num = index_of_friend_pk(dht->friends_list, dht->num_friends, friend_id);
2089
2090
0
    if (num == UINT32_MAX) {
2091
0
        return 0;
2092
0
    }
2093
2094
0
    const DHT_Friend *const dht_friend = &dht->friends_list[num];
2095
2096
0
    IP_Port ip_list[MAX_FRIEND_CLIENTS * 2];
2097
2098
0
    const int n = foreach_ip_port(dht, dht_friend, get_ip_port, ip_list);
2099
2100
0
    if (n < 1) {
2101
0
        return 0;
2102
0
    }
2103
2104
0
    const uint32_t rand_idx = random_range_u32(dht->rng, n);
2105
0
    const int retval = net_send_packet(dht->net, &ip_list[rand_idx], *packet);
2106
2107
0
    if ((unsigned int)retval == packet->length) {
2108
0
        return 1;
2109
0
    }
2110
2111
0
    return 0;
2112
0
}
2113
2114
/*----------------------------------------------------------------------------------*/
2115
/*---------------------BEGINNING OF NAT PUNCHING FUNCTIONS--------------------------*/
2116
2117
static int send_nat_ping(const DHT *_Nonnull dht, const uint8_t *_Nonnull public_key, uint64_t ping_id, uint8_t type)
2118
0
{
2119
0
    uint8_t data[sizeof(uint64_t) + 1];
2120
0
    uint8_t packet_data[MAX_CRYPTO_REQUEST_SIZE];
2121
2122
0
    data[0] = type;
2123
0
    memcpy(data + 1, &ping_id, sizeof(uint64_t));
2124
    /* 254 is NAT ping request packet id */
2125
0
    const int len = create_request(
2126
0
                        dht->mem, dht->rng, dht->self_public_key, dht->self_secret_key, packet_data, public_key,
2127
0
                        data, sizeof(uint64_t) + 1, CRYPTO_PACKET_NAT_PING);
2128
2129
0
    if (len == -1) {
2130
0
        return -1;
2131
0
    }
2132
2133
0
    assert(len <= UINT16_MAX);
2134
0
    uint32_t num = 0;
2135
0
    const Net_Packet packet = {packet_data, (uint16_t)len};
2136
2137
0
    if (type == 0) { /* If packet is request use many people to route it. */
2138
0
        num = route_to_friend(dht, public_key, &packet);
2139
0
    } else if (type == 1) { /* If packet is response use only one person to route it */
2140
0
        num = routeone_to_friend(dht, public_key, &packet);
2141
0
    }
2142
2143
0
    if (num == 0) {
2144
0
        return -1;
2145
0
    }
2146
2147
0
    return num;
2148
0
}
2149
2150
/** Handle a received ping request for. */
2151
static int handle_nat_ping(void *_Nonnull object, const IP_Port *_Nonnull source, const uint8_t *_Nonnull source_pubkey, const uint8_t *_Nonnull packet, uint16_t length,
2152
                           void *_Nonnull userdata)
2153
0
{
2154
0
    DHT *const dht = (DHT *)object;
2155
2156
0
    if (length != sizeof(uint64_t) + 1) {
2157
0
        return 1;
2158
0
    }
2159
2160
0
    uint64_t ping_id;
2161
0
    memcpy(&ping_id, packet + 1, sizeof(uint64_t));
2162
2163
0
    const uint32_t friendnumber = index_of_friend_pk(dht->friends_list, dht->num_friends, source_pubkey);
2164
2165
0
    if (friendnumber == UINT32_MAX) {
2166
0
        return 1;
2167
0
    }
2168
2169
0
    DHT_Friend *const dht_friend = &dht->friends_list[friendnumber];
2170
2171
0
    if (packet[0] == NAT_PING_REQUEST) {
2172
        /* 1 is reply */
2173
0
        send_nat_ping(dht, source_pubkey, ping_id, NAT_PING_RESPONSE);
2174
0
        dht_friend->nat.recv_nat_ping_timestamp = mono_time_get(dht->mono_time);
2175
0
        return 0;
2176
0
    }
2177
2178
0
    if (packet[0] == NAT_PING_RESPONSE) {
2179
0
        if (dht_friend->nat.nat_ping_id == ping_id) {
2180
0
            dht_friend->nat.nat_ping_id = random_u64(dht->rng);
2181
0
            dht_friend->nat.hole_punching = true;
2182
0
            return 0;
2183
0
        }
2184
0
    }
2185
2186
0
    return 1;
2187
0
}
2188
2189
/** @brief Get the most common ip in the ip_portlist.
2190
 * Only return ip if it appears in list min_num or more.
2191
 * len must not be bigger than MAX_FRIEND_CLIENTS.
2192
 *
2193
 * @return ip of 0 if failure.
2194
 */
2195
static IP nat_commonip(const IP_Port *_Nonnull ip_portlist, uint16_t len, uint16_t min_num)
2196
0
{
2197
0
    IP zero;
2198
0
    ip_reset(&zero);
2199
2200
0
    if (len > MAX_FRIEND_CLIENTS) {
2201
0
        return zero;
2202
0
    }
2203
2204
0
    uint16_t numbers[MAX_FRIEND_CLIENTS] = {0};
2205
2206
0
    for (uint32_t i = 0; i < len; ++i) {
2207
0
        for (uint32_t j = 0; j < len; ++j) {
2208
0
            if (ip_equal(&ip_portlist[i].ip, &ip_portlist[j].ip)) {
2209
0
                ++numbers[i];
2210
0
            }
2211
0
        }
2212
2213
0
        if (numbers[i] >= min_num) {
2214
0
            return ip_portlist[i].ip;
2215
0
        }
2216
0
    }
2217
2218
0
    return zero;
2219
0
}
2220
2221
/** @brief Return all the ports for one ip in a list.
2222
 * portlist must be at least len long,
2223
 * where len is the length of ip_portlist.
2224
 *
2225
 * @return number of ports and puts the list of ports in portlist.
2226
 */
2227
static uint16_t nat_getports(uint16_t *_Nonnull portlist, const IP_Port *_Nonnull ip_portlist, uint16_t len, const IP *_Nonnull ip)
2228
0
{
2229
0
    uint16_t num = 0;
2230
2231
0
    for (uint32_t i = 0; i < len; ++i) {
2232
0
        if (ip_equal(&ip_portlist[i].ip, ip)) {
2233
0
            portlist[num] = net_ntohs(ip_portlist[i].port);
2234
0
            ++num;
2235
0
        }
2236
0
    }
2237
2238
0
    return num;
2239
0
}
2240
2241
static void punch_holes(DHT *_Nonnull dht, const IP *_Nonnull ip, const uint16_t *_Nonnull port_list, uint16_t numports, uint16_t friend_num)
2242
0
{
2243
0
    if (!dht->hole_punching_enabled) {
2244
0
        return;
2245
0
    }
2246
2247
0
    if (numports > MAX_FRIEND_CLIENTS || numports == 0) {
2248
0
        return;
2249
0
    }
2250
2251
0
    const uint16_t first_port = port_list[0];
2252
0
    uint16_t port_candidate;
2253
2254
0
    for (port_candidate = 0; port_candidate < numports; ++port_candidate) {
2255
0
        if (first_port != port_list[port_candidate]) {
2256
0
            break;
2257
0
        }
2258
0
    }
2259
2260
0
    if (port_candidate == numports) { /* If all ports are the same, only try that one port. */
2261
0
        IP_Port pinging;
2262
0
        ip_copy(&pinging.ip, ip);
2263
0
        pinging.port = net_htons(first_port);
2264
0
        ping_send_request(dht->ping, &pinging, dht->friends_list[friend_num].public_key);
2265
0
    } else {
2266
0
        uint16_t i;
2267
0
        for (i = 0; i < MAX_PUNCHING_PORTS; ++i) {
2268
            /* TODO(irungentoo): Improve port guessing algorithm. */
2269
0
            const uint32_t it = i + dht->friends_list[friend_num].nat.punching_index;
2270
0
            const int8_t sign = (it % 2 != 0) ? -1 : 1;
2271
0
            const uint32_t delta = sign * (it / (2 * numports));
2272
0
            const uint32_t index = (it / 2) % numports;
2273
0
            const uint16_t port = port_list[index] + delta;
2274
0
            IP_Port pinging;
2275
0
            ip_copy(&pinging.ip, ip);
2276
0
            pinging.port = net_htons(port);
2277
0
            ping_send_request(dht->ping, &pinging, dht->friends_list[friend_num].public_key);
2278
0
        }
2279
2280
0
        dht->friends_list[friend_num].nat.punching_index += i;
2281
0
    }
2282
2283
0
    if (dht->friends_list[friend_num].nat.tries > MAX_NORMAL_PUNCHING_TRIES) {
2284
0
        IP_Port pinging;
2285
0
        ip_copy(&pinging.ip, ip);
2286
2287
0
        uint16_t i;
2288
0
        for (i = 0; i < MAX_PUNCHING_PORTS; ++i) {
2289
0
            const uint32_t it = i + dht->friends_list[friend_num].nat.punching_index2;
2290
0
            const uint16_t port = 1024;
2291
0
            pinging.port = net_htons(port + it);
2292
0
            ping_send_request(dht->ping, &pinging, dht->friends_list[friend_num].public_key);
2293
0
        }
2294
2295
0
        dht->friends_list[friend_num].nat.punching_index2 += i - (MAX_PUNCHING_PORTS / 2);
2296
0
    }
2297
2298
0
    ++dht->friends_list[friend_num].nat.tries;
2299
0
}
2300
2301
static void do_nat(DHT *_Nonnull dht)
2302
0
{
2303
0
    const uint64_t temp_time = mono_time_get(dht->mono_time);
2304
2305
0
    for (uint32_t i = 0; i < dht->num_friends; ++i) {
2306
0
        IP_Port ip_list[MAX_FRIEND_CLIENTS];
2307
0
        const int num = friend_iplist(dht, ip_list, i);
2308
2309
        /* If already connected or friend is not online don't try to hole punch. */
2310
0
        if (num < MAX_FRIEND_CLIENTS / 2) {
2311
0
            continue;
2312
0
        }
2313
2314
0
        if (dht->friends_list[i].nat.nat_ping_timestamp + PUNCH_INTERVAL < temp_time) {
2315
0
            send_nat_ping(dht, dht->friends_list[i].public_key, dht->friends_list[i].nat.nat_ping_id, NAT_PING_REQUEST);
2316
0
            dht->friends_list[i].nat.nat_ping_timestamp = temp_time;
2317
0
        }
2318
2319
0
        if (dht->friends_list[i].nat.hole_punching &&
2320
0
                dht->friends_list[i].nat.punching_timestamp + PUNCH_INTERVAL < temp_time &&
2321
0
                dht->friends_list[i].nat.recv_nat_ping_timestamp + PUNCH_INTERVAL * 2 >= temp_time) {
2322
2323
0
            const IP ip = nat_commonip(ip_list, num, MAX_FRIEND_CLIENTS / 2);
2324
2325
0
            if (!ip_isset(&ip)) {
2326
0
                continue;
2327
0
            }
2328
2329
0
            if (dht->friends_list[i].nat.punching_timestamp + PUNCH_RESET_TIME < temp_time) {
2330
0
                dht->friends_list[i].nat.tries = 0;
2331
0
                dht->friends_list[i].nat.punching_index = 0;
2332
0
                dht->friends_list[i].nat.punching_index2 = 0;
2333
0
            }
2334
2335
0
            uint16_t port_list[MAX_FRIEND_CLIENTS];
2336
0
            const uint16_t numports = nat_getports(port_list, ip_list, num, &ip);
2337
0
            punch_holes(dht, &ip, port_list, numports, i);
2338
2339
0
            dht->friends_list[i].nat.punching_timestamp = temp_time;
2340
0
            dht->friends_list[i].nat.hole_punching = false;
2341
0
        }
2342
0
    }
2343
0
}
2344
2345
/*----------------------------------------------------------------------------------*/
2346
/*-----------------------END OF NAT PUNCHING FUNCTIONS------------------------------*/
2347
2348
/** @brief Put up to max_num nodes in nodes from the closelist.
2349
 *
2350
 * @return the number of nodes.
2351
 */
2352
static uint16_t list_nodes(const Random *_Nonnull rng, const Client_data *_Nonnull list, size_t length, uint64_t cur_time, Node_format *_Nonnull nodes, uint16_t max_num)
2353
28
{
2354
28
    if (max_num == 0) {
2355
0
        return 0;
2356
0
    }
2357
2358
28
    uint16_t count = 0;
2359
2360
252
    for (size_t i = length; i != 0; --i) {
2361
224
        const IPPTsPng *assoc = nullptr;
2362
2363
224
        if (!assoc_timeout(cur_time, &list[i - 1].assoc4)) {
2364
0
            assoc = &list[i - 1].assoc4;
2365
0
        }
2366
2367
224
        if (!assoc_timeout(cur_time, &list[i - 1].assoc6)) {
2368
0
            if (assoc == nullptr || (random_u08(rng) % 2) != 0) {
2369
0
                assoc = &list[i - 1].assoc6;
2370
0
            }
2371
0
        }
2372
2373
224
        if (assoc != nullptr) {
2374
0
            memcpy(nodes[count].public_key, list[i - 1].public_key, CRYPTO_PUBLIC_KEY_SIZE);
2375
0
            nodes[count].ip_port = assoc->ip_port;
2376
0
            ++count;
2377
2378
0
            if (count >= max_num) {
2379
0
                return count;
2380
0
            }
2381
0
        }
2382
224
    }
2383
2384
28
    return count;
2385
28
}
2386
2387
/** @brief Put up to max_num nodes in nodes from the random friends.
2388
 *
2389
 * Important: this function relies on the first two DHT friends *not* being real
2390
 * friends to avoid leaking information about real friends into the onion paths.
2391
 *
2392
 * @return the number of nodes.
2393
 */
2394
uint16_t randfriends_nodes(const DHT *dht, Node_format *nodes, uint16_t max_num)
2395
14
{
2396
14
    if (max_num == 0) {
2397
0
        return 0;
2398
0
    }
2399
2400
14
    uint16_t count = 0;
2401
14
    const uint32_t r = random_u32(dht->rng);
2402
2403
14
    assert(DHT_FAKE_FRIEND_NUMBER <= dht->num_friends);
2404
2405
    // Only gather nodes from the initial 2 fake friends.
2406
42
    for (uint32_t i = 0; i < DHT_FAKE_FRIEND_NUMBER; ++i) {
2407
28
        count += list_nodes(dht->rng, dht->friends_list[(i + r) % DHT_FAKE_FRIEND_NUMBER].client_list,
2408
28
                            MAX_FRIEND_CLIENTS, dht->cur_time,
2409
28
                            nodes + count, max_num - count);
2410
2411
28
        if (count >= max_num) {
2412
0
            break;
2413
0
        }
2414
28
    }
2415
2416
14
    return count;
2417
14
}
2418
2419
/** @brief Put up to max_num nodes in nodes from the closelist.
2420
 *
2421
 * @return the number of nodes.
2422
 */
2423
uint16_t closelist_nodes(const DHT *dht, Node_format *nodes, uint16_t max_num)
2424
0
{
2425
0
    return list_nodes(dht->rng, dht->close_clientlist, LCLIENT_LIST, dht->cur_time, nodes, max_num);
2426
0
}
2427
2428
/*----------------------------------------------------------------------------------*/
2429
2430
void cryptopacket_registerhandler(DHT *dht, uint8_t byte, cryptopacket_handler_cb *cb, void *object)
2431
6.32k
{
2432
6.32k
    dht->cryptopackethandlers[byte].function = cb;
2433
6.32k
    dht->cryptopackethandlers[byte].object = object;
2434
6.32k
}
2435
2436
static int cryptopacket_handle(void *_Nonnull object, const IP_Port *_Nonnull source, const uint8_t *_Nonnull packet, uint16_t length, void *_Nonnull userdata)
2437
0
{
2438
0
    DHT *const dht = (DHT *)object;
2439
2440
0
    assert(packet[0] == NET_PACKET_CRYPTO);
2441
2442
0
    if (length <= CRYPTO_PUBLIC_KEY_SIZE * 2 + CRYPTO_NONCE_SIZE + 1 + CRYPTO_MAC_SIZE ||
2443
0
            length > MAX_CRYPTO_REQUEST_SIZE + CRYPTO_MAC_SIZE) {
2444
0
        return 1;
2445
0
    }
2446
2447
    // Check if request is for us.
2448
0
    if (pk_equal(packet + 1, dht->self_public_key)) {
2449
0
        uint8_t public_key[CRYPTO_PUBLIC_KEY_SIZE];
2450
0
        uint8_t data[MAX_CRYPTO_REQUEST_SIZE];
2451
0
        uint8_t number;
2452
0
        const int len = handle_request(dht->mem, dht->self_public_key, dht->self_secret_key, public_key,
2453
0
                                       data, &number, packet, length);
2454
2455
0
        if (len == -1 || len == 0) {
2456
0
            return 1;
2457
0
        }
2458
2459
0
        if (dht->cryptopackethandlers[number].function == nullptr) {
2460
0
            return 1;
2461
0
        }
2462
2463
0
        return dht->cryptopackethandlers[number].function(
2464
0
                   dht->cryptopackethandlers[number].object, source, public_key,
2465
0
                   data, len, userdata);
2466
0
    }
2467
2468
    /* If request is not for us, try routing it. */
2469
0
    const int retval = route_packet(dht, packet + 1, packet, length);
2470
2471
0
    if ((unsigned int)retval == length) {
2472
0
        return 0;
2473
0
    }
2474
2475
0
    return 1;
2476
0
}
2477
2478
void dht_callback_nodes_response(DHT *dht, dht_nodes_response_cb *function)
2479
1.01k
{
2480
1.01k
    dht->nodes_response_callback = function;
2481
1.01k
}
2482
2483
static int handle_lan_discovery(void *_Nonnull object, const IP_Port *_Nonnull source, const uint8_t *_Nonnull packet, uint16_t length,
2484
                                void *_Nullable userdata)
2485
0
{
2486
0
    DHT *dht = (DHT *)object;
2487
0
    if (!dht->lan_discovery_enabled) {
2488
0
        return 1;
2489
0
    }
2490
2491
0
    if (!ip_is_lan(&source->ip)) {
2492
0
        return 1;
2493
0
    }
2494
2495
0
    if (length != CRYPTO_PUBLIC_KEY_SIZE + 1) {
2496
0
        return 1;
2497
0
    }
2498
2499
0
    dht_bootstrap(dht, source, packet + 1);
2500
0
    return 0;
2501
0
}
2502
2503
/*----------------------------------------------------------------------------------*/
2504
2505
DHT *new_dht(const Logger *log, const Memory *mem, const Random *rng, const Network *ns,
2506
             Mono_Time *mono_time, Networking_Core *net,
2507
             bool hole_punching_enabled, bool lan_discovery_enabled)
2508
1.61k
{
2509
1.61k
    if (net == nullptr) {
2510
0
        return nullptr;
2511
0
    }
2512
2513
1.61k
    DHT *const dht = (DHT *)mem_alloc(mem, sizeof(DHT));
2514
2515
1.61k
    if (dht == nullptr) {
2516
3
        LOGGER_ERROR(log, "failed to allocate DHT struct (%lu bytes)", (unsigned long)sizeof(DHT));
2517
3
        return nullptr;
2518
3
    }
2519
2520
1.61k
    dht->ns = ns;
2521
1.61k
    dht->mono_time = mono_time;
2522
1.61k
    dht->cur_time = mono_time_get(mono_time);
2523
1.61k
    dht->log = log;
2524
1.61k
    dht->net = net;
2525
1.61k
    dht->rng = rng;
2526
1.61k
    dht->mem = mem;
2527
2528
1.61k
    dht->hole_punching_enabled = hole_punching_enabled;
2529
1.61k
    dht->lan_discovery_enabled = lan_discovery_enabled;
2530
2531
1.61k
    struct Ping *temp_ping = ping_new(mem, mono_time, rng, dht, net);
2532
2533
1.61k
    if (temp_ping == nullptr) {
2534
6
        LOGGER_ERROR(log, "failed to initialise ping");
2535
6
        kill_dht(dht);
2536
6
        return nullptr;
2537
6
    }
2538
2539
1.60k
    dht->ping = temp_ping;
2540
2541
1.60k
    networking_registerhandler(dht->net, NET_PACKET_NODES_REQUEST, &handle_nodes_request, dht);
2542
1.60k
    networking_registerhandler(dht->net, NET_PACKET_NODES_RESPONSE, &handle_nodes_response, dht);
2543
1.60k
    networking_registerhandler(dht->net, NET_PACKET_CRYPTO, &cryptopacket_handle, dht);
2544
1.60k
    networking_registerhandler(dht->net, NET_PACKET_LAN_DISCOVERY, &handle_lan_discovery, dht);
2545
1.60k
    cryptopacket_registerhandler(dht, CRYPTO_PACKET_NAT_PING, &handle_nat_ping, dht);
2546
2547
1.60k
#ifdef CHECK_ANNOUNCE_NODE
2548
1.60k
    networking_registerhandler(dht->net, NET_PACKET_DATA_SEARCH_RESPONSE, &handle_data_search_response, dht);
2549
1.60k
#endif /* CHECK_ANNOUNCE_NODE */
2550
2551
1.60k
    crypto_new_keypair(rng, dht->self_public_key, dht->self_secret_key);
2552
2553
1.60k
    Shared_Key_Cache *const temp_shared_keys_recv = shared_key_cache_new(log, mono_time, mem, dht->self_secret_key, KEYS_TIMEOUT, MAX_KEYS_PER_SLOT);
2554
2555
1.60k
    if (temp_shared_keys_recv == nullptr) {
2556
4
        LOGGER_ERROR(log, "failed to initialise shared key cache");
2557
4
        kill_dht(dht);
2558
4
        return nullptr;
2559
4
    }
2560
2561
1.60k
    dht->shared_keys_recv = temp_shared_keys_recv;
2562
2563
1.60k
    Shared_Key_Cache *const temp_shared_keys_sent = shared_key_cache_new(log, mono_time, mem, dht->self_secret_key, KEYS_TIMEOUT, MAX_KEYS_PER_SLOT);
2564
2565
1.60k
    if (temp_shared_keys_sent == nullptr) {
2566
4
        LOGGER_ERROR(log, "failed to initialise shared key cache");
2567
4
        kill_dht(dht);
2568
4
        return nullptr;
2569
4
    }
2570
2571
1.59k
    dht->shared_keys_sent = temp_shared_keys_sent;
2572
2573
1.59k
    Ping_Array *const temp_ping_array = ping_array_new(mem, DHT_PING_ARRAY_SIZE, PING_TIMEOUT);
2574
2575
1.59k
    if (temp_ping_array == nullptr) {
2576
2
        LOGGER_ERROR(log, "failed to initialise ping array");
2577
2
        kill_dht(dht);
2578
2
        return nullptr;
2579
2
    }
2580
2581
1.59k
    dht->dht_ping_array = temp_ping_array;
2582
2583
4.77k
    for (uint32_t i = 0; i < DHT_FAKE_FRIEND_NUMBER; ++i) {
2584
3.18k
        uint8_t random_public_key_bytes[CRYPTO_PUBLIC_KEY_SIZE];
2585
3.18k
        uint8_t random_secret_key_bytes[CRYPTO_SECRET_KEY_SIZE];
2586
2587
3.18k
        crypto_new_keypair(rng, random_public_key_bytes, random_secret_key_bytes);
2588
2589
3.18k
        uint32_t token; // We don't intend to delete these ever, but need to pass the token
2590
3.18k
        if (dht_addfriend(dht, random_public_key_bytes, nullptr, nullptr, 0, &token) != 0) {
2591
4
            LOGGER_ERROR(log, "failed to add initial random seed DHT friends");
2592
4
            kill_dht(dht);
2593
4
            return nullptr;
2594
4
        }
2595
3.18k
    }
2596
2597
1.59k
    if (dht->num_friends != DHT_FAKE_FRIEND_NUMBER) {
2598
0
        LOGGER_ERROR(log, "the RNG provided seems to be broken: it generated the same keypair twice");
2599
0
        kill_dht(dht);
2600
0
        return nullptr;
2601
0
    }
2602
2603
1.59k
    return dht;
2604
1.59k
}
2605
2606
void do_dht(DHT *dht)
2607
2.34k
{
2608
2.34k
    const uint64_t cur_time = mono_time_get(dht->mono_time);
2609
2610
2.34k
    if (dht->cur_time == cur_time) {
2611
2.34k
        return;
2612
2.34k
    }
2613
2614
0
    dht->cur_time = cur_time;
2615
2616
    // Load friends/clients if first call to do_dht
2617
0
    if (dht->loaded_num_nodes > 0) {
2618
0
        dht_connect_after_load(dht);
2619
0
    }
2620
2621
0
    do_close(dht);
2622
0
    do_dht_friends(dht);
2623
0
    do_nat(dht);
2624
0
    ping_iterate(dht->ping);
2625
0
}
2626
2627
void kill_dht(DHT *dht)
2628
1.61k
{
2629
1.61k
    if (dht == nullptr) {
2630
0
        return;
2631
0
    }
2632
2633
1.61k
    networking_registerhandler(dht->net, NET_PACKET_NODES_REQUEST, nullptr, nullptr);
2634
1.61k
    networking_registerhandler(dht->net, NET_PACKET_NODES_RESPONSE, nullptr, nullptr);
2635
1.61k
    networking_registerhandler(dht->net, NET_PACKET_CRYPTO, nullptr, nullptr);
2636
1.61k
    networking_registerhandler(dht->net, NET_PACKET_LAN_DISCOVERY, nullptr, nullptr);
2637
1.61k
    cryptopacket_registerhandler(dht, CRYPTO_PACKET_NAT_PING, nullptr, nullptr);
2638
2639
1.61k
    shared_key_cache_free(dht->shared_keys_recv);
2640
1.61k
    shared_key_cache_free(dht->shared_keys_sent);
2641
1.61k
    ping_array_kill(dht->dht_ping_array);
2642
1.61k
    ping_kill(dht->mem, dht->ping);
2643
1.61k
    mem_delete(dht->mem, dht->friends_list);
2644
1.61k
    mem_delete(dht->mem, dht->loaded_nodes_list);
2645
1.61k
    crypto_memzero(dht->self_secret_key, sizeof(dht->self_secret_key));
2646
1.61k
    mem_delete(dht->mem, dht);
2647
1.61k
}
2648
2649
/* new DHT format for load/save, more robust and forward compatible */
2650
// TODO(irungentoo): Move this closer to Messenger.
2651
1.61k
#define DHT_STATE_COOKIE_GLOBAL 0x159000d
2652
2653
2.58k
#define DHT_STATE_COOKIE_TYPE      0x11ce
2654
1.51k
#define DHT_STATE_TYPE_NODES       4
2655
2656
2.02k
#define MAX_SAVED_DHT_NODES (((DHT_FAKE_FRIEND_NUMBER * MAX_FRIEND_CLIENTS) + LCLIENT_LIST) * 2)
2657
2658
/** Get the size of the DHT (for saving). */
2659
uint32_t dht_size(const DHT *dht)
2660
2.94k
{
2661
2.94k
    uint32_t numv4 = 0;
2662
2.94k
    uint32_t numv6 = 0;
2663
2664
13.4k
    for (uint32_t i = 0; i < dht->loaded_num_nodes; ++i) {
2665
10.5k
        numv4 += net_family_is_ipv4(dht->loaded_nodes_list[i].ip_port.ip.family) ? 1 : 0;
2666
10.5k
        numv6 += net_family_is_ipv6(dht->loaded_nodes_list[i].ip_port.ip.family) ? 1 : 0;
2667
10.5k
    }
2668
2669
3.01M
    for (uint32_t i = 0; i < LCLIENT_LIST; ++i) {
2670
3.01M
        numv4 += dht->close_clientlist[i].assoc4.timestamp != 0 ? 1 : 0;
2671
3.01M
        numv6 += dht->close_clientlist[i].assoc6.timestamp != 0 ? 1 : 0;
2672
3.01M
    }
2673
2674
8.83k
    for (uint32_t i = 0; i < DHT_FAKE_FRIEND_NUMBER && i < dht->num_friends; ++i) {
2675
5.89k
        const DHT_Friend *const fr = &dht->friends_list[i];
2676
2677
53.0k
        for (uint32_t j = 0; j < MAX_FRIEND_CLIENTS; ++j) {
2678
47.1k
            numv4 += fr->client_list[j].assoc4.timestamp != 0 ? 1 : 0;
2679
47.1k
            numv6 += fr->client_list[j].assoc6.timestamp != 0 ? 1 : 0;
2680
47.1k
        }
2681
5.89k
    }
2682
2683
2.94k
    const uint32_t size32 = sizeof(uint32_t);
2684
2.94k
    const uint32_t sizesubhead = size32 * 2;
2685
2686
2.94k
    return size32 + sizesubhead + packed_node_size(net_family_ipv4()) * numv4 + packed_node_size(net_family_ipv6()) * numv6;
2687
2.94k
}
2688
2689
/** Save the DHT in data where data is an array of size `dht_size()`. */
2690
void dht_save(const DHT *dht, uint8_t *data)
2691
982
{
2692
982
    host_to_lendian_bytes32(data, DHT_STATE_COOKIE_GLOBAL);
2693
982
    data += sizeof(uint32_t);
2694
2695
982
    uint8_t *const old_data = data;
2696
2697
    /* get right offset. we write the actual header later. */
2698
982
    data = state_write_section_header(data, DHT_STATE_COOKIE_TYPE, 0, 0);
2699
2700
982
    Node_format *clients = (Node_format *)mem_valloc(dht->mem, MAX_SAVED_DHT_NODES, sizeof(Node_format));
2701
2702
982
    if (clients == nullptr) {
2703
0
        LOGGER_ERROR(dht->log, "could not allocate %u nodes", (unsigned int)MAX_SAVED_DHT_NODES);
2704
0
        return;
2705
0
    }
2706
2707
982
    uint32_t num = 0;
2708
2709
982
    if (dht->loaded_num_nodes > 0) {
2710
162
        memcpy(clients, dht->loaded_nodes_list, sizeof(Node_format) * dht->loaded_num_nodes);
2711
162
        num += dht->loaded_num_nodes;
2712
162
    }
2713
2714
1.00M
    for (uint32_t i = 0; i < LCLIENT_LIST; ++i) {
2715
1.00M
        if (dht->close_clientlist[i].assoc4.timestamp != 0) {
2716
0
            memcpy(clients[num].public_key, dht->close_clientlist[i].public_key, CRYPTO_PUBLIC_KEY_SIZE);
2717
0
            clients[num].ip_port = dht->close_clientlist[i].assoc4.ip_port;
2718
0
            ++num;
2719
0
        }
2720
2721
1.00M
        if (dht->close_clientlist[i].assoc6.timestamp != 0) {
2722
0
            memcpy(clients[num].public_key, dht->close_clientlist[i].public_key, CRYPTO_PUBLIC_KEY_SIZE);
2723
0
            clients[num].ip_port = dht->close_clientlist[i].assoc6.ip_port;
2724
0
            ++num;
2725
0
        }
2726
1.00M
    }
2727
2728
2.94k
    for (uint32_t i = 0; i < DHT_FAKE_FRIEND_NUMBER && i < dht->num_friends; ++i) {
2729
1.96k
        const DHT_Friend *const fr = &dht->friends_list[i];
2730
2731
17.6k
        for (uint32_t j = 0; j < MAX_FRIEND_CLIENTS; ++j) {
2732
15.7k
            if (fr->client_list[j].assoc4.timestamp != 0) {
2733
0
                memcpy(clients[num].public_key, fr->client_list[j].public_key, CRYPTO_PUBLIC_KEY_SIZE);
2734
0
                clients[num].ip_port = fr->client_list[j].assoc4.ip_port;
2735
0
                ++num;
2736
0
            }
2737
2738
15.7k
            if (fr->client_list[j].assoc6.timestamp != 0) {
2739
0
                memcpy(clients[num].public_key, fr->client_list[j].public_key, CRYPTO_PUBLIC_KEY_SIZE);
2740
0
                clients[num].ip_port = fr->client_list[j].assoc6.ip_port;
2741
0
                ++num;
2742
0
            }
2743
15.7k
        }
2744
1.96k
    }
2745
2746
982
    state_write_section_header(
2747
982
        old_data, DHT_STATE_COOKIE_TYPE, pack_nodes(dht->log, data, sizeof(Node_format) * num, clients, num),
2748
982
        DHT_STATE_TYPE_NODES);
2749
2750
982
    mem_delete(dht->mem, clients);
2751
982
}
2752
2753
/** Bootstrap from this number of nodes every time `dht_connect_after_load()` is called */
2754
0
#define SAVE_BOOTSTAP_FREQUENCY 8
2755
2756
int dht_connect_after_load(DHT *dht)
2757
0
{
2758
0
    if (dht == nullptr) {
2759
0
        return -1;
2760
0
    }
2761
2762
0
    if (dht->loaded_nodes_list == nullptr) {
2763
0
        return -1;
2764
0
    }
2765
2766
    /* DHT is connected, stop. */
2767
0
    if (dht_non_lan_connected(dht)) {
2768
0
        mem_delete(dht->mem, dht->loaded_nodes_list);
2769
0
        dht->loaded_nodes_list = nullptr;
2770
0
        dht->loaded_num_nodes = 0;
2771
0
        return 0;
2772
0
    }
2773
2774
0
    for (uint32_t i = 0; i < dht->loaded_num_nodes && i < SAVE_BOOTSTAP_FREQUENCY; ++i) {
2775
0
        const unsigned int index = dht->loaded_nodes_index % dht->loaded_num_nodes;
2776
0
        dht_bootstrap(dht, &dht->loaded_nodes_list[index].ip_port, dht->loaded_nodes_list[index].public_key);
2777
0
        ++dht->loaded_nodes_index;
2778
0
    }
2779
2780
0
    return 0;
2781
0
}
2782
2783
static State_Load_Status dht_load_state_callback(void *_Nonnull outer, const uint8_t *_Nonnull data, uint32_t length, uint16_t type)
2784
599
{
2785
599
    DHT *dht = (DHT *)outer;
2786
2787
599
    switch (type) {
2788
533
        case DHT_STATE_TYPE_NODES: {
2789
533
            if (length == 0) {
2790
10
                break;
2791
10
            }
2792
2793
523
            mem_delete(dht->mem, dht->loaded_nodes_list);
2794
2795
            // Copy to loaded_clients_list
2796
523
            Node_format *nodes = (Node_format *)mem_valloc(dht->mem, MAX_SAVED_DHT_NODES, sizeof(Node_format));
2797
2798
523
            if (nodes == nullptr) {
2799
0
                LOGGER_ERROR(dht->log, "could not allocate %u nodes", (unsigned int)MAX_SAVED_DHT_NODES);
2800
0
                dht->loaded_num_nodes = 0;
2801
0
                break;
2802
0
            }
2803
2804
523
            const int num = unpack_nodes(nodes, MAX_SAVED_DHT_NODES, nullptr, data, length, false);
2805
2806
523
            if (num < 0) {
2807
                // Unpack error happened, we ignore it.
2808
36
                dht->loaded_num_nodes = 0;
2809
487
            } else {
2810
487
                dht->loaded_num_nodes = num;
2811
487
            }
2812
2813
523
            dht->loaded_nodes_list = nodes;
2814
2815
523
            break;
2816
523
        }
2817
2818
66
        default: {
2819
66
            LOGGER_ERROR(dht->log, "Load state (DHT): contains unrecognized part (len %u, type %u)",
2820
66
                         length, type);
2821
66
            break;
2822
523
        }
2823
599
    }
2824
2825
599
    return STATE_LOAD_STATUS_CONTINUE;
2826
599
}
2827
2828
int dht_load(DHT *dht, const uint8_t *data, uint32_t length)
2829
701
{
2830
701
    const uint32_t cookie_len = sizeof(uint32_t);
2831
2832
701
    if (length > cookie_len) {
2833
635
        uint32_t data32;
2834
635
        lendian_bytes_to_host32(&data32, data);
2835
2836
635
        if (data32 == DHT_STATE_COOKIE_GLOBAL) {
2837
616
            return state_load(dht->log, dht_load_state_callback, dht, data + cookie_len,
2838
616
                              length - cookie_len, DHT_STATE_COOKIE_TYPE);
2839
616
        }
2840
635
    }
2841
2842
85
    return -1;
2843
701
}
2844
2845
/**
2846
 * @retval false if we are not connected to the DHT.
2847
 * @retval true if we are.
2848
 */
2849
bool dht_isconnected(const DHT *dht)
2850
0
{
2851
0
    for (uint32_t i = 0; i < LCLIENT_LIST; ++i) {
2852
0
        const Client_data *const client = &dht->close_clientlist[i];
2853
2854
0
        if (!assoc_timeout(dht->cur_time, &client->assoc4) ||
2855
0
                !assoc_timeout(dht->cur_time, &client->assoc6)) {
2856
0
            return true;
2857
0
        }
2858
0
    }
2859
2860
0
    return false;
2861
0
}
2862
2863
/**
2864
 * @retval false if we are not connected or only connected to lan peers with the DHT.
2865
 * @retval true if we are.
2866
 */
2867
bool dht_non_lan_connected(const DHT *dht)
2868
14
{
2869
14.3k
    for (uint32_t i = 0; i < LCLIENT_LIST; ++i) {
2870
14.3k
        const Client_data *const client = &dht->close_clientlist[i];
2871
2872
14.3k
        if (!assoc_timeout(dht->cur_time, &client->assoc4)
2873
0
                && !ip_is_lan(&client->assoc4.ip_port.ip)) {
2874
0
            return true;
2875
0
        }
2876
2877
14.3k
        if (!assoc_timeout(dht->cur_time, &client->assoc6)
2878
0
                && !ip_is_lan(&client->assoc6.ip_port.ip)) {
2879
0
            return true;
2880
0
        }
2881
14.3k
    }
2882
2883
14
    return false;
2884
14
}
2885
2886
uint16_t dht_get_num_closelist(const DHT *dht)
2887
0
{
2888
0
    uint16_t num_valid_close_clients = 0;
2889
0
    for (uint32_t i = 0; i < LCLIENT_LIST; ++i) {
2890
0
        const Client_data *const client = dht_get_close_client(dht, i);
2891
2892
        // check if client is valid
2893
0
        if (!(assoc_timeout(dht->cur_time, &client->assoc4) && assoc_timeout(dht->cur_time, &client->assoc6))) {
2894
0
            ++num_valid_close_clients;
2895
0
        }
2896
0
    }
2897
2898
0
    return num_valid_close_clients;
2899
0
}
2900
2901
uint16_t dht_get_num_closelist_announce_capable(const DHT *dht)
2902
0
{
2903
0
    uint16_t num_valid_close_clients_with_cap = 0;
2904
0
    for (uint32_t i = 0; i < LCLIENT_LIST; ++i) {
2905
0
        const Client_data *const client = dht_get_close_client(dht, i);
2906
2907
        // check if client is valid
2908
0
        if (!(assoc_timeout(dht->cur_time, &client->assoc4) && assoc_timeout(dht->cur_time, &client->assoc6)) && client->announce_node) {
2909
0
            ++num_valid_close_clients_with_cap;
2910
0
        }
2911
0
    }
2912
2913
0
    return num_valid_close_clients_with_cap;
2914
0
}
2915
2916
unsigned int ipport_self_copy(const DHT *dht, IP_Port *dest)
2917
0
{
2918
0
    ipport_reset(dest);
2919
2920
0
    bool is_lan = false;
2921
2922
0
    for (uint32_t i = 0; i < LCLIENT_LIST; ++i) {
2923
0
        const Client_data *client = dht_get_close_client(dht, i);
2924
0
        const IP_Port *ip_port4 = &client->assoc4.ret_ip_port;
2925
2926
0
        if (client->assoc4.ret_ip_self && ipport_isset(ip_port4)) {
2927
0
            ipport_copy(dest, ip_port4);
2928
0
            is_lan = ip_is_lan(&dest->ip);
2929
2930
0
            if (!is_lan) {
2931
0
                break;
2932
0
            }
2933
0
        }
2934
2935
0
        const IP_Port *ip_port6 = &client->assoc6.ret_ip_port;
2936
2937
0
        if (client->assoc6.ret_ip_self && ipport_isset(ip_port6)) {
2938
0
            ipport_copy(dest, ip_port6);
2939
0
            is_lan = ip_is_lan(&dest->ip);
2940
2941
0
            if (!is_lan) {
2942
0
                break;
2943
0
            }
2944
0
        }
2945
0
    }
2946
2947
0
    if (!ipport_isset(dest)) {
2948
0
        return 0;
2949
0
    }
2950
2951
0
    if (is_lan) {
2952
0
        return 2;
2953
0
    }
2954
2955
0
    return 1;
2956
0
}