Skip to content

Commit

Permalink
Add DHT queries to private API
Browse files Browse the repository at this point in the history
This commit adds functionality for clients to send DHT getnodes
requests to their DHT peers. It also allows clients to make
queries on DHT nodes that they receive in a getnodes response,
including port, public key, and IP address (as a null terminated
string).

A typical use case would be for a DHT network crawler, but it
could also be used for understanding and diagnosing DHT network
behaviour.
  • Loading branch information
JFreegman committed Jan 29, 2022
1 parent 2b783c4 commit b6f8847
Show file tree
Hide file tree
Showing 6 changed files with 272 additions and 5 deletions.
2 changes: 1 addition & 1 deletion other/bootstrap_daemon/docker/tox-bootstrapd.sha256
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0edccd9abfeac725152b708b805ab9880a57398ef9e83a814256893c52fef3c0 /usr/local/bin/tox-bootstrapd
27d94faed44419ca5efcc747b44b44572e4c8e86eeef1dffbcf650dee28311fe /usr/local/bin/tox-bootstrapd
17 changes: 15 additions & 2 deletions toxcore/DHT.c
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,8 @@ struct DHT {

Node_format to_bootstrap[MAX_CLOSE_TO_BOOTSTRAP_NODES];
unsigned int num_to_bootstrap;

dht_get_nodes_response_cb *get_nodes_response;
};

const uint8_t *dht_friend_public_key(const DHT_Friend *dht_friend)
Expand Down Expand Up @@ -1499,6 +1501,10 @@ static int handle_sendnodes_ipv6(void *object, IP_Port source, const uint8_t *pa
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);

if (dht->get_nodes_response) {
dht->get_nodes_response(dht, &plain_nodes[i], userdata);
}
}
}

Expand Down Expand Up @@ -1767,15 +1773,17 @@ 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)
int dht_getnodes(DHT *dht, const IP_Port *from_ipp, const uint8_t *from_id, const uint8_t *which_id)
{
getnodes(dht, *from_ipp, from_id, which_id);
const int ret = getnodes(dht, *from_ipp, from_id, which_id);
return ret < 0 ? -1 : 0;
}

void dht_bootstrap(DHT *dht, IP_Port ip_port, const uint8_t *public_key)
{
getnodes(dht, ip_port, public_key, dht->self_public_key);
}

