summaryrefslogtreecommitdiff
path: root/protocols/Tox/libtox/src/toxcore/onion_client.c
diff options
context:
space:
mode:
Diffstat (limited to 'protocols/Tox/libtox/src/toxcore/onion_client.c')
-rw-r--r--protocols/Tox/libtox/src/toxcore/onion_client.c222
1 files changed, 200 insertions, 22 deletions
diff --git a/protocols/Tox/libtox/src/toxcore/onion_client.c b/protocols/Tox/libtox/src/toxcore/onion_client.c
index 91168c661c..ff63473e10 100644
--- a/protocols/Tox/libtox/src/toxcore/onion_client.c
+++ b/protocols/Tox/libtox/src/toxcore/onion_client.c
@@ -15,6 +15,7 @@
#include "LAN_discovery.h"
#include "ccompat.h"
+#include "group_onion_announce.h"
#include "mono_time.h"
#include "util.h"
@@ -54,7 +55,7 @@ typedef struct Last_Pinged {
uint64_t timestamp;
} Last_Pinged;
-typedef struct Onion_Friend {
+struct Onion_Friend {
bool is_valid;
bool is_online;
@@ -87,7 +88,12 @@ typedef struct Onion_Friend {
onion_dht_pk_cb *dht_pk_callback;
void *dht_pk_callback_object;
uint32_t dht_pk_callback_number;
-} Onion_Friend;
+
+ uint8_t gc_data[GCA_MAX_DATA_LENGTH];
+ uint8_t gc_public_key[ENC_PUBLIC_KEY_SIZE];
+ uint16_t gc_data_length;
+ bool is_groupchat;
+};
static const Onion_Friend empty_onion_friend = {false};
@@ -138,8 +144,51 @@ struct Onion_Client {
unsigned int onion_connected;
bool udp_connected;
+
+ onion_group_announce_cb *group_announce_response;
+ void *group_announce_response_user_data;
};
+uint16_t onion_get_friend_count(const Onion_Client *const onion_c)
+{
+ return onion_c->num_friends;
+}
+
+Onion_Friend *onion_get_friend(const Onion_Client *const onion_c, uint16_t friend_num)
+{
+ return &onion_c->friends_list[friend_num];
+}
+
+const uint8_t *onion_friend_get_gc_public_key(const Onion_Friend *const onion_friend)
+{
+ return onion_friend->gc_public_key;
+}
+
+const uint8_t *onion_friend_get_gc_public_key_num(const Onion_Client *const onion_c, uint32_t num)
+{
+ return onion_c->friends_list[num].gc_public_key;
+}
+
+void onion_friend_set_gc_public_key(Onion_Friend *const onion_friend, const uint8_t *public_key)
+{
+ memcpy(onion_friend->gc_public_key, public_key, ENC_PUBLIC_KEY_SIZE);
+}
+
+void onion_friend_set_gc_data(Onion_Friend *const onion_friend, const uint8_t *gc_data, uint16_t gc_data_length)
+{
+ if (gc_data_length > 0 && gc_data != nullptr) {
+ memcpy(onion_friend->gc_data, gc_data, gc_data_length);
+ }
+
+ onion_friend->gc_data_length = gc_data_length;
+ onion_friend->is_groupchat = true;
+}
+
+bool onion_friend_is_groupchat(const Onion_Friend *const onion_friend)
+{
+ return onion_friend->is_groupchat;
+}
+
DHT *onion_get_dht(const Onion_Client *onion_c)
{
return onion_c->dht;
@@ -351,8 +400,8 @@ static bool path_timed_out(const Mono_Time *mono_time, const Onion_Client_Paths
const uint64_t timeout = is_new ? ONION_PATH_FIRST_TIMEOUT : ONION_PATH_TIMEOUT;
return (onion_paths->last_path_used_times[pathnum] >= ONION_PATH_MAX_NO_RESPONSE_USES
- && mono_time_is_timeout(mono_time, onion_paths->last_path_used[pathnum], timeout))
- || mono_time_is_timeout(mono_time, onion_paths->path_creation_time[pathnum], ONION_PATH_MAX_LIFETIME);
+ && mono_time_is_timeout(mono_time, onion_paths->last_path_used[pathnum], timeout))
+ || mono_time_is_timeout(mono_time, onion_paths->path_creation_time[pathnum], ONION_PATH_MAX_LIFETIME);
}
/** should node be considered to have timed out */
@@ -360,8 +409,8 @@ non_null()
static bool onion_node_timed_out(const Onion_Node *node, const Mono_Time *mono_time)
{
return node->timestamp == 0
- || (node->pings_since_last_response >= ONION_NODE_MAX_PINGS
- && mono_time_is_timeout(mono_time, node->last_pinged, ONION_NODE_TIMEOUT));
+ || (node->pings_since_last_response >= ONION_NODE_MAX_PINGS
+ && mono_time_is_timeout(mono_time, node->last_pinged, ONION_NODE_TIMEOUT));
}
/** @brief Create a new path or use an old suitable one (if pathnum is valid)
@@ -600,19 +649,35 @@ static int client_send_announce_request(Onion_Client *onion_c, uint32_t num, con
ping_id = zero_ping_id;
}
- uint8_t request[ONION_ANNOUNCE_REQUEST_SIZE];
+ uint8_t request[ONION_ANNOUNCE_REQUEST_MAX_SIZE];
int len;
if (num == 0) {
len = create_announce_request(
- onion_c->rng, request, sizeof(request), dest_pubkey, nc_get_self_public_key(onion_c->c),
- nc_get_self_secret_key(onion_c->c), ping_id, nc_get_self_public_key(onion_c->c),
- onion_c->temp_public_key, sendback);
+ onion_c->rng, request, sizeof(request), dest_pubkey, nc_get_self_public_key(onion_c->c),
+ nc_get_self_secret_key(onion_c->c), ping_id, nc_get_self_public_key(onion_c->c),
+ onion_c->temp_public_key, sendback);
} else {
- len = create_announce_request(
- onion_c->rng, request, sizeof(request), dest_pubkey, onion_c->friends_list[num - 1].temp_public_key,
- onion_c->friends_list[num - 1].temp_secret_key, ping_id,
- onion_c->friends_list[num - 1].real_public_key, zero_ping_id, sendback);
+ Onion_Friend *onion_friend = &onion_c->friends_list[num - 1];
+
+ if (onion_friend->gc_data_length == 0) { // contact is a friend
+ len = create_announce_request(
+ onion_c->rng, request, sizeof(request), dest_pubkey, onion_friend->temp_public_key,
+ onion_friend->temp_secret_key, ping_id, onion_friend->real_public_key,
+ zero_ping_id, sendback);
+ } else { // contact is a gc
+#ifndef VANILLA_NACL
+ onion_friend->is_groupchat = true;
+
+ len = create_gca_announce_request(
+ onion_c->rng, request, sizeof(request), dest_pubkey, onion_friend->temp_public_key,
+ onion_friend->temp_secret_key, ping_id, onion_friend->real_public_key,
+ zero_ping_id, sendback, onion_friend->gc_data,
+ onion_friend->gc_data_length);
+#else
+ return -1;
+#endif // VANILLA_NACL
+ }
}
if (len == -1) {
@@ -852,6 +917,16 @@ static int client_ping_nodes(Onion_Client *onion_c, uint32_t num, const Node_for
}
non_null()
+static bool handle_group_announce_response(Onion_Client *onion_c, uint32_t num, const uint8_t *plain, size_t plain_size)
+{
+ if (onion_c->group_announce_response == nullptr) {
+ return true;
+ }
+
+ return onion_c->group_announce_response(onion_c, num, plain, plain_size, onion_c->group_announce_response_user_data);
+}
+
+non_null(1, 2, 3) nullable(5)
static int handle_announce_response(void *object, const IP_Port *source, const uint8_t *packet, uint16_t length,
void *userdata)
{
@@ -861,6 +936,95 @@ static int handle_announce_response(void *object, const IP_Port *source, const u
return 1;
}
+ uint8_t public_key[CRYPTO_PUBLIC_KEY_SIZE];
+ IP_Port ip_port;
+ uint32_t path_num;
+ const uint32_t num = check_sendback(onion_c, packet + 1, public_key, &ip_port, &path_num);
+
+ if (num > onion_c->num_friends) {
+ return 1;
+ }
+
+ uint8_t plain[1 + ONION_PING_ID_SIZE + ONION_ANNOUNCE_RESPONSE_MAX_SIZE - ONION_ANNOUNCE_RESPONSE_MIN_SIZE];
+ const int plain_size = 1 + ONION_PING_ID_SIZE + length - ONION_ANNOUNCE_RESPONSE_MIN_SIZE;
+ int len;
+
+ if (num == 0) {
+ len = decrypt_data(public_key, nc_get_self_secret_key(onion_c->c),
+ packet + 1 + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH,
+ packet + 1 + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH + CRYPTO_NONCE_SIZE,
+ length - (1 + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH + CRYPTO_NONCE_SIZE), plain);
+ } else {
+ if (!onion_c->friends_list[num - 1].is_valid) {
+ return 1;
+ }
+
+ len = decrypt_data(public_key, onion_c->friends_list[num - 1].temp_secret_key,
+ packet + 1 + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH,
+ packet + 1 + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH + CRYPTO_NONCE_SIZE,
+ length - (1 + ONION_ANNOUNCE_SENDBACK_DATA_LENGTH + CRYPTO_NONCE_SIZE), plain);
+ }
+
+ if ((uint32_t)len != plain_size) {
+ return 1;
+ }
+
+ const uint32_t path_used = set_path_timeouts(onion_c, num, path_num);
+
+ if (client_add_to_list(onion_c, num, public_key, &ip_port, plain[0], plain + 1, path_used) == -1) {
+ return 1;
+ }
+
+ uint16_t len_nodes = 0;
+ const uint8_t nodes_count = plain[1 + ONION_PING_ID_SIZE];
+
+ if (nodes_count > 0) {
+ if (nodes_count > MAX_SENT_NODES) {
+ return 1;
+ }
+
+ Node_format nodes[MAX_SENT_NODES];
+ const int num_nodes = unpack_nodes(nodes, nodes_count, &len_nodes, plain + 2 + ONION_PING_ID_SIZE,
+ plain_size - 2 - ONION_PING_ID_SIZE, false);
+
+ if (num_nodes < 0) {
+ return 1;
+ }
+
+ if (client_ping_nodes(onion_c, num, nodes, num_nodes, source) == -1) {
+ return 1;
+ }
+ }
+
+ if (len_nodes + 1 < length - ONION_ANNOUNCE_RESPONSE_MIN_SIZE) {
+ const uint16_t offset = 2 + ONION_PING_ID_SIZE + len_nodes;
+
+ if (plain_size < offset) {
+ return 1;
+ }
+
+ if (!handle_group_announce_response(onion_c, num, plain + offset, plain_size - offset)) {
+ return 1;
+ }
+ }
+
+ // TODO(irungentoo): LAN vs non LAN ips?, if we are connected only to LAN, are we offline?
+ onion_c->last_packet_recv = mono_time_get(onion_c->mono_time);
+
+ return 0;
+}
+
+/* TODO(jfreegman): DEPRECATE */
+non_null(1, 2, 3) nullable(5)
+static int handle_announce_response_old(void *object, const IP_Port *source, const uint8_t *packet, uint16_t length,
+ void *userdata)
+{
+ Onion_Client *onion_c = (Onion_Client *)object;
+
+ if (length < ONION_ANNOUNCE_RESPONSE_MIN_SIZE || length > ONION_ANNOUNCE_RESPONSE_MAX_SIZE) {
+ return 1;
+ }
+
const uint16_t len_nodes = length - ONION_ANNOUNCE_RESPONSE_MIN_SIZE;
uint8_t public_key[CRYPTO_PUBLIC_KEY_SIZE];
@@ -1038,10 +1202,14 @@ static int handle_tcp_onion(void *object, const uint8_t *data, uint16_t length,
IP_Port ip_port = {{{0}}};
ip_port.ip.family = net_family_tcp_server();
- if (data[0] == NET_PACKET_ANNOUNCE_RESPONSE_OLD) {
+ if (data[0] == NET_PACKET_ANNOUNCE_RESPONSE) {
return handle_announce_response(object, &ip_port, data, length, userdata);
}
+ if (data[0] == NET_PACKET_ANNOUNCE_RESPONSE_OLD) {
+ return handle_announce_response_old(object, &ip_port, data, length, userdata);
+ }
+
if (data[0] == NET_PACKET_ONION_DATA_RESPONSE) {
return handle_data_response(object, &ip_port, data, length, userdata);
}
@@ -1118,8 +1286,8 @@ int send_onion_data(Onion_Client *onion_c, int friend_num, const uint8_t *data,
uint8_t o_packet[ONION_MAX_PACKET_SIZE];
len = create_data_request(
- onion_c->rng, o_packet, sizeof(o_packet), onion_c->friends_list[friend_num].real_public_key,
- node_list[good_nodes[i]].data_public_key, nonce, packet, SIZEOF_VLA(packet));
+ onion_c->rng, o_packet, sizeof(o_packet), onion_c->friends_list[friend_num].real_public_key,
+ node_list[good_nodes[i]].data_public_key, nonce, packet, SIZEOF_VLA(packet));
if (len == -1) {
continue;
@@ -1167,8 +1335,8 @@ static int send_dht_dhtpk(const Onion_Client *onion_c, int friend_num, const uin
uint8_t packet_data[MAX_CRYPTO_REQUEST_SIZE];
len = create_request(
- onion_c->rng, dht_get_self_public_key(onion_c->dht), dht_get_self_secret_key(onion_c->dht), packet_data,
- onion_c->friends_list[friend_num].dht_public_key, temp, SIZEOF_VLA(temp), CRYPTO_PACKET_DHTPK);
+ onion_c->rng, dht_get_self_public_key(onion_c->dht), dht_get_self_secret_key(onion_c->dht), packet_data,
+ onion_c->friends_list[friend_num].dht_public_key, temp, SIZEOF_VLA(temp), CRYPTO_PACKET_DHTPK);
assert(len <= UINT16_MAX);
const Packet packet = {packet_data, (uint16_t)len};
@@ -1237,7 +1405,8 @@ static int send_dhtpk_announce(Onion_Client *onion_c, uint16_t friend_num, uint8
int nodes_len = 0;
if (num_nodes != 0) {
- nodes_len = pack_nodes(onion_c->logger, data + DHTPK_DATA_MIN_LENGTH, DHTPK_DATA_MAX_LENGTH - DHTPK_DATA_MIN_LENGTH, nodes, num_nodes);
+ nodes_len = pack_nodes(onion_c->logger, data + DHTPK_DATA_MIN_LENGTH, DHTPK_DATA_MAX_LENGTH - DHTPK_DATA_MIN_LENGTH,
+ nodes, num_nodes);
if (nodes_len <= 0) {
return -1;
@@ -1344,7 +1513,8 @@ int onion_addfriend(Onion_Client *onion_c, const uint8_t *public_key)
onion_c->friends_list[index].is_valid = true;
memcpy(onion_c->friends_list[index].real_public_key, public_key, CRYPTO_PUBLIC_KEY_SIZE);
- crypto_new_keypair(onion_c->rng, onion_c->friends_list[index].temp_public_key, onion_c->friends_list[index].temp_secret_key);
+ crypto_new_keypair(onion_c->rng, onion_c->friends_list[index].temp_public_key,
+ onion_c->friends_list[index].temp_secret_key);
return index;
}
@@ -1674,6 +1844,12 @@ void oniondata_registerhandler(Onion_Client *onion_c, uint8_t byte, oniondata_ha
onion_c->onion_data_handlers[byte].object = object;
}
+void onion_group_announce_register(Onion_Client *onion_c, onion_group_announce_cb *func, void *user_data)
+{
+ onion_c->group_announce_response = func;
+ onion_c->group_announce_response_user_data = user_data;
+}
+
#define ANNOUNCE_INTERVAL_NOT_ANNOUNCED 3
#define ANNOUNCE_INTERVAL_ANNOUNCED ONION_NODE_PING_INTERVAL
@@ -1925,7 +2101,8 @@ Onion_Client *new_onion_client(const Logger *logger, const Random *rng, const Mo
onion_c->c = c;
new_symmetric_key(rng, onion_c->secret_symmetric_key);
crypto_new_keypair(rng, onion_c->temp_public_key, onion_c->temp_secret_key);
- networking_registerhandler(onion_c->net, NET_PACKET_ANNOUNCE_RESPONSE_OLD, &handle_announce_response, onion_c);
+ networking_registerhandler(onion_c->net, NET_PACKET_ANNOUNCE_RESPONSE, &handle_announce_response, onion_c);
+ networking_registerhandler(onion_c->net, NET_PACKET_ANNOUNCE_RESPONSE_OLD, &handle_announce_response_old, onion_c);
networking_registerhandler(onion_c->net, NET_PACKET_ONION_DATA_RESPONSE, &handle_data_response, onion_c);
oniondata_registerhandler(onion_c, ONION_DATA_DHTPK, &handle_dhtpk_announce, onion_c);
cryptopacket_registerhandler(onion_c->dht, CRYPTO_PACKET_DHTPK, &handle_dht_dhtpk, onion_c);
@@ -1942,6 +2119,7 @@ void kill_onion_client(Onion_Client *onion_c)
ping_array_kill(onion_c->announce_ping_array);
realloc_onion_friends(onion_c, 0);
+ networking_registerhandler(onion_c->net, NET_PACKET_ANNOUNCE_RESPONSE, nullptr, nullptr);
networking_registerhandler(onion_c->net, NET_PACKET_ANNOUNCE_RESPONSE_OLD, nullptr, nullptr);
networking_registerhandler(onion_c->net, NET_PACKET_ONION_DATA_RESPONSE, nullptr, nullptr);
oniondata_registerhandler(onion_c, ONION_DATA_DHTPK, nullptr, nullptr);