Coverage Report

Created: 2025-08-05 10:35

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