int dht_bootstrap_from_address(DHT *dht, const char *address, uint8_t ipv6enabled,
uint16_t port, const uint8_t *public_key)
{
Expand Down Expand Up @@ -2402,6 +2410,11 @@ static int cryptopacket_handle(void *object, IP_Port source, const uint8_t *pack
return 1;
}

void dht_callback_get_nodes_response(DHT *dht, dht_get_nodes_response_cb *function)
{
dht->get_nodes_response = function;
}

/*----------------------------------------------------------------------------------*/

DHT *new_dht(const Logger *log, Mono_Time *mono_time, Networking_Core *net, bool holepunching_enabled)
Expand Down
12 changes: 11 additions & 1 deletion toxcore/DHT.h
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,17 @@ void dht_get_shared_key_recv(DHT *dht, uint8_t *shared_key, const uint8_t *publi
*/
void dht_get_shared_key_sent(DHT *dht, uint8_t *shared_key, const uint8_t *public_key);

void dht_getnodes(DHT *dht, const IP_Port *from_ipp, const uint8_t *from_id, const uint8_t *which_id);
/** Sends a getnodes request to `from_ipp` with `from_id` for the public key `which_id`.
*
* Return 0 on success.
* Return -1 on failure.
*/
int dht_getnodes(DHT *dht, const IP_Port *from_ipp, const uint8_t *from_id, const uint8_t *which_id);

typedef void dht_get_nodes_response_cb(const DHT *dht, const Node_format *node, void *userdata);

/** Sets the callback to be triggered on a getnodes response. */
void dht_callback_get_nodes_response(DHT *dht, dht_get_nodes_response_cb *function);

typedef void dht_ip_cb(void *object, int32_t number, IP_Port ip_port);

Expand Down
122 changes: 121 additions & 1 deletion toxcore/tox.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,12 @@
#include "tox.h"
#include "tox_private.h"

#if defined(OS_WIN32) || (defined(_WIN32) || defined(__WIN32__) || defined(WIN32))
#include <winsock2.h>
#else
#include <arpa/inet.h>
#endif

#include <assert.h>
#include <stdlib.h>
#include <string.h>
Expand All @@ -21,6 +27,7 @@
#include "group.h"
#include "logger.h"
#include "mono_time.h"
#include "network.h"

#include "../toxencryptsave/defines.h"

Expand All @@ -35,6 +42,10 @@ static_assert(TOX_HASH_LENGTH == CRYPTO_SHA256_SIZE,
"TOX_HASH_LENGTH is assumed to be equal to CRYPTO_SHA256_SIZE");
static_assert(FILE_ID_LENGTH == CRYPTO_SYMMETRIC_KEY_SIZE,
"FILE_ID_LENGTH is assumed to be equal to CRYPTO_SYMMETRIC_KEY_SIZE");
static_assert(TOX_DHT_NODE_IP_STRING_SIZE == IP_NTOA_LEN,
"TOX_DHT_NODE_IP_STRING_SIZE is assumed to be equal to IP_NTOA_LEN");
static_assert(TOX_DHT_NODE_PUBLIC_KEY_SIZE == CRYPTO_PUBLIC_KEY_SIZE,
"TOX_DHT_NODE_PUBLIC_KEY_SIZE is assumed to be equal to CRYPTO_PUBLIC_KEY_SIZE");
static_assert(TOX_FILE_ID_LENGTH == CRYPTO_SYMMETRIC_KEY_SIZE,
"TOX_FILE_ID_LENGTH is assumed to be equal to CRYPTO_SYMMETRIC_KEY_SIZE");
static_assert(TOX_FILE_ID_LENGTH == TOX_HASH_LENGTH,
Expand All @@ -47,7 +58,6 @@ static_assert(TOX_MAX_NAME_LENGTH == MAX_NAME_LENGTH,
"TOX_MAX_NAME_LENGTH is assumed to be equal to MAX_NAME_LENGTH");
static_assert(TOX_MAX_STATUS_MESSAGE_LENGTH == MAX_STATUSMESSAGE_LENGTH,
"TOX_MAX_STATUS_MESSAGE_LENGTH is assumed to be equal to MAX_STATUSMESSAGE_LENGTH");

struct Tox {
// XXX: Messenger *must* be the first member, because toxav casts its
// `Tox *` to `Messenger **`.
Expand All @@ -74,6 +84,7 @@ struct Tox {
tox_conference_title_cb *conference_title_callback;
tox_conference_peer_name_cb *conference_peer_name_callback;
tox_conference_peer_list_changed_cb *conference_peer_list_changed_callback;
tox_dht_get_nodes_response_cb *dht_get_nodes_response_callback;
tox_friend_lossy_packet_cb *friend_lossy_packet_callback_per_pktid[UINT8_MAX + 1];
tox_friend_lossless_packet_cb *friend_lossless_packet_callback_per_pktid[UINT8_MAX + 1];

Expand Down Expand Up @@ -293,6 +304,29 @@ static void tox_conference_peer_list_changed_handler(Messenger *m, uint32_t conf
}
}

static void tox_dht_get_nodes_response_handler(const DHT *dht, const Node_format *node, void *user_data)
{
struct Tox_Userdata *tox_data = (struct Tox_Userdata *)user_data;

if (tox_data->tox->dht_get_nodes_response_callback != nullptr) {
Tox_Dht_Node *tox_node = (Tox_Dht_Node *)calloc(1, sizeof(Tox_Dht_Node));

if (tox_node == nullptr) {
return;
}

tox_node->data = (Node_format *)calloc(1, sizeof(Node_format));

if (tox_node->data == nullptr) {
free(tox_node);
return;
}

memcpy(tox_node->data, node, sizeof(Node_format));
tox_data->tox->dht_get_nodes_response_callback(tox_data->tox, (Tox_Dht_Node *)tox_node, tox_data->user_data);
}
}

static void tox_friend_lossy_packet_handler(Messenger *m, uint32_t friend_number, uint8_t packet_id,
const uint8_t *data, size_t length, void *user_data)
{
Expand Down Expand Up @@ -588,6 +622,7 @@ Tox *tox_new(const struct Tox_Options *options, Tox_Err_New *error)
callback_file_reqchunk(tox->m, tox_file_chunk_request_handler);
callback_file_sendrequest(tox->m, tox_file_recv_handler);
callback_file_data(tox->m, tox_file_recv_chunk_handler);
dht_callback_get_nodes_response(tox->m->dht, tox_dht_get_nodes_response_handler);
g_callback_group_invite(tox->m->conferences_object, tox_conference_invite_handler);
g_callback_group_connected(tox->m->conferences_object, tox_conference_connected_handler);
g_callback_group_message(tox->m->conferences_object, tox_conference_message_handler);
Expand Down Expand Up @@ -2521,3 +2556,88 @@ uint16_t tox_self_get_tcp_port(const Tox *tox, Tox_Err_Get_Port *error)
unlock(tox);
return 0;
}

void tox_callback_dht_get_nodes_response(Tox *tox, tox_dht_get_nodes_response_cb *callback)
{
assert(tox != nullptr);
tox->dht_get_nodes_response_callback = callback;
}

bool tox_dht_get_nodes(const Tox *tox, const Tox_Dht_Node *dest_node, const uint8_t *public_key,
Tox_Err_Dht_Get_Nodes *error)
{
assert(tox != nullptr);

if (dest_node == nullptr || public_key == nullptr) {
SET_ERROR_PARAMETER(error, TOX_ERR_DHT_GET_NODES_NULL);
return false;
}

const Node_format *node = (const Node_format *)dest_node->data;

if (node == nullptr) {
SET_ERROR_PARAMETER(error, TOX_ERR_DHT_GET_NODES_NULL);
return false;
}

lock(tox);
const int ret = dht_getnodes(tox->m->dht, &node->ip_port, node->public_key, public_key);
unlock(tox);

if (ret < 0) {
SET_ERROR_PARAMETER(error, TOX_ERR_DHT_GET_NODES_FAIL);
return false;
}

SET_ERROR_PARAMETER(error, TOX_ERR_DHT_GET_NODES_OK);

return true;
}

uint16_t tox_dht_node_get_port(const Tox_Dht_Node *dht_node)
{
if (dht_node == nullptr) {
return 0;
}

const Node_format *node = (const Node_format *)dht_node->data;
return ntohs(node->ip_port.port);
}

void tox_dht_node_get_public_key(const Tox_Dht_Node *dht_node, uint8_t *public_key)
{
if (dht_node == nullptr || public_key == nullptr) {
return;
}

const Node_format *node = (const Node_format *)dht_node->data;
memcpy(public_key, node->public_key, CRYPTO_PUBLIC_KEY_SIZE);
}

size_t tox_dht_node_get_ip_string(const Tox_Dht_Node *dht_node, char *ip_str, size_t length)
{
if (dht_node == nullptr) {
return 0;
}

const Node_format *node = (const Node_format *)dht_node->data;
ip_ntoa(&node->ip_port.ip, ip_str, length);

size_t i;

for (i = 0; i < length; ++i) {
if (ip_str[i] == '\0') {
break;
}
}

return i;
}

void tox_dht_node_free(Tox_Dht_Node *dht_node)
{
if (dht_node) {
free(dht_node->data);
free(dht_node);
}
}
3 changes: 3 additions & 0 deletions toxcore/tox_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
* Copyright © 2016-2021 The TokTok team.
*/
#include "tox.h"
#include "tox_private.h"

#include <stdlib.h>
#include <string.h>
Expand Down Expand Up @@ -41,6 +42,8 @@ CONST_FUNCTION(hash_length, HASH_LENGTH)
CONST_FUNCTION(file_id_length, FILE_ID_LENGTH)
CONST_FUNCTION(max_filename_length, MAX_FILENAME_LENGTH)
CONST_FUNCTION(max_hostname_length, MAX_HOSTNAME_LENGTH)
CONST_FUNCTION(dht_node_ip_string_size, DHT_NODE_IP_STRING_SIZE)
CONST_FUNCTION(dht_node_public_key_size, DHT_NODE_PUBLIC_KEY_SIZE)


#define ACCESSORS(type, ns, name) \
Expand Down
Loading

0 comments on commit b6f8847

Please sign in to comment.