Coverage Report

Created: 2025-11-29 10:29

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