summaryrefslogtreecommitdiff
path: root/protocols/Tox/libtox/src/toxcore/DHT.c
diff options
context:
space:
mode:
authordartraiden <wowemuh@gmail.com>2022-02-07 00:34:21 +0300
committerdartraiden <wowemuh@gmail.com>2022-02-07 00:35:37 +0300
commit223306302f39455970b67a97ba62e4a542224f7a (patch)
tree21da0622af231bea688b413d1238d15315d658ce /protocols/Tox/libtox/src/toxcore/DHT.c
parent41317031f257ad6a06fa743860aff212074dc416 (diff)
Update libtox to 0.2.15
Diffstat (limited to 'protocols/Tox/libtox/src/toxcore/DHT.c')
-rw-r--r--protocols/Tox/libtox/src/toxcore/DHT.c1120
1 files changed, 451 insertions, 669 deletions
diff --git a/protocols/Tox/libtox/src/toxcore/DHT.c b/protocols/Tox/libtox/src/toxcore/DHT.c
index 267d46881e..4cc8d2002f 100644
--- a/protocols/Tox/libtox/src/toxcore/DHT.c
+++ b/protocols/Tox/libtox/src/toxcore/DHT.c
@@ -3,15 +3,15 @@
* Copyright © 2013 Tox project.
*/
-/*
+/**
* An implementation of the DHT as seen in docs/updates/DHT.md
*/
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
#include "DHT.h"
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
#include "LAN_discovery.h"
#include "logger.h"
#include "mono_time.h"
@@ -20,22 +20,18 @@
#include "state.h"
#include "util.h"
-#include <assert.h>
-#include <stdlib.h>
-#include <string.h>
-
-/* The timeout after which a node is discarded completely. */
+/** The timeout after which a node is discarded completely. */
#define KILL_NODE_TIMEOUT (BAD_NODE_TIMEOUT + PING_INTERVAL)
-/* Ping interval in seconds for each random sending of a get nodes request. */
+/** Ping interval in seconds for each random sending of a get nodes request. */
#define GET_NODE_INTERVAL 20
#define MAX_PUNCHING_PORTS 48
-/* Interval in seconds between punching attempts*/
+/** Interval in seconds between punching attempts*/
#define PUNCH_INTERVAL 3
-/* Time in seconds after which punching parameters will be reset */
+/** Time in seconds after which punching parameters will be reset */
#define PUNCH_RESET_TIME 40
#define MAX_NORMAL_PUNCHING_TRIES 5
@@ -43,7 +39,7 @@
#define NAT_PING_REQUEST 0
#define NAT_PING_RESPONSE 1
-/* Number of get node requests to send to quickly find close nodes. */
+/** Number of get node requests to send to quickly find close nodes. */
#define MAX_BOOTSTRAP_TIMES 5
typedef struct DHT_Friend_Callback {
@@ -103,8 +99,7 @@ struct DHT {
struct Ping *ping;
Ping_Array *dht_ping_array;
- Ping_Array *dht_harden_ping_array;
- uint64_t last_run;
+ uint64_t cur_time;
Cryptopacket_Handler cryptopackethandlers[256];
@@ -178,7 +173,23 @@ static bool assoc_timeout(uint64_t cur_time, const IPPTsPng *assoc)
return (assoc->timestamp + BAD_NODE_TIMEOUT) <= cur_time;
}
-/* Compares pk1 and pk2 with pk.
+/** Converts an IPv4-in-IPv6 to IPv4 and returns the new IP_Port.
+ *
+ * If the ip_port is already IPv4 this function returns a copy of the original ip_port.
+ */
+static IP_Port ip_port_normalize(const IP_Port *ip_port)
+{
+ IP_Port res = *ip_port;
+
+ if (net_family_is_ipv6(res.ip.family) && ipv6_ipv4_in_v6(&res.ip.ip.v6)) {
+ res.ip.family = net_family_ipv4;
+ res.ip.ip.v4.uint32 = res.ip.ip.v6.uint32[3];
+ }
+
+ return res;
+}
+
+/** Compares pk1 and pk2 with pk.
*
* return 0 if both are same distance.
* return 1 if pk1 is closer.
@@ -202,7 +213,7 @@ int id_closest(const uint8_t *pk, const uint8_t *pk1, const uint8_t *pk2)
return 0;
}
-/* Return index of first unequal bit number.
+/** Return index of first unequal bit number.
*/
static unsigned int bit_by_bit_cmp(const uint8_t *pk1, const uint8_t *pk2)
{
@@ -228,11 +239,11 @@ static unsigned int bit_by_bit_cmp(const uint8_t *pk1, const uint8_t *pk2)
return i * 8 + j;
}
-/* Shared key generations are costly, it is therefore smart to store commonly used
- * ones so that they can re used later without being computed again.
+/** Shared key generations are costly, it is therefore smart to store commonly used
+ * ones so that they can be re-used later without being computed again.
*
- * If shared key is already in shared_keys, copy it to shared_key.
- * else generate it into shared_key and copy it to shared_keys
+ * If a shared key is already in shared_keys, copy it to shared_key.
+ * Otherwise generate it into shared_key and copy it to shared_keys
*/
void get_shared_key(const Mono_Time *mono_time, Shared_Keys *shared_keys, uint8_t *shared_key,
const uint8_t *secret_key, const uint8_t *public_key)
@@ -279,7 +290,7 @@ void get_shared_key(const Mono_Time *mono_time, Shared_Keys *shared_keys, uint8_
}
}
-/* Copy shared_key to encrypt/decrypt DHT packet from public_key into shared_key
+/** Copy shared_key to encrypt/decrypt DHT packet from public_key into shared_key
* for packets that we receive.
*/
void dht_get_shared_key_recv(DHT *dht, uint8_t *shared_key, const uint8_t *public_key)
@@ -287,7 +298,7 @@ void dht_get_shared_key_recv(DHT *dht, uint8_t *shared_key, const uint8_t *publi
get_shared_key(dht->mono_time, &dht->shared_keys_recv, shared_key, dht->self_secret_key, public_key);
}
-/* Copy shared_key to encrypt/decrypt DHT packet from public_key into shared_key
+/** Copy shared_key to encrypt/decrypt DHT packet from public_key into shared_key
* for packets that we send.
*/
void dht_get_shared_key_sent(DHT *dht, uint8_t *shared_key, const uint8_t *public_key)
@@ -297,7 +308,7 @@ void dht_get_shared_key_sent(DHT *dht, uint8_t *shared_key, const uint8_t *publi
#define CRYPTO_SIZE (1 + CRYPTO_PUBLIC_KEY_SIZE * 2 + CRYPTO_NONCE_SIZE)
-/* Create a request to peer.
+/** Create a request to peer.
* send_public_key and send_secret_key are the pub/secret keys of the sender.
* recv_public_key is public key of receiver.
* packet must be an array of MAX_CRYPTO_REQUEST_SIZE big.
@@ -339,7 +350,7 @@ int create_request(const uint8_t *send_public_key, const uint8_t *send_secret_ke
return len + CRYPTO_SIZE;
}
-/* Puts the senders public key in the request in public_key, the data from the request
+/** Puts the senders public key in the request in public_key, the data from the request
* in data if a friend or ping request was sent to us and returns the length of the data.
* packet is the request packet and length is its length.
*
@@ -381,7 +392,7 @@ int handle_request(const uint8_t *self_public_key, const uint8_t *self_secret_ke
#define PACKED_NODE_SIZE_IP4 (1 + SIZE_IP4 + sizeof(uint16_t) + CRYPTO_PUBLIC_KEY_SIZE)
#define PACKED_NODE_SIZE_IP6 (1 + SIZE_IP6 + sizeof(uint16_t) + CRYPTO_PUBLIC_KEY_SIZE)
-/* Return packet size of packed node with ip_family on success.
+/** Return packet size of packed node with ip_family on success.
* Return -1 on failure.
*/
int packed_node_size(Family ip_family)
@@ -398,7 +409,9 @@ int packed_node_size(Family ip_family)
}
-/* Packs an IP_Port structure into data of max size length.
+/** Packs an IP_Port structure into data of max size length.
+ *
+ * Packed_length is the offset of data currently packed.
*
* Returns size of packed IP_Port data on success
* Return -1 on failure.
@@ -455,7 +468,8 @@ int pack_ip_port(uint8_t *data, uint16_t length, const IP_Port *ip_port)
}
static int dht_create_packet(const uint8_t public_key[CRYPTO_PUBLIC_KEY_SIZE],
- const uint8_t *shared_key, const uint8_t type, uint8_t *plain, size_t plain_length, uint8_t *packet)
+ const uint8_t *shared_key, const uint8_t type,
+ const uint8_t *plain, size_t plain_length, uint8_t *packet)
{
VLA(uint8_t, encrypted, plain_length + CRYPTO_MAC_SIZE);
uint8_t nonce[CRYPTO_NONCE_SIZE];
@@ -476,7 +490,9 @@ static int dht_create_packet(const uint8_t public_key[CRYPTO_PUBLIC_KEY_SIZE],
return 1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE + encrypted_length;
}
-/* Unpack IP_Port structure from data of max size length into ip_port.
+/** Unpack IP_Port structure from data of max size length into ip_port.
+ *
+ * len_processed is the offset of data currently unpacked.
*
* Return size of unpacked ip_port on success.
* Return -1 on failure.
@@ -514,6 +530,10 @@ int unpack_ip_port(IP_Port *ip_port, const uint8_t *data, uint16_t length, bool
return -1;
}
+ *ip_port = (IP_Port) {
+ 0
+ };
+
if (is_ipv4) {
const uint32_t size = 1 + SIZE_IP4 + sizeof(uint16_t);
@@ -539,7 +559,7 @@ int unpack_ip_port(IP_Port *ip_port, const uint8_t *data, uint16_t length, bool
}
}
-/* Pack number of nodes into data of maxlength length.
+/** Pack number of nodes into data of maxlength length.
*
* return length of packed nodes on success.
* return -1 on failure.
@@ -573,7 +593,7 @@ int pack_nodes(uint8_t *data, uint16_t length, const Node_format *nodes, uint16_
return packed_length;
}
-/* Unpack data of length into nodes of size max_num_nodes.
+/** Unpack data of length into nodes of size max_num_nodes.
* Put the length of the data processed in processed_data_len.
* tcp_enabled sets if TCP nodes are expected (true) or not (false).
*
@@ -616,37 +636,44 @@ int unpack_nodes(Node_format *nodes, uint16_t max_num_nodes, uint16_t *processed
return num;
}
-/* Find index in an array with public_key equal to pk.
+/** Find index in an array with public_key equal to pk.
*
* return index or UINT32_MAX if not found.
*/
-#define INDEX_OF_PK(array, size, pk) \
- do { \
- for (uint32_t i = 0; i < size; ++i) { \
- if (id_equal(array[i].public_key, pk)) { \
- return i; \
- } \
- } \
- \
- return UINT32_MAX; \
- } while (0)
-
static uint32_t index_of_client_pk(const Client_data *array, uint32_t size, const uint8_t *pk)
{
- INDEX_OF_PK(array, size, pk);
+ for (uint32_t i = 0; i < size; ++i) {
+ if (id_equal(array[i].public_key, pk)) {
+ return i;
+ }
+ }
+
+ return UINT32_MAX;
}
static uint32_t index_of_friend_pk(const DHT_Friend *array, uint32_t size, const uint8_t *pk)
{
- INDEX_OF_PK(array, size, pk);
+ for (uint32_t i = 0; i < size; ++i) {
+ if (id_equal(array[i].public_key, pk)) {
+ return i;
+ }
+ }
+
+ return UINT32_MAX;
}
static uint32_t index_of_node_pk(const Node_format *array, uint32_t size, const uint8_t *pk)
{
- INDEX_OF_PK(array, size, pk);
+ for (uint32_t i = 0; i < size; ++i) {
+ if (id_equal(array[i].public_key, pk)) {
+ return i;
+ }
+ }
+
+ return UINT32_MAX;
}
-/* Find index of Client_data with ip_port equal to param ip_port.
+/** Find index of Client_data with ip_port equal to param ip_port.
*
* return index or UINT32_MAX if not found.
*/
@@ -662,43 +689,43 @@ static uint32_t index_of_client_ip_port(const Client_data *array, uint32_t size,
return UINT32_MAX;
}
-/* Update ip_port of client if it's needed.
+/** Update ip_port of client if it's needed.
*/
static void update_client(const Logger *log, const Mono_Time *mono_time, int index, Client_data *client,
- IP_Port ip_port)
+ const IP_Port *ip_port)
{
IPPTsPng *assoc;
int ip_version;
- if (net_family_is_ipv4(ip_port.ip.family)) {
+ if (net_family_is_ipv4(ip_port->ip.family)) {
assoc = &client->assoc4;
ip_version = 4;
- } else if (net_family_is_ipv6(ip_port.ip.family)) {
+ } else if (net_family_is_ipv6(ip_port->ip.family)) {
assoc = &client->assoc6;
ip_version = 6;
} else {
return;
}
- if (!ipport_equal(&assoc->ip_port, &ip_port)) {
+ if (!ipport_equal(&assoc->ip_port, ip_port)) {
char ip_str[IP_NTOA_LEN];
LOGGER_TRACE(log, "coipil[%u]: switching ipv%d from %s:%u to %s:%u",
index, ip_version,
ip_ntoa(&assoc->ip_port.ip, ip_str, sizeof(ip_str)),
net_ntohs(assoc->ip_port.port),
- ip_ntoa(&ip_port.ip, ip_str, sizeof(ip_str)),
- net_ntohs(ip_port.port));
+ ip_ntoa(&ip_port->ip, ip_str, sizeof(ip_str)),
+ net_ntohs(ip_port->port));
}
- if (!ip_is_lan(assoc->ip_port.ip) && ip_is_lan(ip_port.ip)) {
+ if (!ip_is_lan(&assoc->ip_port.ip) && ip_is_lan(&ip_port->ip)) {
return;
}
- assoc->ip_port = ip_port;
+ assoc->ip_port = *ip_port;
assoc->timestamp = mono_time_get(mono_time);
}
-/* Check if client with public_key is already in list of length length.
+/** Check if client with public_key is already in list of length length.
* If it is then set its corresponding timestamp to current time.
* If the id is already in the list with a different ip_port, update it.
* TODO(irungentoo): Maybe optimize this.
@@ -706,7 +733,7 @@ static void update_client(const Logger *log, const Mono_Time *mono_time, int ind
* return True(1) or False(0)
*/
static int client_or_ip_port_in_list(const Logger *log, const Mono_Time *mono_time, Client_data *list, uint16_t length,
- const uint8_t *public_key, IP_Port ip_port)
+ const uint8_t *public_key, const IP_Port *ip_port)
{
const uint64_t temp_time = mono_time_get(mono_time);
uint32_t index = index_of_client_pk(list, length, public_key);
@@ -722,7 +749,7 @@ static int client_or_ip_port_in_list(const Logger *log, const Mono_Time *mono_ti
* TODO(irungentoo): maybe we SHOULDN'T do that if that public_key is in a friend_list
* and the one who is the actual friend's public_key/address set?
* MAYBE: check the other address, if valid, don't nuke? */
- index = index_of_client_ip_port(list, length, &ip_port);
+ index = index_of_client_ip_port(list, length, ip_port);
if (index == UINT32_MAX) {
return 0;
@@ -731,7 +758,7 @@ static int client_or_ip_port_in_list(const Logger *log, const Mono_Time *mono_ti
IPPTsPng *assoc;
int ip_version;
- if (net_family_is_ipv4(ip_port.ip.family)) {
+ if (net_family_is_ipv4(ip_port->ip.family)) {
assoc = &list[index].assoc4;
ip_version = 4;
} else {
@@ -746,11 +773,13 @@ static int client_or_ip_port_in_list(const Logger *log, const Mono_Time *mono_ti
LOGGER_DEBUG(log, "coipil[%u]: switching public_key (ipv%d)", index, ip_version);
/* kill the other address, if it was set */
- memset(assoc, 0, sizeof(IPPTsPng));
+ *assoc = (IPPTsPng) {
+ 0
+ };
return 1;
}
-bool add_to_list(Node_format *nodes_list, uint32_t length, const uint8_t *pk, IP_Port ip_port,
+bool add_to_list(Node_format *nodes_list, uint32_t length, const uint8_t *pk, const IP_Port *ip_port,
const uint8_t *cmp_pk)
{
for (uint32_t i = 0; i < length; ++i) {
@@ -759,10 +788,10 @@ bool add_to_list(Node_format *nodes_list, uint32_t length, const uint8_t *pk, IP
memcpy(pk_bak, nodes_list[i].public_key, CRYPTO_PUBLIC_KEY_SIZE);
const IP_Port ip_port_bak = nodes_list[i].ip_port;
memcpy(nodes_list[i].public_key, pk, CRYPTO_PUBLIC_KEY_SIZE);
- nodes_list[i].ip_port = ip_port;
+ nodes_list[i].ip_port = *ip_port;
if (i != length - 1) {
- add_to_list(nodes_list, length, pk_bak, ip_port_bak, cmp_pk);
+ add_to_list(nodes_list, length, pk_bak, &ip_port_bak, cmp_pk);
}
return true;
@@ -772,25 +801,12 @@ bool add_to_list(Node_format *nodes_list, uint32_t length, const uint8_t *pk, IP
return false;
}
-/* TODO(irungentoo): change this to 7 when done*/
-#define HARDENING_ALL_OK 2
-/* return 0 if not.
- * return 1 if route request are ok
- * return 2 if it responds to send node packets correctly
- * return 4 if it can test other nodes correctly
- * return HARDENING_ALL_OK if all ok.
- */
-static uint8_t hardening_correct(const Hardening *h)
-{
- return h->routes_requests_ok + (h->send_nodes_ok << 1) + (h->testing_requests << 2);
-}
-
-/*
+/**
* helper for get_close_nodes(). argument list is a monster :D
*/
static void get_close_nodes_inner(uint64_t cur_time, const uint8_t *public_key, Node_format *nodes_list,
Family sa_family, const Client_data *client_list, uint32_t client_list_length,
- uint32_t *num_nodes_ptr, bool is_LAN, uint8_t want_good)
+ uint32_t *num_nodes_ptr, bool is_LAN)
{
if (!net_family_is_ipv4(sa_family) && !net_family_is_ipv6(sa_family) && !net_family_is_unspec(sa_family)) {
return;
@@ -824,12 +840,7 @@ static void get_close_nodes_inner(uint64_t cur_time, const uint8_t *public_key,
}
/* don't send LAN ips to non LAN peers */
- if (ip_is_lan(ipptp->ip_port.ip) && !is_LAN) {
- continue;
- }
-
- if (!ip_is_lan(ipptp->ip_port.ip) && want_good && hardening_correct(&ipptp->hardening) != HARDENING_ALL_OK
- && !id_equal(public_key, client->public_key)) {
+ if (ip_is_lan(&ipptp->ip_port.ip) && !is_LAN) {
continue;
}
@@ -838,78 +849,58 @@ static void get_close_nodes_inner(uint64_t cur_time, const uint8_t *public_key,
nodes_list[num_nodes].ip_port = ipptp->ip_port;
++num_nodes;
} else {
- add_to_list(nodes_list, MAX_SENT_NODES, client->public_key, ipptp->ip_port, public_key);
+ add_to_list(nodes_list, MAX_SENT_NODES, client->public_key, &ipptp->ip_port, public_key);
}
}
*num_nodes_ptr = num_nodes;
}
-/* Find MAX_SENT_NODES nodes closest to the public_key for the send nodes request:
+/** Find MAX_SENT_NODES nodes closest to the public_key for the send nodes request:
* put them in the nodes_list and return how many were found.
*
* TODO(irungentoo): For the love of based <your favorite deity, in doubt use
* "love"> make this function cleaner and much more efficient.
- *
- * want_good : do we want only good nodes as checked with the hardening returned or not?
*/
static int get_somewhat_close_nodes(const DHT *dht, const uint8_t *public_key, Node_format *nodes_list,
- Family sa_family, bool is_LAN, uint8_t want_good)
+ Family sa_family, bool is_LAN)
{
uint32_t num_nodes = 0;
- get_close_nodes_inner(dht->last_run, public_key, nodes_list, sa_family,
- dht->close_clientlist, LCLIENT_LIST, &num_nodes, is_LAN, 0);
-
- /* TODO(irungentoo): uncomment this when hardening is added to close friend clients */
-#if 0
+ get_close_nodes_inner(dht->cur_time, public_key, nodes_list, sa_family,
+ dht->close_clientlist, LCLIENT_LIST, &num_nodes, is_LAN);
for (uint32_t i = 0; i < dht->num_friends; ++i) {
- get_close_nodes_inner(dht->mono_time, public_key, nodes_list, sa_family,
+ get_close_nodes_inner(dht->cur_time, public_key, nodes_list, sa_family,
dht->friends_list[i].client_list, MAX_FRIEND_CLIENTS,
- &num_nodes, is_LAN, want_good);
- }
-
-#endif
-
- for (uint32_t i = 0; i < dht->num_friends; ++i) {
- get_close_nodes_inner(dht->last_run, public_key, nodes_list, sa_family,
- dht->friends_list[i].client_list, MAX_FRIEND_CLIENTS,
- &num_nodes, is_LAN, 0);
+ &num_nodes, is_LAN);
}
return num_nodes;
}
int get_close_nodes(const DHT *dht, const uint8_t *public_key, Node_format *nodes_list, Family sa_family,
- bool is_LAN, uint8_t want_good)
+ bool is_LAN)
{
memset(nodes_list, 0, MAX_SENT_NODES * sizeof(Node_format));
- return get_somewhat_close_nodes(dht, public_key, nodes_list, sa_family, is_LAN, want_good);
+ return get_somewhat_close_nodes(dht, public_key, nodes_list, sa_family, is_LAN);
}
-typedef struct DHT_Cmp_data {
+typedef struct DHT_Cmp_Data {
uint64_t cur_time;
const uint8_t *base_public_key;
Client_data entry;
-} DHT_Cmp_data;
-
-static bool incorrect_hardening(const IPPTsPng *assoc)
-{
- return hardening_correct(&assoc->hardening) != HARDENING_ALL_OK;
-}
+} DHT_Cmp_Data;
-static int cmp_dht_entry(const void *a, const void *b)
+static int dht_cmp_entry(const void *a, const void *b)
{
- DHT_Cmp_data cmp1;
- DHT_Cmp_data cmp2;
- memcpy(&cmp1, a, sizeof(DHT_Cmp_data));
- memcpy(&cmp2, b, sizeof(DHT_Cmp_data));
- const Client_data entry1 = cmp1.entry;
- const Client_data entry2 = cmp2.entry;
- const uint8_t *cmp_public_key = cmp1.base_public_key;
+ const DHT_Cmp_Data *cmp1 = (const DHT_Cmp_Data *)a;
+ const DHT_Cmp_Data *cmp2 = (const DHT_Cmp_Data *)b;
+ const Client_data entry1 = cmp1->entry;
+ const Client_data entry2 = cmp2->entry;
+ const uint8_t *cmp_public_key = cmp1->base_public_key;
- bool t1 = assoc_timeout(cmp1.cur_time, &entry1.assoc4) && assoc_timeout(cmp1.cur_time, &entry1.assoc6);
- bool t2 = assoc_timeout(cmp2.cur_time, &entry2.assoc4) && assoc_timeout(cmp2.cur_time, &entry2.assoc6);
+ const bool t1 = assoc_timeout(cmp1->cur_time, &entry1.assoc4) && assoc_timeout(cmp1->cur_time, &entry1.assoc6);
+ const bool t2 = assoc_timeout(cmp2->cur_time, &entry2.assoc4) && assoc_timeout(cmp2->cur_time, &entry2.assoc6);
if (t1 && t2) {
return 0;
@@ -923,17 +914,6 @@ static int cmp_dht_entry(const void *a, const void *b)
return 1;
}
- t1 = incorrect_hardening(&entry1.assoc4) && incorrect_hardening(&entry1.assoc6);
- t2 = incorrect_hardening(&entry2.assoc4) && incorrect_hardening(&entry2.assoc6);
-
- if (t1 && !t2) {
- return -1;
- }
-
- if (!t1 && t2) {
- return 1;
- }
-
const int close = id_closest(cmp_public_key, entry1.public_key, entry2.public_key);
if (close == 1) {
@@ -947,7 +927,7 @@ static int cmp_dht_entry(const void *a, const void *b)
return 0;
}
-/* Is it ok to store node with public_key in client.
+/** Is it ok to store node with public_key in client.
*
* return 0 if node can't be stored.
* return 1 if it can.
@@ -965,7 +945,7 @@ static void sort_client_list(Client_data *list, uint64_t cur_time, unsigned int
{
// Pass comp_public_key to qsort with each Client_data entry, so the
// comparison function can use it as the base of comparison.
- VLA(DHT_Cmp_data, cmp_list, length);
+ VLA(DHT_Cmp_Data, cmp_list, length);
for (uint32_t i = 0; i < length; ++i) {
cmp_list[i].cur_time = cur_time;
@@ -973,7 +953,7 @@ static void sort_client_list(Client_data *list, uint64_t cur_time, unsigned int
cmp_list[i].entry = list[i];
}
- qsort(cmp_list, length, sizeof(DHT_Cmp_data), cmp_dht_entry);
+ qsort(cmp_list, length, sizeof(DHT_Cmp_Data), dht_cmp_entry);
for (uint32_t i = 0; i < length; ++i) {
list[i] = cmp_list[i].entry;
@@ -999,12 +979,13 @@ static void update_client_with_reset(const Mono_Time *mono_time, Client_data *cl
ip_reset(&ipptp_write->ret_ip_port.ip);
ipptp_write->ret_ip_port.port = 0;
ipptp_write->ret_timestamp = 0;
+ ipptp_write->ret_ip_self = false;
/* zero out other address */
memset(ipptp_clear, 0, sizeof(*ipptp_clear));
}
-/* Replace a first bad (or empty) node with this one
+/** Replace a first bad (or empty) node with this one
* or replace a possibly bad node (tests failed or not done yet)
* that is further than any other in the list
* from the comp_public_key
@@ -1021,35 +1002,35 @@ static bool replace_all(const DHT *dht,
Client_data *list,
uint16_t length,
const uint8_t *public_key,
- IP_Port ip_port,
+ const IP_Port *ip_port,
const uint8_t *comp_public_key)
{
- if (!net_family_is_ipv4(ip_port.ip.family) && !net_family_is_ipv6(ip_port.ip.family)) {
+ if (!net_family_is_ipv4(ip_port->ip.family) && !net_family_is_ipv6(ip_port->ip.family)) {
return false;
}
- if (!store_node_ok(&list[1], dht->last_run, public_key, comp_public_key) &&
- !store_node_ok(&list[0], dht->last_run, public_key, comp_public_key)) {
+ if (!store_node_ok(&list[1], dht->cur_time, public_key, comp_public_key) &&
+ !store_node_ok(&list[0], dht->cur_time, public_key, comp_public_key)) {
return false;
}
- sort_client_list(list, dht->last_run, length, comp_public_key);
+ sort_client_list(list, dht->cur_time, length, comp_public_key);
Client_data *const client = &list[0];
id_copy(client->public_key, public_key);
- update_client_with_reset(dht->mono_time, client, &ip_port);
+ update_client_with_reset(dht->mono_time, client, ip_port);
return true;
}
-/* Add node to close list.
+/** Add node to close list.
*
* simulate is set to 1 if we want to check if a node can be added to the list without adding it.
*
* return -1 on failure.
* return 0 on success.
*/
-static int add_to_close(DHT *dht, const uint8_t *public_key, IP_Port ip_port, bool simulate)
+static int add_to_close(DHT *dht, const uint8_t *public_key, const IP_Port *ip_port, bool simulate)
{
unsigned int index = bit_by_bit_cmp(public_key, dht->self_public_key);
@@ -1062,8 +1043,8 @@ static int add_to_close(DHT *dht, const uint8_t *public_key, IP_Port ip_port, bo
* index is left as >= LCLIENT_LENGTH */
Client_data *const client = &dht->close_clientlist[(index * LCLIENT_NODES) + i];
- if (!assoc_timeout(dht->last_run, &client->assoc4) ||
- !assoc_timeout(dht->last_run, &client->assoc6)) {
+ if (!assoc_timeout(dht->cur_time, &client->assoc4) ||
+ !assoc_timeout(dht->cur_time, &client->assoc6)) {
continue;
}
@@ -1072,22 +1053,22 @@ static int add_to_close(DHT *dht, const uint8_t *public_key, IP_Port ip_port, bo
}
id_copy(client->public_key, public_key);
- update_client_with_reset(dht->mono_time, client, &ip_port);
+ update_client_with_reset(dht->mono_time, client, ip_port);
return 0;
}
return -1;
}
-/* Return 1 if node can be added to close list, 0 if it can't.
+/** Return 1 if node can be added to close list, 0 if it can't.
*/
-bool node_addable_to_close_list(DHT *dht, const uint8_t *public_key, IP_Port ip_port)
+bool node_addable_to_close_list(DHT *dht, const uint8_t *public_key, const IP_Port *ip_port)
{
return add_to_close(dht, public_key, ip_port, 1) == 0;
}
static bool is_pk_in_client_list(const Client_data *list, unsigned int client_list_length, uint64_t cur_time,
- const uint8_t *public_key, IP_Port ip_port)
+ const uint8_t *public_key, const IP_Port *ip_port)
{
const uint32_t index = index_of_client_pk(list, client_list_length, public_key);
@@ -1095,14 +1076,14 @@ static bool is_pk_in_client_list(const Client_data *list, unsigned int client_li
return 0;
}
- const IPPTsPng *assoc = net_family_is_ipv4(ip_port.ip.family)
+ const IPPTsPng *assoc = net_family_is_ipv4(ip_port->ip.family)
? &list[index].assoc4
: &list[index].assoc6;
return !assoc_timeout(cur_time, assoc);
}
-static bool is_pk_in_close_list(DHT *dht, const uint8_t *public_key, IP_Port ip_port)
+static bool is_pk_in_close_list(const DHT *dht, const uint8_t *public_key, const IP_Port *ip_port)
{
unsigned int index = bit_by_bit_cmp(public_key, dht->self_public_key);
@@ -1110,17 +1091,17 @@ static bool is_pk_in_close_list(DHT *dht, const uint8_t *public_key, IP_Port ip_
index = LCLIENT_LENGTH - 1;
}
- return is_pk_in_client_list(dht->close_clientlist + index * LCLIENT_NODES, LCLIENT_NODES, dht->last_run, public_key,
+ return is_pk_in_client_list(dht->close_clientlist + index * LCLIENT_NODES, LCLIENT_NODES, dht->cur_time, public_key,
ip_port);
}
-/* Check if the node obtained with a get_nodes with public_key should be pinged.
+/** Check if the node obtained with a get_nodes with public_key should be pinged.
* NOTE: for best results call it after addto_lists.
*
* return false if the node should not be pinged.
* return true if it should.
*/
-static bool ping_node_from_getnodes_ok(DHT *dht, const uint8_t *public_key, IP_Port ip_port)
+static bool ping_node_from_getnodes_ok(DHT *dht, const uint8_t *public_key, const IP_Port *ip_port)
{
bool ret = false;
@@ -1136,7 +1117,7 @@ static bool ping_node_from_getnodes_ok(DHT *dht, const uint8_t *public_key, IP_P
if (ret && index == UINT32_MAX && !in_close_list) {
if (*num < MAX_CLOSE_TO_BOOTSTRAP_NODES) {
memcpy(dht->to_bootstrap[*num].public_key, public_key, CRYPTO_PUBLIC_KEY_SIZE);
- dht->to_bootstrap[*num].ip_port = ip_port;
+ dht->to_bootstrap[*num].ip_port = *ip_port;
++*num;
} else {
// TODO(irungentoo): ipv6 vs v4
@@ -1150,24 +1131,24 @@ static bool ping_node_from_getnodes_ok(DHT *dht, const uint8_t *public_key, IP_P
bool store_ok = false;
- if (store_node_ok(&dht_friend->client_list[1], dht->last_run, public_key, dht_friend->public_key)) {
+ if (store_node_ok(&dht_friend->client_list[1], dht->cur_time, public_key, dht_friend->public_key)) {
store_ok = true;
}
- if (store_node_ok(&dht_friend->client_list[0], dht->last_run, public_key, dht_friend->public_key)) {
+ if (store_node_ok(&dht_friend->client_list[0], dht->cur_time, public_key, dht_friend->public_key)) {
store_ok = true;
}
unsigned int *const friend_num = &dht_friend->num_to_bootstrap;
const uint32_t index = index_of_node_pk(dht_friend->to_bootstrap, *friend_num, public_key);
- const bool pk_in_list = is_pk_in_client_list(dht_friend->client_list, MAX_FRIEND_CLIENTS, dht->last_run, public_key,
+ const bool pk_in_list = is_pk_in_client_list(dht_friend->client_list, MAX_FRIEND_CLIENTS, dht->cur_time, public_key,
ip_port);
if (store_ok && index == UINT32_MAX && !pk_in_list) {
if (*friend_num < MAX_SENT_NODES) {
Node_format *const format = &dht_friend->to_bootstrap[*friend_num];
memcpy(format->public_key, public_key, CRYPTO_PUBLIC_KEY_SIZE);
- format->ip_port = ip_port;
+ format->ip_port = *ip_port;
++*friend_num;
} else {
add_to_list(dht_friend->to_bootstrap, MAX_SENT_NODES, public_key, ip_port, dht_friend->public_key);
@@ -1180,41 +1161,37 @@ static bool ping_node_from_getnodes_ok(DHT *dht, const uint8_t *public_key, IP_P
return ret;
}
-/* Attempt to add client with ip_port and public_key to the friends client list
+/** Attempt to add client with ip_port and public_key to the friends client list
* and close_clientlist.
*
* returns 1+ if the item is used in any list, 0 else
*/
-uint32_t addto_lists(DHT *dht, IP_Port ip_port, const uint8_t *public_key)
+uint32_t addto_lists(DHT *dht, const IP_Port *ip_port, const uint8_t *public_key)
{
- uint32_t used = 0;
+ IP_Port ipp_copy = ip_port_normalize(ip_port);
- /* convert IPv4-in-IPv6 to IPv4 */
- if (net_family_is_ipv6(ip_port.ip.family) && ipv6_ipv4_in_v6(ip_port.ip.ip.v6)) {
- ip_port.ip.family = net_family_ipv4;
- ip_port.ip.ip.v4.uint32 = ip_port.ip.ip.v6.uint32[3];
- }
+ uint32_t used = 0;
/* NOTE: Current behavior if there are two clients with the same id is
* to replace the first ip by the second.
*/
const bool in_close_list = client_or_ip_port_in_list(dht->log, dht->mono_time, dht->close_clientlist, LCLIENT_LIST,
- public_key, ip_port);
+ public_key, &ipp_copy);
/* add_to_close should be called only if !in_list (don't extract to variable) */
- if (in_close_list || add_to_close(dht, public_key, ip_port, 0)) {
+ if (in_close_list || add_to_close(dht, public_key, &ipp_copy, 0)) {
++used;
}
- DHT_Friend *friend_foundip = nullptr;
+ const DHT_Friend *friend_foundip = nullptr;
for (uint32_t i = 0; i < dht->num_friends; ++i) {
const bool in_list = client_or_ip_port_in_list(dht->log, dht->mono_time, dht->friends_list[i].client_list,
- MAX_FRIEND_CLIENTS, public_key, ip_port);
+ MAX_FRIEND_CLIENTS, public_key, &ipp_copy);
/* replace_all should be called only if !in_list (don't extract to variable) */
if (in_list
- || replace_all(dht, dht->friends_list[i].client_list, MAX_FRIEND_CLIENTS, public_key, ip_port,
+ || replace_all(dht, dht->friends_list[i].client_list, MAX_FRIEND_CLIENTS, public_key, &ipp_copy,
dht->friends_list[i].public_key)) {
DHT_Friend *dht_friend = &dht->friends_list[i];
@@ -1233,15 +1210,15 @@ uint32_t addto_lists(DHT *dht, IP_Port ip_port, const uint8_t *public_key)
for (uint32_t i = 0; i < friend_foundip->lock_count; ++i) {
if (friend_foundip->callbacks[i].ip_callback) {
friend_foundip->callbacks[i].ip_callback(friend_foundip->callbacks[i].data,
- friend_foundip->callbacks[i].number, ip_port);
+ friend_foundip->callbacks[i].number, &ipp_copy);
}
}
return used;
}
-static bool update_client_data(const Mono_Time *mono_time, Client_data *array, size_t size, IP_Port ip_port,
- const uint8_t *pk)
+static bool update_client_data(const Mono_Time *mono_time, Client_data *array, size_t size, const IP_Port *ip_port,
+ const uint8_t *pk, bool node_is_self)
{
const uint64_t temp_time = mono_time_get(mono_time);
const uint32_t index = index_of_client_pk(array, size, pk);
@@ -1253,32 +1230,30 @@ static bool update_client_data(const Mono_Time *mono_time, Client_data *array, s
Client_data *const data = &array[index];
IPPTsPng *assoc;
- if (net_family_is_ipv4(ip_port.ip.family)) {
+ if (net_family_is_ipv4(ip_port->ip.family)) {
assoc = &data->assoc4;
- } else if (net_family_is_ipv6(ip_port.ip.family)) {
+ } else if (net_family_is_ipv6(ip_port->ip.family)) {
assoc = &data->assoc6;
} else {
return true;
}
- assoc->ret_ip_port = ip_port;
+ assoc->ret_ip_port = *ip_port;
assoc->ret_timestamp = temp_time;
+ assoc->ret_ip_self = node_is_self;
+
return true;
}
-/* If public_key is a friend or us, update ret_ip_port
+/** If public_key is a friend or us, update ret_ip_port
* nodepublic_key is the id of the node that sent us this info.
*/
-static void returnedip_ports(DHT *dht, IP_Port ip_port, const uint8_t *public_key, const uint8_t *nodepublic_key)
+static void returnedip_ports(DHT *dht, const IP_Port *ip_port, const uint8_t *public_key, const uint8_t *nodepublic_key)
{
- /* convert IPv4-in-IPv6 to IPv4 */
- if (net_family_is_ipv6(ip_port.ip.family) && ipv6_ipv4_in_v6(ip_port.ip.ip.v6)) {
- ip_port.ip.family = net_family_ipv4;
- ip_port.ip.ip.v4.uint32 = ip_port.ip.ip.v6.uint32[3];
- }
+ IP_Port ipp_copy = ip_port_normalize(ip_port);
if (id_equal(public_key, dht->self_public_key)) {
- update_client_data(dht->mono_time, dht->close_clientlist, LCLIENT_LIST, ip_port, nodepublic_key);
+ update_client_data(dht->mono_time, dht->close_clientlist, LCLIENT_LIST, &ipp_copy, nodepublic_key, true);
return;
}
@@ -1286,41 +1261,36 @@ static void returnedip_ports(DHT *dht, IP_Port ip_port, const uint8_t *public_ke
if (id_equal(public_key, dht->friends_list[i].public_key)) {
Client_data *const client_list = dht->friends_list[i].client_list;
- if (update_client_data(dht->mono_time, client_list, MAX_FRIEND_CLIENTS, ip_port, nodepublic_key)) {
+ if (update_client_data(dht->mono_time, client_list, MAX_FRIEND_CLIENTS, &ipp_copy, nodepublic_key, false)) {
return;
}
}
}
}
-/* Send a getnodes request.
- * sendback_node is the node that it will send back the response to (set to NULL to disable this) */
-static int getnodes(DHT *dht, IP_Port ip_port, const uint8_t *public_key, const uint8_t *client_id,
- const Node_format *sendback_node)
+bool dht_getnodes(DHT *dht, const IP_Port *ip_port, const uint8_t *public_key, const uint8_t *client_id)
{
/* Check if packet is going to be sent to ourself. */
if (id_equal(public_key, dht->self_public_key)) {
- return -1;
+ return false;
}
uint8_t plain_message[sizeof(Node_format) * 2] = {0};
Node_format receiver;
memcpy(receiver.public_key, public_key, CRYPTO_PUBLIC_KEY_SIZE);
- receiver.ip_port = ip_port;
- memcpy(plain_message, &receiver, sizeof(receiver));
+ receiver.ip_port = *ip_port;
+
+ if (pack_nodes(plain_message, sizeof(plain_message), &receiver, 1) == -1) {
+ return false;
+ }
uint64_t ping_id = 0;
- if (sendback_node != nullptr) {
- memcpy(plain_message + sizeof(receiver), sendback_node, sizeof(Node_format));
- ping_id = ping_array_add(dht->dht_harden_ping_array, dht->mono_time, plain_message, sizeof(plain_message));
- } else {
- ping_id = ping_array_add(dht->dht_ping_array, dht->mono_time, plain_message, sizeof(receiver));
- }
+ ping_id = ping_array_add(dht->dht_ping_array, dht->mono_time, plain_message, sizeof(receiver));
if (ping_id == 0) {
- return -1;
+ return false;
}
uint8_t plain[CRYPTO_PUBLIC_KEY_SIZE + sizeof(ping_id)];
@@ -1335,15 +1305,21 @@ static int getnodes(DHT *dht, IP_Port ip_port, const uint8_t *public_key, const
const int len = dht_create_packet(dht->self_public_key, shared_key, NET_PACKET_GET_NODES,
plain, sizeof(plain), data);
+ crypto_memzero(shared_key, sizeof(shared_key));
+
if (len != sizeof(data)) {
- return -1;
+ return false;
}
- return sendpacket(dht->net, ip_port, data, len);
+ if (sendpacket(dht->net, ip_port, data, len) > 0) {
+ return true;
+ }
+
+ return false;
}
-/* Send a send nodes response: message for IPv6 nodes */
-static int sendnodes_ipv6(const DHT *dht, IP_Port ip_port, const uint8_t *public_key, const uint8_t *client_id,
+/** Send a send nodes response: message for IPv6 nodes */
+static int sendnodes_ipv6(const DHT *dht, const IP_Port *ip_port, const uint8_t *public_key, const uint8_t *client_id,
const uint8_t *sendback_data, uint16_t length, const uint8_t *shared_encryption_key)
{
/* Check if packet is going to be sent to ourself. */
@@ -1359,7 +1335,7 @@ static int sendnodes_ipv6(const DHT *dht, IP_Port ip_port, const uint8_t *public
Node_format nodes_list[MAX_SENT_NODES];
const uint32_t num_nodes =
- get_close_nodes(dht, client_id, nodes_list, net_family_unspec, ip_is_lan(ip_port.ip), 1);
+ get_close_nodes(dht, client_id, nodes_list, net_family_unspec, ip_is_lan(&ip_port->ip));
VLA(uint8_t, plain, 1 + node_format_size * MAX_SENT_NODES + length);
@@ -1391,7 +1367,7 @@ static int sendnodes_ipv6(const DHT *dht, IP_Port ip_port, const uint8_t *public
#define CRYPTO_NODE_SIZE (CRYPTO_PUBLIC_KEY_SIZE + sizeof(uint64_t))
-static int handle_getnodes(void *object, IP_Port source, const uint8_t *packet, uint16_t length, void *userdata)
+static int handle_getnodes(void *object, const IP_Port *source, const uint8_t *packet, uint16_t length, void *userdata)
{
if (length != (CRYPTO_SIZE + CRYPTO_MAC_SIZE + sizeof(uint64_t))) {
return true;
@@ -1416,6 +1392,7 @@ static int handle_getnodes(void *object, IP_Port source, const uint8_t *packet,
plain);
if (len != CRYPTO_NODE_SIZE) {
+ crypto_memzero(shared_key, sizeof(shared_key));
return true;
}
@@ -1423,39 +1400,34 @@ static int handle_getnodes(void *object, IP_Port source, const uint8_t *packet,
ping_add(dht->ping, packet + 1, source);
+ crypto_memzero(shared_key, sizeof(shared_key));
+
return false;
}
-/* return false if no
- * return true if yes */
-static bool sent_getnode_to_node(DHT *dht, const uint8_t *public_key, IP_Port node_ip_port, uint64_t ping_id,
- Node_format *sendback_node)
+/** Return true if we sent a getnode packet to the peer associated with the supplied info. */
+static bool sent_getnode_to_node(DHT *dht, const uint8_t *public_key, const IP_Port *node_ip_port, uint64_t ping_id)
{
uint8_t data[sizeof(Node_format) * 2];
- if (ping_array_check(dht->dht_ping_array, dht->mono_time, data, sizeof(data), ping_id) == sizeof(Node_format)) {
- memset(sendback_node, 0, sizeof(Node_format));
- } else if (ping_array_check(dht->dht_harden_ping_array, dht->mono_time, data, sizeof(data), ping_id) == sizeof(data)) {
- memcpy(sendback_node, data + sizeof(Node_format), sizeof(Node_format));
- } else {
+ if (ping_array_check(dht->dht_ping_array, dht->mono_time, data, sizeof(data), ping_id) != sizeof(Node_format)) {
return false;
}
Node_format test;
- memcpy(&test, data, sizeof(Node_format));
- if (!ipport_equal(&test.ip_port, &node_ip_port) || !id_equal(test.public_key, public_key)) {
+ if (unpack_nodes(&test, 1, nullptr, data, sizeof(data), false) != 1) {
+ return false;
+ }
+
+ if (!ipport_equal(&test.ip_port, node_ip_port) || !id_equal(test.public_key, public_key)) {
return false;
}
return true;
}
-/* Function is needed in following functions. */
-static int send_hardening_getnode_res(const DHT *dht, const Node_format *sendto, const uint8_t *queried_client_id,
- const uint8_t *nodes_data, uint16_t nodes_data_length);
-
-static int handle_sendnodes_core(void *object, IP_Port source, const uint8_t *packet, uint16_t length,
+static int handle_sendnodes_core(void *object, const IP_Port *source, const uint8_t *packet, uint16_t length,
Node_format *plain_nodes, uint16_t size_plain_nodes, uint32_t *num_nodes_out)
{
DHT *const dht = (DHT *)object;
@@ -1485,6 +1457,8 @@ static int handle_sendnodes_core(void *object, IP_Port source, const uint8_t *pa
1 + data_size + sizeof(uint64_t) + CRYPTO_MAC_SIZE,
plain);
+ crypto_memzero(shared_key, sizeof(shared_key));
+
if ((unsigned int)len != SIZEOF_VLA(plain)) {
return 1;
}
@@ -1493,12 +1467,10 @@ static int handle_sendnodes_core(void *object, IP_Port source, const uint8_t *pa
return 1;
}
- Node_format sendback_node;
-
uint64_t ping_id;
memcpy(&ping_id, plain + 1 + data_size, sizeof(ping_id));
- if (!sent_getnode_to_node(dht, packet + 1, source, ping_id, &sendback_node)) {
+ if (!sent_getnode_to_node(dht, packet + 1, source, ping_id)) {
return 1;
}
@@ -1522,11 +1494,11 @@ static int handle_sendnodes_core(void *object, IP_Port source, const uint8_t *pa
*num_nodes_out = num_nodes;
- send_hardening_getnode_res(dht, &sendback_node, packet + 1, plain + 1, data_size);
return 0;
}
-static int handle_sendnodes_ipv6(void *object, IP_Port source, const uint8_t *packet, uint16_t length, void *userdata)
+static int handle_sendnodes_ipv6(void *object, const IP_Port *source, const uint8_t *packet, uint16_t length,
+ void *userdata)
{
DHT *const dht = (DHT *)object;
Node_format plain_nodes[MAX_SENT_NODES];
@@ -1542,8 +1514,8 @@ static int handle_sendnodes_ipv6(void *object, IP_Port source, const uint8_t *pa
for (uint32_t i = 0; i < num_nodes; ++i) {
if (ipport_isset(&plain_nodes[i].ip_port)) {
- ping_node_from_getnodes_ok(dht, plain_nodes[i].public_key, plain_nodes[i].ip_port);
- returnedip_ports(dht, plain_nodes[i].ip_port, plain_nodes[i].public_key, packet + 1);
+ ping_node_from_getnodes_ok(dht, plain_nodes[i].public_key, &plain_nodes[i].ip_port);
+ returnedip_ports(dht, &plain_nodes[i].ip_port, plain_nodes[i].public_key, packet + 1);
}
}
@@ -1553,13 +1525,25 @@ static int handle_sendnodes_ipv6(void *object, IP_Port source, const uint8_t *pa
/*----------------------------------------------------------------------------------*/
/*------------------------END of packet handling functions--------------------------*/
+static void dht_friend_lock(DHT_Friend *const dht_friend, dht_ip_cb *ip_callback,
+ void *data, int32_t number, uint16_t *lock_count)
+{
+ const uint16_t lock_num = dht_friend->lock_count;
+ ++dht_friend->lock_count;
+ dht_friend->callbacks[lock_num].ip_callback = ip_callback;
+ dht_friend->callbacks[lock_num].data = data;
+ dht_friend->callbacks[lock_num].number = number;
+
+ if (lock_count) {
+ *lock_count = lock_num + 1;
+ }
+}
+
int dht_addfriend(DHT *dht, const uint8_t *public_key, dht_ip_cb *ip_callback,
void *data, int32_t number, uint16_t *lock_count)
{
const uint32_t friend_num = index_of_friend_pk(dht->friends_list, dht->num_friends, public_key);
- uint16_t lock_num;
-
if (friend_num != UINT32_MAX) { /* Is friend already in DHT? */
DHT_Friend *const dht_friend = &dht->friends_list[friend_num];
@@ -1567,15 +1551,7 @@ int dht_addfriend(DHT *dht, const uint8_t *public_key, dht_ip_cb *ip_callback,
return -1;
}
- lock_num = dht_friend->lock_count;
- ++dht_friend->lock_count;
- dht_friend->callbacks[lock_num].ip_callback = ip_callback;
- dht_friend->callbacks[lock_num].data = data;
- dht_friend->callbacks[lock_num].number = number;
-
- if (lock_count) {
- *lock_count = lock_num + 1;
- }
+ dht_friend_lock(dht_friend, ip_callback, data, number, lock_count);
return 0;
}
@@ -1594,18 +1570,10 @@ int dht_addfriend(DHT *dht, const uint8_t *public_key, dht_ip_cb *ip_callback,
dht_friend->nat.nat_ping_id = random_u64();
++dht->num_friends;
- lock_num = dht_friend->lock_count;
- ++dht_friend->lock_count;
- dht_friend->callbacks[lock_num].ip_callback = ip_callback;
- dht_friend->callbacks[lock_num].data = data;
- dht_friend->callbacks[lock_num].number = number;
-
- if (lock_count) {
- *lock_count = lock_num + 1;
- }
+ dht_friend_lock(dht_friend, ip_callback, data, number, lock_count);
dht_friend->num_to_bootstrap = get_close_nodes(dht, dht_friend->public_key, dht_friend->to_bootstrap, net_family_unspec,
- 1, 0);
+ 1);
return 0;
}
@@ -1632,9 +1600,7 @@ int dht_delfriend(DHT *dht, const uint8_t *public_key, uint16_t lock_count)
--dht->num_friends;
if (dht->num_friends != friend_num) {
- memcpy(&dht->friends_list[friend_num],
- &dht->friends_list[dht->num_friends],
- sizeof(DHT_Friend));
+ dht->friends_list[friend_num] = dht->friends_list[dht->num_friends];
}
if (dht->num_friends == 0) {
@@ -1643,7 +1609,7 @@ int dht_delfriend(DHT *dht, const uint8_t *public_key, uint16_t lock_count)
return 0;
}
- DHT_Friend *const temp = (DHT_Friend *)realloc(dht->friends_list, sizeof(DHT_Friend) * (dht->num_friends));
+ DHT_Friend *const temp = (DHT_Friend *)realloc(dht->friends_list, sizeof(DHT_Friend) * dht->num_friends);
if (temp == nullptr) {
return -1;
@@ -1665,7 +1631,7 @@ int dht_getfriendip(const DHT *dht, const uint8_t *public_key, IP_Port *ip_port)
return -1;
}
- DHT_Friend *const frnd = &dht->friends_list[friend_index];
+ const DHT_Friend *const frnd = &dht->friends_list[friend_index];
const uint32_t client_index = index_of_client_pk(frnd->client_list, MAX_FRIEND_CLIENTS, public_key);
if (client_index == -1) {
@@ -1678,7 +1644,7 @@ int dht_getfriendip(const DHT *dht, const uint8_t *public_key, IP_Port *ip_port)
for (const IPPTsPng * const *it = assocs; *it; ++it) {
const IPPTsPng *const assoc = *it;
- if (!assoc_timeout(dht->last_run, assoc)) {
+ if (!assoc_timeout(dht->cur_time, assoc)) {
*ip_port = assoc->ip_port;
return 1;
}
@@ -1687,7 +1653,7 @@ int dht_getfriendip(const DHT *dht, const uint8_t *public_key, IP_Port *ip_port)
return -1;
}
-/* returns number of nodes not in kill-timeout */
+/** returns number of nodes not in kill-timeout */
static uint8_t do_ping_and_sendnode_requests(DHT *dht, uint64_t *lastgetnode, const uint8_t *public_key,
Client_data *list, uint32_t list_count, uint32_t *bootstrap_times, bool sortable)
{
@@ -1714,12 +1680,12 @@ static uint8_t do_ping_and_sendnode_requests(DHT *dht, uint64_t *lastgetnode, co
++not_kill;
if (mono_time_is_timeout(dht->mono_time, assoc->last_pinged, PING_INTERVAL)) {
- getnodes(dht, assoc->ip_port, client->public_key, public_key, nullptr);
+ dht_getnodes(dht, &assoc->ip_port, client->public_key, public_key);
assoc->last_pinged = temp_time;
}
/* If node is good. */
- if (!assoc_timeout(dht->last_run, assoc)) {
+ if (!assoc_timeout(dht->cur_time, assoc)) {
client_list[num_nodes] = client;
assoc_list[num_nodes] = assoc;
++num_nodes;
@@ -1736,18 +1702,18 @@ static uint8_t do_ping_and_sendnode_requests(DHT *dht, uint64_t *lastgetnode, co
}
if (sortable && sort_ok) {
- sort_client_list(list, dht->last_run, list_count, public_key);
+ sort_client_list(list, dht->cur_time, list_count, public_key);
}
if ((num_nodes != 0) && (mono_time_is_timeout(dht->mono_time, *lastgetnode, GET_NODE_INTERVAL)
|| *bootstrap_times < MAX_BOOTSTRAP_TIMES)) {
- uint32_t rand_node = random_u32() % num_nodes;
+ uint32_t rand_node = random_range_u32(num_nodes);
if ((num_nodes - 1) != rand_node) {
- rand_node += random_u32() % (num_nodes - (rand_node + 1));
+ rand_node += random_range_u32(num_nodes - (rand_node + 1));
}
- getnodes(dht, assoc_list[rand_node]->ip_port, client_list[rand_node]->public_key, public_key, nullptr);
+ dht_getnodes(dht, &assoc_list[rand_node]->ip_port, client_list[rand_node]->public_key, public_key);
*lastgetnode = temp_time;
++*bootstrap_times;
@@ -1756,7 +1722,7 @@ static uint8_t do_ping_and_sendnode_requests(DHT *dht, uint64_t *lastgetnode, co
return not_kill;
}
-/* Ping each client in the "friends" list every PING_INTERVAL seconds. Send a get nodes request
+/** Ping each client in the "friends" list every PING_INTERVAL seconds. Send a get nodes request
* every GET_NODE_INTERVAL seconds to a random good node for each "friend" in our "friends" list.
*/
static void do_dht_friends(DHT *dht)
@@ -1765,8 +1731,7 @@ static void do_dht_friends(DHT *dht)
DHT_Friend *const dht_friend = &dht->friends_list[i];
for (size_t j = 0; j < dht_friend->num_to_bootstrap; ++j) {
- getnodes(dht, dht_friend->to_bootstrap[j].ip_port, dht_friend->to_bootstrap[j].public_key, dht_friend->public_key,
- nullptr);
+ dht_getnodes(dht, &dht_friend->to_bootstrap[j].ip_port, dht_friend->to_bootstrap[j].public_key, dht_friend->public_key);
}
dht_friend->num_to_bootstrap = 0;
@@ -1777,13 +1742,13 @@ static void do_dht_friends(DHT *dht)
}
}
-/* Ping each client in the close nodes list every PING_INTERVAL seconds.
+/** Ping each client in the close nodes list every PING_INTERVAL seconds.
* Send a get nodes request every GET_NODE_INTERVAL seconds to a random good node in the list.
*/
static void do_Close(DHT *dht)
{
for (size_t i = 0; i < dht->num_to_bootstrap; ++i) {
- getnodes(dht, dht->to_bootstrap[i].ip_port, dht->to_bootstrap[i].public_key, dht->self_public_key, nullptr);
+ dht_getnodes(dht, &dht->to_bootstrap[i].ip_port, dht->to_bootstrap[i].public_key, dht->self_public_key);
}
dht->num_to_bootstrap = 0;
@@ -1819,15 +1784,11 @@ static void do_Close(DHT *dht)
}
}
-void dht_getnodes(DHT *dht, const IP_Port *from_ipp, const uint8_t *from_id, const uint8_t *which_id)
+void dht_bootstrap(DHT *dht, const IP_Port *ip_port, const uint8_t *public_key)
{
- getnodes(dht, *from_ipp, from_id, which_id, nullptr);
+ dht_getnodes(dht, ip_port, public_key, dht->self_public_key);
}
-void dht_bootstrap(DHT *dht, IP_Port ip_port, const uint8_t *public_key)
-{
- getnodes(dht, ip_port, public_key, dht->self_public_key, nullptr);
-}
int dht_bootstrap_from_address(DHT *dht, const char *address, uint8_t ipv6enabled,
uint16_t port, const uint8_t *public_key)
{
@@ -1845,11 +1806,11 @@ int dht_bootstrap_from_address(DHT *dht, const char *address, uint8_t ipv6enable
if (addr_resolve_or_parse_ip(address, &ip_port_v64.ip, ip_extra)) {
ip_port_v64.port = port;
- dht_bootstrap(dht, ip_port_v64, public_key);
+ dht_bootstrap(dht, &ip_port_v64, public_key);
if ((ip_extra != nullptr) && ip_isset(ip_extra)) {
ip_port_v4.port = port;
- dht_bootstrap(dht, ip_port_v4, public_key);
+ dht_bootstrap(dht, &ip_port_v4, public_key);
}
return 1;
@@ -1858,7 +1819,7 @@ int dht_bootstrap_from_address(DHT *dht, const char *address, uint8_t ipv6enable
return 0;
}
-/* Send the given packet to node with public_key
+/** Send the given packet to node with public_key.
*
* return -1 if failure.
*/
@@ -1873,7 +1834,7 @@ int route_packet(const DHT *dht, const uint8_t *public_key, const uint8_t *packe
const IPPTsPng *const assoc = *it;
if (ip_isset(&assoc->ip_port.ip)) {
- return sendpacket(dht->net, assoc->ip_port, packet, length);
+ return sendpacket(dht->net, &assoc->ip_port, packet, length);
}
}
@@ -1884,7 +1845,7 @@ int route_packet(const DHT *dht, const uint8_t *public_key, const uint8_t *packe
return -1;
}
-/* Puts all the different ips returned by the nodes for a friend_num into array ip_portlist.
+/** Puts all the different ips returned by the nodes for a friend_num into array ip_portlist.
* ip_portlist must be at least MAX_FRIEND_CLIENTS big.
*
* return the number of ips returned.
@@ -1920,8 +1881,8 @@ static int friend_iplist(const DHT *dht, IP_Port *ip_portlist, uint16_t friend_n
}
if (id_equal(client->public_key, dht_friend->public_key)) {
- if (!assoc_timeout(dht->last_run, &client->assoc6)
- || !assoc_timeout(dht->last_run, &client->assoc4)) {
+ if (!assoc_timeout(dht->cur_time, &client->assoc6)
+ || !assoc_timeout(dht->cur_time, &client->assoc4)) {
return 0; /* direct connectivity */
}
}
@@ -1960,12 +1921,83 @@ static int friend_iplist(const DHT *dht, IP_Port *ip_portlist, uint16_t friend_n
}
-/* Send the following packet to everyone who tells us they are connected to friend_id.
+/**
+ * Callback invoked for each IP/port of each client of a friend.
+ *
+ * For each client, the callback is invoked twice: once for IPv4 and once for
+ * IPv6. If the callback returns `false` after the IPv4 invocation, it will not
+ * be invoked for IPv6.
+ *
+ * @param dht The main DHT instance.
+ * @param ip_port The currently processed IP/port.
+ * @param n A pointer to the number that will be returned from `foreach_ip_port`.
+ * @param userdata The `userdata` pointer passed to `foreach_ip_port`.
+ */
+typedef bool foreach_ip_port_cb(const DHT *dht, const IP_Port *ip_port, uint32_t *n, void *userdata);
+
+/**
+ * Runs a callback on every active connection for a given DHT friend.
+ *
+ * This iterates over the client list of a DHT friend and invokes a callback for
+ * every non-zero IP/port (IPv4 and IPv6) that's not timed out.
+ *
+ * @param dht The main DHT instance, passed to the callback.
+ * @param dht_friend The friend over whose connections we should iterate.
+ * @param callback The callback to invoke for each IP/port.
+ * @param userdata Extra pointer passed to the callback.
+ */
+static uint32_t foreach_ip_port(const DHT *dht, const DHT_Friend *dht_friend,
+ foreach_ip_port_cb *callback, void *userdata)
+{
+ uint32_t n = 0;
+
+ /* extra legwork, because having the outside allocating the space for us
+ * is *usually* good(tm) (bites us in the behind in this case though) */
+ for (uint32_t i = 0; i < MAX_FRIEND_CLIENTS; ++i) {
+ const Client_data *const client = &dht_friend->client_list[i];
+ const IPPTsPng *const assocs[] = { &client->assoc4, &client->assoc6, nullptr };
+
+ for (const IPPTsPng * const *it = assocs; *it != nullptr; ++it) {
+ const IPPTsPng *const assoc = *it;
+
+ /* If ip is not zero and node is good. */
+ if (!ip_isset(&assoc->ret_ip_port.ip)
+ && !mono_time_is_timeout(dht->mono_time, assoc->ret_timestamp, BAD_NODE_TIMEOUT)) {
+ continue;
+ }
+
+ if (!callback(dht, &assoc->ip_port, &n, userdata)) {
+ /* If the callback is happy with just one of the assocs, we
+ * don't give it the second one. */
+ break;
+ }
+ }
+ }
+
+ return n;
+}
+
+static bool send_packet_to_friend(const DHT *dht, const IP_Port *ip_port, uint32_t *n, void *userdata)
+{
+ const Packet *packet = (const Packet *)userdata;
+ const int retval = send_packet(dht->net, ip_port, *packet);
+
+ if ((uint32_t)retval == packet->length) {
+ ++*n;
+ /* Send one packet per friend: stop the foreach on the first success. */
+ return false;
+ }
+
+ return true;
+}
+
+/**
+ * Send the following packet to everyone who tells us they are connected to friend_id.
*
* return ip for friend.
* return number of nodes the packet was sent to. (Only works if more than (MAX_FRIEND_CLIENTS / 4).
*/
-int route_tofriend(const DHT *dht, const uint8_t *friend_id, const uint8_t *packet, uint16_t length)
+uint32_t route_to_friend(const DHT *dht, const uint8_t *friend_id, const Packet *packet)
{
const uint32_t num = index_of_friend_pk(dht->friends_list, dht->num_friends, friend_id);
@@ -1973,47 +2005,33 @@ int route_tofriend(const DHT *dht, const uint8_t *friend_id, const uint8_t *pack
return 0;
}
- uint32_t sent = 0;
IP_Port ip_list[MAX_FRIEND_CLIENTS];
const int ip_num = friend_iplist(dht, ip_list, num);
- if (ip_num < (MAX_FRIEND_CLIENTS / 4)) {
+ if (ip_num < MAX_FRIEND_CLIENTS / 4) {
return 0; /* Reason for that? */
}
const DHT_Friend *const dht_friend = &dht->friends_list[num];
+ Packet packet_userdata = *packet; // Copy because it needs to be non-const.
- /* extra legwork, because having the outside allocating the space for us
- * is *usually* good(tm) (bites us in the behind in this case though) */
-
- for (uint32_t i = 0; i < MAX_FRIEND_CLIENTS; ++i) {
- const Client_data *const client = &dht_friend->client_list[i];
- const IPPTsPng *const assocs[] = { &client->assoc4, &client->assoc6, nullptr };
-
- for (const IPPTsPng * const *it = assocs; *it; ++it) {
- const IPPTsPng *const assoc = *it;
-
- /* If ip is not zero and node is good. */
- if (ip_isset(&assoc->ret_ip_port.ip) && !mono_time_is_timeout(dht->mono_time, assoc->ret_timestamp, BAD_NODE_TIMEOUT)) {
- const int retval = sendpacket(dht->net, assoc->ip_port, packet, length);
-
- if ((unsigned int)retval == length) {
- ++sent;
- break; /* Send one packet per client.*/
- }
- }
- }
- }
+ return foreach_ip_port(dht, dht_friend, send_packet_to_friend, &packet_userdata);
+}
- return sent;
+static bool get_ip_port(const DHT *dht, const IP_Port *ip_port, uint32_t *n, void *userdata)
+{
+ IP_Port *ip_list = (IP_Port *)userdata;
+ ip_list[*n] = *ip_port;
+ ++*n;
+ return true;
}
-/* Send the following packet to one random person who tells us they are connected to friend_id.
+/** Send the following packet to one random person who tells us they are connected to friend_id.
*
* return number of nodes the packet was sent to.
*/
-static int routeone_tofriend(DHT *dht, const uint8_t *friend_id, const uint8_t *packet, uint16_t length)
+static uint32_t routeone_to_friend(const DHT *dht, const uint8_t *friend_id, const Packet *packet)
{
const uint32_t num = index_of_friend_pk(dht->friends_list, dht->num_friends, friend_id);
@@ -2024,33 +2042,17 @@ static int routeone_tofriend(DHT *dht, const uint8_t *friend_id, const uint8_t *
const DHT_Friend *const dht_friend = &dht->friends_list[num];
IP_Port ip_list[MAX_FRIEND_CLIENTS * 2];
- int n = 0;
- /* extra legwork, because having the outside allocating the space for us
- * is *usually* good(tm) (bites us in the behind in this case though) */
-
- for (uint32_t i = 0; i < MAX_FRIEND_CLIENTS; ++i) {
- const Client_data *const client = &dht_friend->client_list[i];
- const IPPTsPng *const assocs[] = { &client->assoc4, &client->assoc6, nullptr };
-
- for (const IPPTsPng * const *it = assocs; *it; ++it) {
- const IPPTsPng *const assoc = *it;
-
- /* If ip is not zero and node is good. */
- if (ip_isset(&assoc->ret_ip_port.ip) && !mono_time_is_timeout(dht->mono_time, assoc->ret_timestamp, BAD_NODE_TIMEOUT)) {
- ip_list[n] = assoc->ip_port;
- ++n;
- }
- }
- }
+ const int n = foreach_ip_port(dht, dht_friend, get_ip_port, ip_list);
if (n < 1) {
return 0;
}
- const int retval = sendpacket(dht->net, ip_list[random_u32() % n], packet, length);
+ const uint32_t rand_idx = random_range_u32(n);
+ const int retval = send_packet(dht->net, &ip_list[rand_idx], *packet);
- if ((unsigned int)retval == length) {
+ if ((unsigned int)retval == packet->length) {
return 1;
}
@@ -2060,28 +2062,30 @@ static int routeone_tofriend(DHT *dht, const uint8_t *friend_id, const uint8_t *
/*----------------------------------------------------------------------------------*/
/*---------------------BEGINNING OF NAT PUNCHING FUNCTIONS--------------------------*/
-static int send_NATping(DHT *dht, const uint8_t *public_key, uint64_t ping_id, uint8_t type)
+static int send_NATping(const DHT *dht, const uint8_t *public_key, uint64_t ping_id, uint8_t type)
{
uint8_t data[sizeof(uint64_t) + 1];
- uint8_t packet[MAX_CRYPTO_REQUEST_SIZE];
-
- int num = 0;
+ uint8_t packet_data[MAX_CRYPTO_REQUEST_SIZE];
data[0] = type;
memcpy(data + 1, &ping_id, sizeof(uint64_t));
/* 254 is NAT ping request packet id */
const int len = create_request(
- dht->self_public_key, dht->self_secret_key, packet, public_key, data,
+ dht->self_public_key, dht->self_secret_key, packet_data, public_key, data,
sizeof(uint64_t) + 1, CRYPTO_PACKET_NAT_PING);
if (len == -1) {
return -1;
}
+ assert(len <= UINT16_MAX);
+ uint32_t num = 0;
+ const Packet packet = {packet_data, (uint16_t)len};
+
if (type == 0) { /* If packet is request use many people to route it. */
- num = route_tofriend(dht, public_key, packet, len);
+ num = route_to_friend(dht, public_key, &packet);
} else if (type == 1) { /* If packet is response use only one person to route it */
- num = routeone_tofriend(dht, public_key, packet, len);
+ num = routeone_to_friend(dht, public_key, &packet);
}
if (num == 0) {
@@ -2091,8 +2095,8 @@ static int send_NATping(DHT *dht, const uint8_t *public_key, uint64_t ping_id, u
return num;
}
-/* Handle a received ping request for. */
-static int handle_NATping(void *object, IP_Port source, const uint8_t *source_pubkey, const uint8_t *packet,
+/** Handle a received ping request for. */
+static int handle_NATping(void *object, const IP_Port *source, const uint8_t *source_pubkey, const uint8_t *packet,
uint16_t length, void *userdata)
{
if (length != sizeof(uint64_t) + 1) {
@@ -2129,13 +2133,13 @@ static int handle_NATping(void *object, IP_Port source, const uint8_t *source_pu
return 1;
}
-/* Get the most common ip in the ip_portlist.
+/** Get the most common ip in the ip_portlist.
* Only return ip if it appears in list min_num or more.
* len must not be bigger than MAX_FRIEND_CLIENTS.
*
* return ip of 0 if failure.
*/
-static IP nat_commonip(IP_Port *ip_portlist, uint16_t len, uint16_t min_num)
+static IP nat_commonip(const IP_Port *ip_portlist, uint16_t len, uint16_t min_num)
{
IP zero;
ip_reset(&zero);
@@ -2161,18 +2165,18 @@ static IP nat_commonip(IP_Port *ip_portlist, uint16_t len, uint16_t min_num)
return zero;
}
-/* Return all the ports for one ip in a list.
+/** Return all the ports for one ip in a list.
* portlist must be at least len long,
* where len is the length of ip_portlist.
*
* return number of ports and puts the list of ports in portlist.
*/
-static uint16_t nat_getports(uint16_t *portlist, IP_Port *ip_portlist, uint16_t len, IP ip)
+static uint16_t nat_getports(uint16_t *portlist, const IP_Port *ip_portlist, uint16_t len, const IP *ip)
{
uint16_t num = 0;
for (uint32_t i = 0; i < len; ++i) {
- if (ip_equal(&ip_portlist[i].ip, &ip)) {
+ if (ip_equal(&ip_portlist[i].ip, ip)) {
portlist[num] = net_ntohs(ip_portlist[i].port);
++num;
}
@@ -2181,7 +2185,7 @@ static uint16_t nat_getports(uint16_t *portlist, IP_Port *ip_portlist, uint16_t
return num;
}
-static void punch_holes(DHT *dht, IP ip, uint16_t *port_list, uint16_t numports, uint16_t friend_num)
+static void punch_holes(DHT *dht, const IP *ip, const uint16_t *port_list, uint16_t numports, uint16_t friend_num)
{
if (!dht->hole_punching_enabled) {
return;
@@ -2202,9 +2206,9 @@ static void punch_holes(DHT *dht, IP ip, uint16_t *port_list, uint16_t numports,
if (i == numports) { /* If all ports are the same, only try that one port. */
IP_Port pinging;
- ip_copy(&pinging.ip, &ip);
+ ip_copy(&pinging.ip, ip);
pinging.port = net_htons(first_port);
- ping_send_request(dht->ping, pinging, dht->friends_list[friend_num].public_key);
+ ping_send_request(dht->ping, &pinging, dht->friends_list[friend_num].public_key);
} else {
for (i = 0; i < MAX_PUNCHING_PORTS; ++i) {
/* TODO(irungentoo): Improve port guessing algorithm. */
@@ -2214,9 +2218,9 @@ static void punch_holes(DHT *dht, IP ip, uint16_t *port_list, uint16_t numports,
const uint32_t index = (it / 2) % numports;
const uint16_t port = port_list[index] + delta;
IP_Port pinging;
- ip_copy(&pinging.ip, &ip);
+ ip_copy(&pinging.ip, ip);
pinging.port = net_htons(port);
- ping_send_request(dht->ping, pinging, dht->friends_list[friend_num].public_key);
+ ping_send_request(dht->ping, &pinging, dht->friends_list[friend_num].public_key);
}
dht->friends_list[friend_num].nat.punching_index += i;
@@ -2225,12 +2229,12 @@ static void punch_holes(DHT *dht, IP ip, uint16_t *port_list, uint16_t numports,
if (dht->friends_list[friend_num].nat.tries > MAX_NORMAL_PUNCHING_TRIES) {
const uint16_t port = 1024;
IP_Port pinging;
- ip_copy(&pinging.ip, &ip);
+ ip_copy(&pinging.ip, ip);
for (i = 0; i < MAX_PUNCHING_PORTS; ++i) {
uint32_t it = i + dht->friends_list[friend_num].nat.punching_index2;
pinging.port = net_htons(port + it);
- ping_send_request(dht->ping, pinging, dht->friends_list[friend_num].public_key);
+ ping_send_request(dht->ping, &pinging, dht->friends_list[friend_num].public_key);
}
dht->friends_list[friend_num].nat.punching_index2 += i - (MAX_PUNCHING_PORTS / 2);
@@ -2274,8 +2278,8 @@ static void do_NAT(DHT *dht)
}
uint16_t port_list[MAX_FRIEND_CLIENTS];
- const uint16_t numports = nat_getports(port_list, ip_list, num, ip);
- punch_holes(dht, ip, port_list, numports, i);
+ const uint16_t numports = nat_getports(port_list, ip_list, num, &ip);
+ punch_holes(dht, &ip, port_list, numports, i);
dht->friends_list[i].nat.punching_timestamp = temp_time;
dht->friends_list[i].nat.hole_punching = 0;
@@ -2286,233 +2290,12 @@ static void do_NAT(DHT *dht)
/*----------------------------------------------------------------------------------*/
/*-----------------------END OF NAT PUNCHING FUNCTIONS------------------------------*/
-#define DHT_HARDENING 0
-#define HARDREQ_DATA_SIZE 384 // Attempt to prevent amplification/other attacks
-
-typedef enum Check_Type {
- CHECK_TYPE_ROUTE_REQ = 0,
- CHECK_TYPE_ROUTE_RES = 1,
- CHECK_TYPE_GETNODE_REQ = 2,
- CHECK_TYPE_GETNODE_RES = 3,
- CHECK_TYPE_TEST_REQ = 4,
- CHECK_TYPE_TEST_RES = 5,
-} Check_Type;
-
-#if DHT_HARDENING
-static int send_hardening_req(DHT *dht, Node_format *sendto, uint8_t type, uint8_t *contents, uint16_t length)
-{
- if (length > HARDREQ_DATA_SIZE - 1) {
- return -1;
- }
-
- uint8_t packet[MAX_CRYPTO_REQUEST_SIZE];
- uint8_t data[HARDREQ_DATA_SIZE] = {0};
- data[0] = type;
- memcpy(data + 1, contents, length);
- const int len = create_request(
- dht->self_public_key, dht->self_secret_key, packet, sendto->public_key,
- data, sizeof(data), CRYPTO_PACKET_HARDENING);
-
- if (len == -1) {
- return -1;
- }
-
- return sendpacket(dht->net, sendto->ip_port, packet, len);
-}
-
-/* Send a get node hardening request */
-static int send_hardening_getnode_req(DHT *dht, Node_format *dest, Node_format *node_totest, uint8_t *search_id)
-{
- uint8_t data[sizeof(Node_format) + CRYPTO_PUBLIC_KEY_SIZE];
- memcpy(data, node_totest, sizeof(Node_format));
- memcpy(data + sizeof(Node_format), search_id, CRYPTO_PUBLIC_KEY_SIZE);
- return send_hardening_req(dht, dest, CHECK_TYPE_GETNODE_REQ, data, sizeof(Node_format) + CRYPTO_PUBLIC_KEY_SIZE);
-}
-#endif
-
-/* Send a get node hardening response */
-static int send_hardening_getnode_res(const DHT *dht, const Node_format *sendto, const uint8_t *queried_client_id,
- const uint8_t *nodes_data, uint16_t nodes_data_length)
-{
- if (!ip_isset(&sendto->ip_port.ip)) {
- return -1;
- }
-
- uint8_t packet[MAX_CRYPTO_REQUEST_SIZE];
- VLA(uint8_t, data, 1 + CRYPTO_PUBLIC_KEY_SIZE + nodes_data_length);
- data[0] = CHECK_TYPE_GETNODE_RES;
- memcpy(data + 1, queried_client_id, CRYPTO_PUBLIC_KEY_SIZE);
- memcpy(data + 1 + CRYPTO_PUBLIC_KEY_SIZE, nodes_data, nodes_data_length);
- const int len = create_request(
- dht->self_public_key, dht->self_secret_key, packet, sendto->public_key,
- data, SIZEOF_VLA(data), CRYPTO_PACKET_HARDENING);
-
- if (len == -1) {
- return -1;
- }
-
- return sendpacket(dht->net, sendto->ip_port, packet, len);
-}
-
-/* TODO(irungentoo): improve */
-static IPPTsPng *get_closelist_IPPTsPng(DHT *dht, const uint8_t *public_key, Family sa_family)
-{
- for (uint32_t i = 0; i < LCLIENT_LIST; ++i) {
- if (!id_equal(dht->close_clientlist[i].public_key, public_key)) {
- continue;
- }
-
- if (net_family_is_ipv4(sa_family)) {
- return &dht->close_clientlist[i].assoc4;
- }
-
- if (net_family_is_ipv6(sa_family)) {
- return &dht->close_clientlist[i].assoc6;
- }
- }
-
- return nullptr;
-}
-
-/*
- * check how many nodes in nodes are also present in the closelist.
- * TODO(irungentoo): make this function better.
- */
-static uint32_t have_nodes_closelist(DHT *dht, Node_format *nodes, uint16_t num)
-{
- uint32_t counter = 0;
-
- for (uint32_t i = 0; i < num; ++i) {
- if (id_equal(nodes[i].public_key, dht->self_public_key)) {
- ++counter;
- continue;
- }
-
- const IPPTsPng *const temp = get_closelist_IPPTsPng(dht, nodes[i].public_key, nodes[i].ip_port.ip.family);
-
- if (temp) {
- if (!assoc_timeout(dht->last_run, temp)) {
- ++counter;
- }
- }
- }
-
- return counter;
-}
-
-/* Interval in seconds between hardening checks */
-#define HARDENING_INTERVAL 120
-
-/* Handle a received hardening packet */
-static int handle_hardening(void *object, IP_Port source, const uint8_t *source_pubkey, const uint8_t *packet,
- uint16_t length, void *userdata)
-{
- DHT *const dht = (DHT *)object;
-
- if (length < 2) {
- return 1;
- }
-
- switch (packet[0]) {
- case CHECK_TYPE_GETNODE_REQ: {
- if (length != HARDREQ_DATA_SIZE) {
- return 1;
- }
-
- Node_format node;
- Node_format tocheck_node;
- node.ip_port = source;
- memcpy(node.public_key, source_pubkey, CRYPTO_PUBLIC_KEY_SIZE);
- memcpy(&tocheck_node, packet + 1, sizeof(Node_format));
-
- if (getnodes(dht, tocheck_node.ip_port, tocheck_node.public_key, packet + 1 + sizeof(Node_format), &node) == -1) {
- return 1;
- }
-
- return 0;
- }
-
- case CHECK_TYPE_GETNODE_RES: {
- if (length <= CRYPTO_PUBLIC_KEY_SIZE + 1) {
- return 1;
- }
-
- if (length > 1 + CRYPTO_PUBLIC_KEY_SIZE + sizeof(Node_format) * MAX_SENT_NODES) {
- return 1;
- }
-
- uint16_t length_nodes = length - 1 - CRYPTO_PUBLIC_KEY_SIZE;
- Node_format nodes[MAX_SENT_NODES];
- const int num_nodes = unpack_nodes(nodes, MAX_SENT_NODES, nullptr, packet + 1 + CRYPTO_PUBLIC_KEY_SIZE,
- length_nodes, 0);
-
- /* TODO(irungentoo): MAX_SENT_NODES nodes should be returned at all times
- * (right now we have a small network size so it could cause problems for testing and etc..) */
- if (num_nodes <= 0) {
- return 1;
- }
-
- /* NOTE: This should work for now but should be changed to something better. */
- if (have_nodes_closelist(dht, nodes, num_nodes) < (uint32_t)((num_nodes + 2) / 2)) {
- return 1;
- }
-
- IPPTsPng *const temp = get_closelist_IPPTsPng(dht, packet + 1, nodes[0].ip_port.ip.family);
-
- if (temp == nullptr) {
- return 1;
- }
-
- if (mono_time_is_timeout(dht->mono_time, temp->hardening.send_nodes_timestamp, HARDENING_INTERVAL)) {
- return 1;
- }
-
- if (!id_equal(temp->hardening.send_nodes_pingedid, source_pubkey)) {
- return 1;
- }
-
- /* If Nodes look good and the request checks out */
- temp->hardening.send_nodes_ok = 1;
- return 0;/* success*/
- }
- }
-
- return 1;
-}
-
-#if DHT_HARDENING
-#define HARDEN_TIMEOUT 1200
-
-/* Return a random node from all the nodes we are connected to.
- * TODO(irungentoo): improve this function.
- */
-static Node_format random_node(DHT *dht, Family sa_family)
-{
- uint8_t id[CRYPTO_PUBLIC_KEY_SIZE];
-
- for (uint32_t i = 0; i < CRYPTO_PUBLIC_KEY_SIZE / 4; ++i) { /* populate the id with pseudorandom bytes.*/
- const uint32_t t = random_u32();
- memcpy(id + i * sizeof(t), &t, sizeof(t));
- }
-
- Node_format nodes_list[MAX_SENT_NODES];
- memset(nodes_list, 0, sizeof(nodes_list));
- const uint32_t num_nodes = get_close_nodes(dht, id, nodes_list, sa_family, 1, 0);
-
- if (num_nodes == 0) {
- return nodes_list[0];
- }
-
- return nodes_list[random_u32() % num_nodes];
-}
-#endif
-
-/* Put up to max_num nodes in nodes from the closelist.
+/** Put up to max_num nodes in nodes from the closelist.
*
* return the number of nodes.
*/
-static uint16_t list_nodes(Client_data *list, size_t length, uint64_t cur_time, Node_format *nodes,
- uint16_t max_num)
+static uint16_t list_nodes(const Client_data *list, size_t length, uint64_t cur_time,
+ Node_format *nodes, uint16_t max_num)
{
if (max_num == 0) {
return 0;
@@ -2549,11 +2332,11 @@ static uint16_t list_nodes(Client_data *list, size_t length, uint64_t cur_time,
return count;
}
-/* Put up to max_num nodes in nodes from the random friends.
+/** Put up to max_num nodes in nodes from the random friends.
*
* return the number of nodes.
*/
-uint16_t randfriends_nodes(DHT *dht, Node_format *nodes, uint16_t max_num)
+uint16_t randfriends_nodes(const DHT *dht, Node_format *nodes, uint16_t max_num)
{
if (max_num == 0) {
return 0;
@@ -2563,7 +2346,7 @@ uint16_t randfriends_nodes(DHT *dht, Node_format *nodes, uint16_t max_num)
const uint32_t r = random_u32();
for (size_t i = 0; i < DHT_FAKE_FRIEND_NUMBER; ++i) {
- count += list_nodes(dht->friends_list[(i + r) % DHT_FAKE_FRIEND_NUMBER].client_list, MAX_FRIEND_CLIENTS, dht->last_run,
+ count += list_nodes(dht->friends_list[(i + r) % DHT_FAKE_FRIEND_NUMBER].client_list, MAX_FRIEND_CLIENTS, dht->cur_time,
nodes + count, max_num - count);
if (count >= max_num) {
@@ -2574,68 +2357,15 @@ uint16_t randfriends_nodes(DHT *dht, Node_format *nodes, uint16_t max_num)
return count;
}
-/* Put up to max_num nodes in nodes from the closelist.
+/** Put up to max_num nodes in nodes from the closelist.
*
* return the number of nodes.
*/
-uint16_t closelist_nodes(DHT *dht, Node_format *nodes, uint16_t max_num)
+uint16_t closelist_nodes(const DHT *dht, Node_format *nodes, uint16_t max_num)
{
- return list_nodes(dht->close_clientlist, LCLIENT_LIST, dht->last_run, nodes, max_num);
+ return list_nodes(dht->close_clientlist, LCLIENT_LIST, dht->cur_time, nodes, max_num);
}
-#if DHT_HARDENING
-static void do_hardening(DHT *dht)
-{
- for (uint32_t i = 0; i < LCLIENT_LIST * 2; ++i) {
- IPPTsPng *cur_iptspng;
- Family sa_family;
- const uint8_t *const public_key = dht->close_clientlist[i / 2].public_key;
-
- if (i % 2 == 0) {
- cur_iptspng = &dht->close_clientlist[i / 2].assoc4;
- sa_family = net_family_ipv4;
- } else {
- cur_iptspng = &dht->close_clientlist[i / 2].assoc6;
- sa_family = net_family_ipv6;
- }
-
- if (assoc_timeout(dht->mono_time, cur_iptspng)) {
- continue;
- }
-
- if (cur_iptspng->hardening.send_nodes_ok == 0) {
- if (mono_time_is_timeout(dht->mono_time, cur_iptspng->hardening.send_nodes_timestamp, HARDENING_INTERVAL)) {
- Node_format rand_node = random_node(dht, sa_family);
-
- if (!ipport_isset(&rand_node.ip_port)) {
- continue;
- }
-
- if (id_equal(public_key, rand_node.public_key)) {
- continue;
- }
-
- Node_format to_test;
- to_test.ip_port = cur_iptspng->ip_port;
- memcpy(to_test.public_key, public_key, CRYPTO_PUBLIC_KEY_SIZE);
-
- // TODO(irungentoo): The search id should maybe not be ours?
- if (send_hardening_getnode_req(dht, &rand_node, &to_test, dht->self_public_key) > 0) {
- memcpy(cur_iptspng->hardening.send_nodes_pingedid, rand_node.public_key, CRYPTO_PUBLIC_KEY_SIZE);
- cur_iptspng->hardening.send_nodes_timestamp = mono_time_get(dht->mono_time);
- }
- }
- } else {
- if (mono_time_is_timeout(dht->mono_time, cur_iptspng->hardening.send_nodes_timestamp, HARDEN_TIMEOUT)) {
- cur_iptspng->hardening.send_nodes_ok = 0;
- }
- }
-
- // TODO(irungentoo): add the 2 other testers.
- }
-}
-#endif
-
/*----------------------------------------------------------------------------------*/
void cryptopacket_registerhandler(DHT *dht, uint8_t byte, cryptopacket_handler_cb *cb, void *object)
@@ -2644,7 +2374,8 @@ void cryptopacket_registerhandler(DHT *dht, uint8_t byte, cryptopacket_handler_c
dht->cryptopackethandlers[byte].object = object;
}
-static int cryptopacket_handle(void *object, IP_Port source, const uint8_t *packet, uint16_t length, void *userdata)
+static int cryptopacket_handle(void *object, const IP_Port *source, const uint8_t *packet, uint16_t length,
+ void *userdata)
{
DHT *const dht = (DHT *)object;
@@ -2701,7 +2432,7 @@ DHT *new_dht(const Logger *log, Mono_Time *mono_time, Networking_Core *net, bool
}
dht->mono_time = mono_time;
- dht->last_run = mono_time_get(mono_time);
+ dht->cur_time = mono_time_get(mono_time);
dht->log = log;
dht->net = net;
@@ -2718,14 +2449,12 @@ DHT *new_dht(const Logger *log, Mono_Time *mono_time, Networking_Core *net, bool
networking_registerhandler(dht->net, NET_PACKET_SEND_NODES_IPV6, &handle_sendnodes_ipv6, dht);
networking_registerhandler(dht->net, NET_PACKET_CRYPTO, &cryptopacket_handle, dht);
cryptopacket_registerhandler(dht, CRYPTO_PACKET_NAT_PING, &handle_NATping, dht);
- cryptopacket_registerhandler(dht, CRYPTO_PACKET_HARDENING, &handle_hardening, dht);
crypto_new_keypair(dht->self_public_key, dht->self_secret_key);
dht->dht_ping_array = ping_array_new(DHT_PING_ARRAY_SIZE, PING_TIMEOUT);
- dht->dht_harden_ping_array = ping_array_new(DHT_PING_ARRAY_SIZE, PING_TIMEOUT);
- if (dht->dht_ping_array == nullptr || dht->dht_harden_ping_array == nullptr) {
+ if (dht->dht_ping_array == nullptr) {
kill_dht(dht);
return nullptr;
}
@@ -2749,11 +2478,11 @@ void do_dht(DHT *dht)
{
const uint64_t cur_time = mono_time_get(dht->mono_time);
- if (dht->last_run == cur_time) {
+ if (dht->cur_time == cur_time) {
return;
}
- dht->last_run = cur_time;
+ dht->cur_time = cur_time;
// Load friends/clients if first call to do_dht
if (dht->loaded_num_nodes) {
@@ -2764,9 +2493,6 @@ void do_dht(DHT *dht)
do_dht_friends(dht);
do_NAT(dht);
ping_iterate(dht->ping);
-#if DHT_HARDENING
- do_hardening(dht);
-#endif
}
void kill_dht(DHT *dht)
@@ -2774,12 +2500,13 @@ void kill_dht(DHT *dht)
networking_registerhandler(dht->net, NET_PACKET_GET_NODES, nullptr, nullptr);
networking_registerhandler(dht->net, NET_PACKET_SEND_NODES_IPV6, nullptr, nullptr);
cryptopacket_registerhandler(dht, CRYPTO_PACKET_NAT_PING, nullptr, nullptr);
- cryptopacket_registerhandler(dht, CRYPTO_PACKET_HARDENING, nullptr, nullptr);
ping_array_kill(dht->dht_ping_array);
- ping_array_kill(dht->dht_harden_ping_array);
ping_kill(dht->ping);
free(dht->friends_list);
free(dht->loaded_nodes_list);
+ crypto_memzero(&dht->shared_keys_recv, sizeof(dht->shared_keys_recv));
+ crypto_memzero(&dht->shared_keys_sent, sizeof(dht->shared_keys_sent));
+ crypto_memzero(dht->self_secret_key, sizeof(dht->self_secret_key));
free(dht);
}
@@ -2792,7 +2519,7 @@ void kill_dht(DHT *dht)
#define MAX_SAVED_DHT_NODES (((DHT_FAKE_FRIEND_NUMBER * MAX_FRIEND_CLIENTS) + LCLIENT_LIST) * 2)
-/* Get the size of the DHT (for saving). */
+/** Get the size of the DHT (for saving). */
uint32_t dht_size(const DHT *dht)
{
uint32_t numv4 = 0;
@@ -2823,7 +2550,7 @@ uint32_t dht_size(const DHT *dht)
return size32 + sizesubhead + packed_node_size(net_family_ipv4) * numv4 + packed_node_size(net_family_ipv6) * numv6;
}
-/* Save the DHT in data where data is an array of size dht_size(). */
+/** Save the DHT in data where data is an array of size dht_size(). */
void dht_save(const DHT *dht, uint8_t *data)
{
host_to_lendian_bytes32(data, DHT_STATE_COOKIE_GLOBAL);
@@ -2834,7 +2561,7 @@ void dht_save(const DHT *dht, uint8_t *data)
/* get right offset. we write the actual header later. */
data = state_write_section_header(data, DHT_STATE_COOKIE_TYPE, 0, 0);
- Node_format *clients = (Node_format *)malloc(MAX_SAVED_DHT_NODES * sizeof(Node_format));
+ Node_format *clients = (Node_format *)calloc(MAX_SAVED_DHT_NODES, sizeof(Node_format));
if (clients == nullptr) {
LOGGER_ERROR(dht->log, "could not allocate %u nodes", MAX_SAVED_DHT_NODES);
@@ -2886,10 +2613,14 @@ void dht_save(const DHT *dht, uint8_t *data)
free(clients);
}
-/* Bootstrap from this number of nodes every time dht_connect_after_load() is called */
+/** Bootstrap from this number of nodes every time dht_connect_after_load() is called */
#define SAVE_BOOTSTAP_FREQUENCY 8
-/* Start sending packets after DHT loaded_friends_list and loaded_clients_list are set */
+/** Start sending packets after DHT loaded_friends_list and loaded_clients_list are set.
+ *
+ * returns 0 if successful
+ * returns -1 otherwise
+ */
int dht_connect_after_load(DHT *dht)
{
if (dht == nullptr) {
@@ -2910,7 +2641,7 @@ int dht_connect_after_load(DHT *dht)
for (uint32_t i = 0; i < dht->loaded_num_nodes && i < SAVE_BOOTSTAP_FREQUENCY; ++i) {
const unsigned int index = dht->loaded_nodes_index % dht->loaded_num_nodes;
- dht_bootstrap(dht, dht->loaded_nodes_list[index].ip_port, dht->loaded_nodes_list[index].public_key);
+ dht_bootstrap(dht, &dht->loaded_nodes_list[index].ip_port, dht->loaded_nodes_list[index].public_key);
++dht->loaded_nodes_index;
}
@@ -2948,16 +2679,17 @@ static State_Load_Status dht_load_state_callback(void *outer, const uint8_t *dat
break;
}
- default:
+ default: {
LOGGER_ERROR(dht->log, "Load state (DHT): contains unrecognized part (len %u, type %u)",
length, type);
break;
+ }
}
return STATE_LOAD_STATUS_CONTINUE;
}
-/* Load the DHT from data of size size.
+/** Load the DHT from data of size size.
*
* return -1 if failure.
* return 0 if success.
@@ -2979,7 +2711,7 @@ int dht_load(DHT *dht, const uint8_t *data, uint32_t length)
return -1;
}
-/* return false if we are not connected to the DHT.
+/** return false if we are not connected to the DHT.
* return true if we are.
*/
bool dht_isconnected(const DHT *dht)
@@ -2987,8 +2719,8 @@ bool dht_isconnected(const DHT *dht)
for (uint32_t i = 0; i < LCLIENT_LIST; ++i) {
const Client_data *const client = &dht->close_clientlist[i];
- if (!assoc_timeout(dht->last_run, &client->assoc4) ||
- !assoc_timeout(dht->last_run, &client->assoc6)) {
+ if (!assoc_timeout(dht->cur_time, &client->assoc4) ||
+ !assoc_timeout(dht->cur_time, &client->assoc6)) {
return true;
}
}
@@ -2996,7 +2728,7 @@ bool dht_isconnected(const DHT *dht)
return false;
}
-/* return false if we are not connected or only connected to lan peers with the DHT.
+/** return false if we are not connected or only connected to lan peers with the DHT.
* return true if we are.
*/
bool dht_non_lan_connected(const DHT *dht)
@@ -3004,16 +2736,66 @@ bool dht_non_lan_connected(const DHT *dht)
for (uint32_t i = 0; i < LCLIENT_LIST; ++i) {
const Client_data *const client = &dht->close_clientlist[i];
- if (!assoc_timeout(dht->last_run, &client->assoc4)
- && !ip_is_lan(client->assoc4.ip_port.ip)) {
+ if (!assoc_timeout(dht->cur_time, &client->assoc4)
+ && !ip_is_lan(&client->assoc4.ip_port.ip)) {
return true;
}
- if (!assoc_timeout(dht->last_run, &client->assoc6)
- && !ip_is_lan(client->assoc6.ip_port.ip)) {
+ if (!assoc_timeout(dht->cur_time, &client->assoc6)
+ && !ip_is_lan(&client->assoc6.ip_port.ip)) {
return true;
}
}
return false;
}
+
+/** Copies our own ip_port structure to `dest`. WAN addresses take priority over LAN addresses.
+ *
+ * This function will zero the `dest` buffer before use.
+ *
+ * Return 0 if our ip port can't be found (this usually means we're not connected to the DHT).
+ * Return 1 if IP is a WAN address.
+ * Return 2 if IP is a LAN address.
+ */
+unsigned int ipport_self_copy(const DHT *dht, IP_Port *dest)
+{
+ ipport_reset(dest);
+
+ bool is_lan = false;
+
+ for (uint32_t i = 0; i < LCLIENT_LIST; ++i) {
+ const Client_data *client = dht_get_close_client(dht, i);
+ const IP_Port *ip_port4 = &client->assoc4.ret_ip_port;
+
+ if (client->assoc4.ret_ip_self && ipport_isset(ip_port4)) {
+ ipport_copy(dest, ip_port4);
+ is_lan = ip_is_lan(&dest->ip);
+
+ if (!is_lan) {
+ break;
+ }
+ }
+
+ const IP_Port *ip_port6 = &client->assoc6.ret_ip_port;
+
+ if (client->assoc6.ret_ip_self && ipport_isset(ip_port6)) {
+ ipport_copy(dest, ip_port6);
+ is_lan = ip_is_lan(&dest->ip);
+
+ if (!is_lan) {
+ break;
+ }
+ }
+ }
+
+ if (!ipport_isset(dest)) {
+ return 0;
+ }
+
+ if (is_lan) {
+ return 2;
+ }
+
+ return 1;
+}