Skip to content

Commit

Permalink
DHT improvements part 1.
Browse files Browse the repository at this point in the history
  • Loading branch information
irungentoo committed Jan 5, 2016
1 parent dedf863 commit 760f20c
Show file tree
Hide file tree
Showing 3 changed files with 125 additions and 113 deletions.
212 changes: 105 additions & 107 deletions toxcore/DHT.c
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,11 @@
/* Number of get node requests to send to quickly find close nodes. */
#define MAX_BOOTSTRAP_TIMES 5

static uint8_t calc_dist(uint8_t a, uint8_t b)
{
return a ^ b;
}

/* Compares pk1 and pk2 with pk.
*
* return 0 if both are same distance.
Expand All @@ -79,43 +84,38 @@ int id_closest(const uint8_t *pk, const uint8_t *pk1, const uint8_t *pk2)

for (i = 0; i < crypto_box_PUBLICKEYBYTES; ++i) {

distance1 = pk[i] ^ pk1[i];
distance2 = pk[i] ^ pk2[i];
distance1 = calc_dist(pk[i], pk1[i]);
distance2 = calc_dist(pk[i], pk2[i]);

if (!i) {
if (distance1 & (1 << 7)) {
d1_abs = 1;
}
if (distance1 < distance2)
return 1;

if (distance2 & (1 << 7)) {
d2_abs = 1;
}
}
if (distance1 > distance2)
return 2;
}

if (d1_abs)
distance1 = ~distance1;
return 0;
}

if (d2_abs)
distance2 = ~distance2;
/* Return index of first unequal bit number.
*/
static unsigned int bit_by_bit_cmp(const uint8_t *pk1, const uint8_t *pk2)
{
unsigned int i, j = 0;

if (i == (crypto_box_PUBLICKEYBYTES - 1)) {
if (d1_abs)
if (distance1 != UINT8_MAX)
++distance1;
for (i = 0; i < crypto_box_PUBLICKEYBYTES; ++i) {
if (pk1[i] == pk2[i])
continue;

if (d2_abs)
if (distance2 != UINT8_MAX)
++distance2;
for (j = 0; j < 8; ++j) {
if ((pk1[i] & (1 << (7 - j))) != (pk2[i] & (1 << (7 - j))))
break;
}

if (distance1 < distance2)
return 1;

if (distance1 > distance2)
return 2;
break;
}

return 0;
return i * 8 + j;
}

/* Shared key generations are costly, it is therefor smart to store commonly used
Expand Down Expand Up @@ -586,7 +586,7 @@ static int get_somewhat_close_nodes(const DHT *dht, const uint8_t *public_key, N
{
uint32_t num_nodes = 0, i;
get_close_nodes_inner(public_key, nodes_list, sa_family,
dht->close_clientlist, LCLIENT_LIST, &num_nodes, is_LAN, want_good);
dht->close_clientlist, LCLIENT_LIST, &num_nodes, is_LAN, 0);

/*TODO uncomment this when hardening is added to close friend clients
for (i = 0; i < dht->num_friends; ++i)
Expand Down Expand Up @@ -780,6 +780,68 @@ static int replace_all( Client_data *list,
return 0;
}

/* 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)
{
unsigned int i;

unsigned int index = bit_by_bit_cmp(public_key, dht->self_public_key);

if (index > LCLIENT_LENGTH)
index = LCLIENT_LENGTH - 1;

for (i = 0; i < LCLIENT_NODES; ++i) {
Client_data *client = &dht->close_clientlist[(index * LCLIENT_NODES) + i];

if (is_timeout(client->assoc4.timestamp, BAD_NODE_TIMEOUT) && is_timeout(client->assoc6.timestamp, BAD_NODE_TIMEOUT)) {
if (!simulate) {
IPPTsPng *ipptp_write = NULL;
IPPTsPng *ipptp_clear = NULL;

if (ip_port.ip.family == AF_INET) {
ipptp_write = &client->assoc4;
ipptp_clear = &client->assoc6;
} else {
ipptp_write = &client->assoc6;
ipptp_clear = &client->assoc4;
}

id_copy(client->public_key, public_key);
ipptp_write->ip_port = ip_port;
ipptp_write->timestamp = unix_time();

ip_reset(&ipptp_write->ret_ip_port.ip);
ipptp_write->ret_ip_port.port = 0;
ipptp_write->ret_timestamp = 0;

/* zero out other address */
memset(ipptp_clear, 0, sizeof(*ipptp_clear));
}

return 0;
}
}

return -1;
}

/* 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)
{
if (add_to_close(dht, public_key, ip_port, 1) == 0) {
return 1;
}

return 0;
}

static _Bool is_pk_in_client_list(Client_data *list, unsigned int client_list_length, const uint8_t *public_key,
IP_Port ip_port)
{
Expand Down Expand Up @@ -807,23 +869,18 @@ static unsigned int ping_node_from_getnodes_ok(DHT *dht, const uint8_t *public_k
{
_Bool ret = 0;

if (store_node_ok(&dht->close_clientlist[1], public_key, dht->self_public_key)) {
ret = 1;
}

if (store_node_ok(&dht->close_clientlist[0], public_key, dht->self_public_key)) {
if (add_to_close(dht, public_key, ip_port, 1) == 0) {
ret = 1;
}

if (ret && !client_in_nodelist(dht->to_bootstrap, dht->num_to_bootstrap, public_key)
&& !is_pk_in_client_list(dht->close_clientlist, LCLIENT_LIST, public_key, ip_port)) {
if (dht->num_to_bootstrap < MAX_SENT_NODES) {
if (ret && !client_in_nodelist(dht->to_bootstrap, dht->num_to_bootstrap, public_key)) {
if (dht->num_to_bootstrap < MAX_CLOSE_TO_BOOTSTRAP_NODES) {
memcpy(dht->to_bootstrap[dht->num_to_bootstrap].public_key, public_key, crypto_box_PUBLICKEYBYTES);
dht->to_bootstrap[dht->num_to_bootstrap].ip_port = ip_port;
++dht->num_to_bootstrap;
} else {
//TODO: ipv6 vs v4
add_to_list(dht->to_bootstrap, MAX_SENT_NODES, public_key, ip_port, dht->self_public_key);
add_to_list(dht->to_bootstrap, MAX_CLOSE_TO_BOOTSTRAP_NODES, public_key, ip_port, dht->self_public_key);
}
}

Expand Down Expand Up @@ -878,7 +935,7 @@ int addto_lists(DHT *dht, IP_Port ip_port, const uint8_t *public_key)
* to replace the first ip by the second.
*/
if (!client_or_ip_port_in_list(dht->close_clientlist, LCLIENT_LIST, public_key, ip_port)) {
if (replace_all(dht->close_clientlist, LCLIENT_LIST, public_key, ip_port, dht->self_public_key))
if (add_to_close(dht, public_key, ip_port, 0))
used++;
} else
used++;
Expand Down Expand Up @@ -1391,54 +1448,9 @@ int DHT_getfriendip(const DHT *dht, const uint8_t *public_key, IP_Port *ip_port)
return -1;
}

static void abs_divide_by_2(uint8_t *public_key_dist)
{
unsigned int i;
_Bool one = 0, abs = 0;

if (public_key_dist[0] & (1 << 7)) {
for (i = 0; i < crypto_box_PUBLICKEYBYTES; ++i) {
public_key_dist[i] = ~public_key_dist[i];
}

if (public_key_dist[crypto_box_PUBLICKEYBYTES - 1] != UINT8_MAX)
++public_key_dist[crypto_box_PUBLICKEYBYTES - 1];
}

for (i = 0; i < crypto_box_PUBLICKEYBYTES; ++i) {
_Bool temp = 0;

if (public_key_dist[i] & (1)) {
temp = 1;
}

public_key_dist[i] >>= 1;

if (one)
public_key_dist[i] += (1 << 7);

one = temp;
}
}

static void find_midpoint(uint8_t *out, const uint8_t *top, const uint8_t *bot)
{
unsigned int i;

for (i = 0; i < crypto_box_PUBLICKEYBYTES; ++i) {
out[i] = top[i] ^ bot[i];
}

abs_divide_by_2(out);

for (i = 0; i < crypto_box_PUBLICKEYBYTES; ++i) {
out[i] ^= bot[i];
}
}

/* 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)
Client_data *list, uint32_t list_count, uint32_t *bootstrap_times, _Bool sortable)
{
uint32_t i;
uint8_t not_kill = 0;
Expand Down Expand Up @@ -1482,33 +1494,19 @@ static uint8_t do_ping_and_sendnode_requests(DHT *dht, uint64_t *lastgetnode, co
}
}

if (sort_ok) {
if (sortable && sort_ok) {
sort_client_list(list, list_count, public_key);
}

if ((num_nodes != 0) && (is_timeout(*lastgetnode, GET_NODE_INTERVAL) || *bootstrap_times < MAX_BOOTSTRAP_TIMES)) {
uint32_t rand_node = rand() % (num_nodes * 2);

if (rand_node >= num_nodes) {
rand_node = rand_node % num_nodes;

if ((num_nodes - 1) != rand_node) {
rand_node += rand() % (num_nodes - (rand_node + 1));
}

if (memcmp(client_list[rand_node]->public_key, public_key, crypto_box_PUBLICKEYBYTES) != 0) {
uint8_t get_pk[crypto_box_PUBLICKEYBYTES];
find_midpoint(get_pk, client_list[rand_node]->public_key, public_key);
getnodes(dht, assoc_list[rand_node]->ip_port, client_list[rand_node]->public_key, get_pk, NULL);
}
} else {
if ((num_nodes - 1) != rand_node) {
rand_node += rand() % (num_nodes - (rand_node + 1));
}
uint32_t rand_node = rand() % (num_nodes);

getnodes(dht, assoc_list[rand_node]->ip_port, client_list[rand_node]->public_key, public_key, NULL);
if ((num_nodes - 1) != rand_node) {
rand_node += rand() % (num_nodes - (rand_node + 1));
}

getnodes(dht, assoc_list[rand_node]->ip_port, client_list[rand_node]->public_key, public_key, NULL);

*lastgetnode = temp_time;
++*bootstrap_times;
}
Expand All @@ -1533,7 +1531,7 @@ static void do_DHT_friends(DHT *dht)
friend->num_to_bootstrap = 0;

do_ping_and_sendnode_requests(dht, &friend->lastgetnode, friend->public_key, friend->client_list, MAX_FRIEND_CLIENTS,
&friend->bootstrap_times);
&friend->bootstrap_times, 1);
}
}

Expand All @@ -1551,7 +1549,7 @@ static void do_Close(DHT *dht)
dht->num_to_bootstrap = 0;

uint8_t not_killed = do_ping_and_sendnode_requests(dht, &dht->close_lastgetnodes, dht->self_public_key,
dht->close_clientlist, LCLIENT_LIST, &dht->close_bootstrap_times);
dht->close_clientlist, LCLIENT_LIST, &dht->close_bootstrap_times, 0);

if (!not_killed) {
/* all existing nodes are at least KILL_NODE_TIMEOUT,
Expand Down Expand Up @@ -2453,7 +2451,7 @@ void do_DHT(DHT *dht)
do_DHT_friends(dht);
do_NAT(dht);
do_to_ping(dht->ping);
do_hardening(dht);
//do_hardening(dht);
#ifdef ENABLE_ASSOC_DHT

if (dht->assoc)
Expand Down
15 changes: 12 additions & 3 deletions toxcore/DHT.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,13 @@
/* Maximum number of clients stored per friend. */
#define MAX_FRIEND_CLIENTS 8

#define LCLIENT_NODES (MAX_FRIEND_CLIENTS)
#define LCLIENT_LENGTH 128

/* A list of the clients mathematically closest to ours. */
#define LCLIENT_LIST 32
#define LCLIENT_LIST (LCLIENT_LENGTH * LCLIENT_NODES)

#define MAX_CLOSE_TO_BOOTSTRAP_NODES 8

/* The max number of nodes to send with send nodes. */
#define MAX_SENT_NODES 4
Expand All @@ -58,7 +63,7 @@
#define TOX_TCP_INET6 138

/* The number of "fake" friends to add (for optimization purposes and so our paths for the onion part are more random) */
#define DHT_FAKE_FRIEND_NUMBER 4
#define DHT_FAKE_FRIEND_NUMBER 2

/* Functions to transfer ips safely across wire. */
void to_net_family(IP *ip);
Expand Down Expand Up @@ -232,7 +237,7 @@ typedef struct {

Cryptopacket_Handles cryptopackethandlers[256];

Node_format to_bootstrap[MAX_SENT_NODES];
Node_format to_bootstrap[MAX_CLOSE_TO_BOOTSTRAP_NODES];
unsigned int num_to_bootstrap;
} DHT;
/*----------------------------------------------------------------------------------*/
Expand Down Expand Up @@ -307,6 +312,10 @@ int id_closest(const uint8_t *pk, const uint8_t *pk1, const uint8_t *pk2);
_Bool add_to_list(Node_format *nodes_list, unsigned int length, const uint8_t *pk, IP_Port ip_port,
const uint8_t *cmp_pk);

/* 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);

/* Get the (maximum MAX_SENT_NODES) closest nodes to public_key we know
* and put them in nodes_list (must be MAX_SENT_NODES big).
*
Expand Down
11 changes: 8 additions & 3 deletions toxcore/ping.c
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,10 @@
#define PING_NUM_MAX 512

/* Maximum newly announced nodes to ping per TIME_TO_PING seconds. */
#define MAX_TO_PING 16
#define MAX_TO_PING 32

/* Ping newly announced nodes to ping per TIME_TO_PING seconds*/
#define TIME_TO_PING 4
#define TIME_TO_PING 2


struct PING {
Expand Down Expand Up @@ -262,9 +262,11 @@ int add_to_ping(PING *ping, const uint8_t *public_key, IP_Port ip_port)
if (!ip_isset(&ip_port.ip))
return -1;

if (in_list(ping->dht->close_clientlist, LCLIENT_LIST, public_key, ip_port))
if (!node_addable_to_close_list(ping->dht, public_key, ip_port))
return -1;

if (in_list(ping->dht->close_clientlist, LCLIENT_LIST, public_key, ip_port))
return -1;

IP_Port temp;

Expand Down Expand Up @@ -311,6 +313,9 @@ void do_to_ping(PING *ping)
if (!ip_isset(&ping->to_ping[i].ip_port.ip))
break;

if (!node_addable_to_close_list(ping->dht, ping->to_ping[i].public_key, ping->to_ping[i].ip_port))
continue;

send_ping_request(ping, ping->to_ping[i].ip_port, ping->to_ping[i].public_key);
ip_reset(&ping->to_ping[i].ip_port.ip);
}
Expand Down

0 comments on commit 760f20c

Please sign in to comment.