summaryrefslogtreecommitdiff
path: root/protocols/Tox/libtox/src/toxcore/group_chats.c
diff options
context:
space:
mode:
Diffstat (limited to 'protocols/Tox/libtox/src/toxcore/group_chats.c')
-rw-r--r--protocols/Tox/libtox/src/toxcore/group_chats.c772
1 files changed, 466 insertions, 306 deletions
diff --git a/protocols/Tox/libtox/src/toxcore/group_chats.c b/protocols/Tox/libtox/src/toxcore/group_chats.c
index f9cb2d18fb..96f647cc2e 100644
--- a/protocols/Tox/libtox/src/toxcore/group_chats.c
+++ b/protocols/Tox/libtox/src/toxcore/group_chats.c
@@ -9,29 +9,34 @@
#include "group_chats.h"
-#include <assert.h>
-
-#ifndef VANILLA_NACL
#include <sodium.h>
-#endif
+#include <assert.h>
+#include <stdlib.h>
#include <string.h>
#include "DHT.h"
-#include "LAN_discovery.h"
#include "Messenger.h"
#include "TCP_connection.h"
+#include "attributes.h"
+#include "bin_pack.h"
+#include "bin_unpack.h"
#include "ccompat.h"
+#include "crypto_core.h"
#include "friend_connection.h"
+#include "group_announce.h"
#include "group_common.h"
+#include "group_connection.h"
#include "group_moderation.h"
#include "group_pack.h"
+#include "logger.h"
#include "mono_time.h"
+#include "net_crypto.h"
#include "network.h"
+#include "onion_announce.h"
+#include "onion_client.h"
#include "util.h"
-#ifndef VANILLA_NACL
-
/* The minimum size of a plaintext group handshake packet */
#define GC_MIN_HS_PACKET_PAYLOAD_SIZE (1 + ENC_PUBLIC_KEY_SIZE + SIG_PUBLIC_KEY_SIZE + 1 + 1)
@@ -108,10 +113,19 @@ static_assert(GCC_BUFFER_SIZE <= UINT16_MAX,
static_assert(MAX_GC_PACKET_CHUNK_SIZE < MAX_GC_PACKET_SIZE,
"MAX_GC_PACKET_CHUNK_SIZE must be < MAX_GC_PACKET_SIZE");
+static_assert(MAX_GC_PACKET_INCOMING_CHUNK_SIZE < MAX_GC_PACKET_SIZE,
+ "MAX_GC_PACKET_INCOMING_CHUNK_SIZE must be < MAX_GC_PACKET_SIZE");
+
+static_assert(MAX_GC_PACKET_INCOMING_CHUNK_SIZE >= MAX_GC_PACKET_CHUNK_SIZE,
+ "MAX_GC_PACKET_INCOMING_CHUNK_SIZE must be >= MAX_GC_PACKET_CHUNK_SIZE");
+
// size of a lossless handshake packet - lossless packets can't/shouldn't be split up
static_assert(MAX_GC_PACKET_CHUNK_SIZE >= 171,
"MAX_GC_PACKET_CHUNK_SIZE must be >= 171");
+static_assert(MAX_GC_PACKET_INCOMING_CHUNK_SIZE >= 171,
+ "MAX_GC_PACKET_INCOMING_CHUNK_SIZE must be >= 171");
+
// group_moderation constants assume this is the max packet size.
static_assert(MAX_GC_PACKET_SIZE >= 50000,
"MAX_GC_PACKET_SIZE doesn't match constants in group_moderation.h");
@@ -119,6 +133,9 @@ static_assert(MAX_GC_PACKET_SIZE >= 50000,
static_assert(MAX_GC_PACKET_SIZE <= UINT16_MAX - MAX_GC_PACKET_CHUNK_SIZE,
"MAX_GC_PACKET_SIZE must be <= UINT16_MAX - MAX_GC_PACKET_CHUNK_SIZE");
+static_assert(MAX_GC_PACKET_SIZE <= UINT16_MAX - MAX_GC_PACKET_INCOMING_CHUNK_SIZE,
+ "MAX_GC_PACKET_SIZE must be <= UINT16_MAX - MAX_GC_PACKET_INCOMING_CHUNK_SIZE");
+
/** Types of broadcast messages. */
typedef enum Group_Message_Type {
GC_MESSAGE_TYPE_NORMAL = 0x00,
@@ -148,7 +165,7 @@ non_null() static bool self_gc_is_founder(const GC_Chat *chat);
non_null() static bool group_number_valid(const GC_Session *c, int group_number);
non_null() static int peer_update(const GC_Chat *chat, const GC_Peer *peer, uint32_t peer_number);
non_null() static void group_delete(GC_Session *c, GC_Chat *chat);
-non_null() static void group_cleanup(GC_Session *c, GC_Chat *chat);
+non_null() static void group_cleanup(const GC_Session *c, GC_Chat *chat);
non_null() static bool group_exists(const GC_Session *c, const uint8_t *chat_id);
non_null() static void add_tcp_relays_to_chat(const GC_Session *c, GC_Chat *chat);
non_null(1, 2) nullable(4)
@@ -160,6 +177,35 @@ non_null() static bool saved_peer_is_valid(const GC_SavedPeerInfo *saved_peer);
static const GC_Chat empty_gc_chat = {nullptr};
+#define GC_INVALID_PEER_ID_VALUE ((force GC_Peer_Id_Value)-1)
+
+static GC_Peer_Id gc_invalid_peer_id(void)
+{
+ const GC_Peer_Id invalid = {GC_INVALID_PEER_ID_VALUE};
+ return invalid;
+}
+
+static bool gc_peer_id_is_valid(GC_Peer_Id peer_id)
+{
+ return peer_id.value != GC_INVALID_PEER_ID_VALUE;
+}
+
+GC_Peer_Id gc_peer_id_from_int(uint32_t value)
+{
+ const GC_Peer_Id peer_id = {(force GC_Peer_Id_Value)value};
+ return peer_id;
+}
+
+uint32_t gc_peer_id_to_int(GC_Peer_Id peer_id)
+{
+ return (force uint32_t)peer_id.value;
+}
+
+static GC_Peer_Id gc_unknown_peer_id(void)
+{
+ return gc_peer_id_from_int(0);
+}
+
non_null()
static void kill_group_friend_connection(const GC_Session *c, const GC_Chat *chat)
{
@@ -170,7 +216,7 @@ static void kill_group_friend_connection(const GC_Session *c, const GC_Chat *cha
uint16_t gc_get_wrapped_packet_size(uint16_t length, Net_Packet_Type packet_type)
{
- assert(length <= MAX_GC_PACKET_CHUNK_SIZE);
+ assert(length <= (packet_type == NET_PACKET_GC_LOSSY ? MAX_GC_CUSTOM_LOSSY_PACKET_SIZE : MAX_GC_PACKET_CHUNK_SIZE));
const uint16_t min_header_size = packet_type == NET_PACKET_GC_LOSSY
? GC_MIN_LOSSY_PAYLOAD_SIZE
@@ -214,10 +260,20 @@ GC_Connection *get_gc_connection(const GC_Chat *chat, int peer_number)
return &peer->gconn;
}
+/** Returns the max packet size, not wrapped */
+static uint16_t group_packet_max_packet_size(Net_Packet_Type net_packet_type)
+{
+ if (net_packet_type == NET_PACKET_GC_LOSSY) {
+ return MAX_GC_CUSTOM_LOSSY_PACKET_SIZE;
+ } else {
+ return MAX_GC_PACKET_CHUNK_SIZE;
+ }
+}
+
/** Returns the amount of empty padding a packet of designated length should have. */
-static uint16_t group_packet_padding_length(uint16_t length)
+static uint16_t group_packet_padding_length(uint16_t length, uint16_t max_length)
{
- return (MAX_GC_PACKET_CHUNK_SIZE - length) % GC_MAX_PACKET_PADDING;
+ return (max_length - length) % GC_MAX_PACKET_PADDING;
}
void gc_get_self_nick(const GC_Chat *chat, uint8_t *nick)
@@ -302,7 +358,7 @@ static void self_gc_set_status(const GC_Chat *chat, Group_Peer_Status status)
LOGGER_WARNING(chat->log, "Attempting to set user status with invalid status: %u", (uint8_t)status);
}
-uint32_t gc_get_self_peer_id(const GC_Chat *chat)
+GC_Peer_Id gc_get_self_peer_id(const GC_Chat *chat)
{
const GC_Peer *peer = get_gc_peer(chat, 0);
assert(peer != nullptr);
@@ -330,7 +386,7 @@ static bool self_gc_is_founder(const GC_Chat *chat)
void gc_get_self_public_key(const GC_Chat *chat, uint8_t *public_key)
{
if (public_key != nullptr) {
- memcpy(public_key, chat->self_public_key, ENC_PUBLIC_KEY_SIZE);
+ memcpy(public_key, chat->self_public_key.enc, ENC_PUBLIC_KEY_SIZE);
}
}
@@ -339,12 +395,12 @@ void gc_get_self_public_key(const GC_Chat *chat, uint8_t *public_key)
* If `ext_public_key` is null this function has no effect.
*/
non_null()
-static void self_gc_set_ext_public_key(const GC_Chat *chat, const uint8_t *ext_public_key)
+static void self_gc_set_ext_public_key(const GC_Chat *chat, const Extended_Public_Key *ext_public_key)
{
if (ext_public_key != nullptr) {
GC_Connection *gconn = get_gc_connection(chat, 0);
assert(gconn != nullptr);
- memcpy(gconn->addr.public_key, ext_public_key, EXT_PUBLIC_KEY_SIZE);
+ gconn->addr.public_key = *ext_public_key;
}
}
@@ -523,7 +579,7 @@ static GC_Chat *get_chat_by_id(const GC_Session *c, const uint8_t *id)
continue;
}
- if (memcmp(id, chat->self_public_key, ENC_PUBLIC_KEY_SIZE) == 0) {
+ if (memcmp(id, chat->self_public_key.enc, ENC_PUBLIC_KEY_SIZE) == 0) {
return chat;
}
@@ -585,7 +641,7 @@ int get_peer_number_of_enc_pk(const GC_Chat *chat, const uint8_t *public_enc_key
continue;
}
- if (memcmp(gconn->addr.public_key, public_enc_key, ENC_PUBLIC_KEY_SIZE) == 0) {
+ if (memcmp(gconn->addr.public_key.enc, public_enc_key, ENC_PUBLIC_KEY_SIZE) == 0) {
return i;
}
}
@@ -606,7 +662,7 @@ static int get_peer_number_of_sig_pk(const GC_Chat *chat, const uint8_t *public_
assert(gconn != nullptr);
- if (memcmp(get_sig_pk(gconn->addr.public_key), public_sig_key, SIG_PUBLIC_KEY_SIZE) == 0) {
+ if (memcmp(get_sig_pk(&gconn->addr.public_key), public_sig_key, SIG_PUBLIC_KEY_SIZE) == 0) {
return i;
}
}
@@ -622,7 +678,7 @@ static bool gc_get_enc_pk_from_sig_pk(const GC_Chat *chat, uint8_t *public_key,
assert(gconn != nullptr);
- const uint8_t *full_pk = gconn->addr.public_key;
+ const Extended_Public_Key *full_pk = &gconn->addr.public_key;
if (memcmp(public_sig_key, get_sig_pk(full_pk), SIG_PUBLIC_KEY_SIZE) == 0) {
memcpy(public_key, get_enc_key(full_pk), ENC_PUBLIC_KEY_SIZE);
@@ -662,10 +718,10 @@ static GC_Connection *random_gc_connection(const GC_Chat *chat)
* Returns -1 if peer_id is invalid.
*/
non_null()
-static int get_peer_number_of_peer_id(const GC_Chat *chat, uint32_t peer_id)
+static int get_peer_number_of_peer_id(const GC_Chat *chat, GC_Peer_Id peer_id)
{
for (uint32_t i = 0; i < chat->numpeers; ++i) {
- if (chat->group[i].peer_id == peer_id) {
+ if (chat->group[i].peer_id.value == peer_id.value) {
return i;
}
}
@@ -680,15 +736,16 @@ static int get_peer_number_of_peer_id(const GC_Chat *chat, uint32_t peer_id)
* considered arbitrary values.
*/
non_null()
-static uint32_t get_new_peer_id(const GC_Chat *chat)
+static GC_Peer_Id get_new_peer_id(const GC_Chat *chat)
{
for (uint32_t i = 0; i < UINT32_MAX - 1; ++i) {
- if (get_peer_number_of_peer_id(chat, i) == -1) {
- return i;
+ const GC_Peer_Id peer_id = gc_peer_id_from_int(i);
+ if (get_peer_number_of_peer_id(chat, peer_id) == -1) {
+ return peer_id;
}
}
- return UINT32_MAX;
+ return gc_invalid_peer_id();
}
/** @brief Sets the password for the group (locally only).
@@ -704,7 +761,7 @@ static bool set_gc_password_local(GC_Chat *chat, const uint8_t *passwd, uint16_t
if (passwd == nullptr || length == 0) {
chat->shared_state.password_length = 0;
- memset(chat->shared_state.password, 0, MAX_GC_PASSWORD_SIZE);
+ memzero(chat->shared_state.password, MAX_GC_PASSWORD_SIZE);
} else {
chat->shared_state.password_length = length;
crypto_memlock(chat->shared_state.password, sizeof(chat->shared_state.password));
@@ -732,12 +789,12 @@ static void set_gc_shared_state_version(GC_Chat *chat, uint32_t version)
* Return true on success.
*/
non_null()
-static bool expand_chat_id(uint8_t *dest, const uint8_t *chat_id)
+static bool expand_chat_id(Extended_Public_Key *dest, const uint8_t *chat_id)
{
assert(dest != nullptr);
- const int ret = crypto_sign_ed25519_pk_to_curve25519(dest, chat_id);
- memcpy(dest + ENC_PUBLIC_KEY_SIZE, chat_id, SIG_PUBLIC_KEY_SIZE);
+ const int ret = crypto_sign_ed25519_pk_to_curve25519(dest->enc, chat_id);
+ memcpy(dest->sig, chat_id, SIG_PUBLIC_KEY_SIZE);
return ret != -1;
}
@@ -753,7 +810,7 @@ static void copy_gc_saved_peer(const Random *rng, const GC_Connection *gconn, GC
}
addr->ip_port = gconn->addr.ip_port;
- memcpy(addr->public_key, gconn->addr.public_key, ENC_PUBLIC_KEY_SIZE);
+ memcpy(addr->public_key, gconn->addr.public_key.enc, ENC_PUBLIC_KEY_SIZE);
}
/** Return true if `saved_peer` has either a valid IP_Port or a valid TCP relay. */
@@ -837,7 +894,7 @@ static int saved_peers_get_new_index(const GC_Chat *chat, const uint8_t *public_
non_null()
static void add_gc_saved_peers(GC_Chat *chat, const GC_Connection *gconn)
{
- const int idx = saved_peers_get_new_index(chat, gconn->addr.public_key);
+ const int idx = saved_peers_get_new_index(chat, gconn->addr.public_key.enc);
if (idx == -1) {
return;
@@ -872,7 +929,7 @@ static void refresh_gc_saved_peers(GC_Chat *chat)
continue;
}
- if (saved_peer_index(chat, gconn->addr.public_key) == -1) {
+ if (saved_peer_index(chat, gconn->addr.public_key.enc) == -1) {
GC_SavedPeerInfo *saved_peer = &chat->saved_peers[idx];
copy_gc_saved_peer(chat->rng, gconn, saved_peer);
return;
@@ -917,7 +974,7 @@ static bool peer_is_observer(const GC_Chat *chat, uint32_t peer_number)
return false;
}
- return sanctions_list_is_observer(&chat->moderation, get_enc_key(gconn->addr.public_key));
+ return sanctions_list_is_observer(&chat->moderation, get_enc_key(&gconn->addr.public_key));
}
/** Returns true if peer designated by `peer_number` is the group founder. */
@@ -931,7 +988,7 @@ static bool peer_is_founder(const GC_Chat *chat, uint32_t peer_number)
return false;
}
- return memcmp(chat->shared_state.founder_public_key, gconn->addr.public_key, ENC_PUBLIC_KEY_SIZE) == 0;
+ return memcmp(chat->shared_state.founder_public_key.enc, gconn->addr.public_key.enc, ENC_PUBLIC_KEY_SIZE) == 0;
}
/** Returns true if peer designated by `peer_number` is in the moderator list or is the founder. */
@@ -948,7 +1005,7 @@ static bool peer_is_moderator(const GC_Chat *chat, uint32_t peer_number)
return false;
}
- return mod_list_verify_sig_pk(&chat->moderation, get_sig_pk(gconn->addr.public_key));
+ return mod_list_verify_sig_pk(&chat->moderation, get_sig_pk(&gconn->addr.public_key));
}
/** @brief Iterates through the peerlist and updates group roles according to the
@@ -977,7 +1034,7 @@ static void update_gc_peer_roles(GC_Chat *chat)
continue;
}
- const uint8_t first_byte = gconn->addr.public_key[0];
+ const uint8_t first_byte = gconn->addr.public_key.enc[0];
const bool is_founder = peer_is_founder(chat, i);
if (is_founder) {
@@ -1059,43 +1116,16 @@ static bool prune_gc_mod_list(GC_Chat *chat)
&& update_gc_topic(chat, public_sig_key);
}
-/** @brief Removes the first found offline sanctioned peer from the sanctions list and sends the
- * event to the rest of the group.
- *
- * @retval false on failure or if no presently sanctioned peer is offline.
- */
non_null()
-static bool prune_gc_sanctions_list(GC_Chat *chat)
+static bool prune_gc_sanctions_list_inner(
+ GC_Chat *chat, const Mod_Sanction *sanction,
+ const uint8_t target_ext_pk[ENC_PUBLIC_KEY_SIZE + SIG_PUBLIC_KEY_SIZE])
{
- if (chat->moderation.num_sanctions == 0) {
- return true;
- }
-
- const Mod_Sanction *sanction = nullptr;
- uint8_t target_ext_pk[ENC_PUBLIC_KEY_SIZE + SIG_PUBLIC_KEY_SIZE];
-
- for (uint16_t i = 0; i < chat->moderation.num_sanctions; ++i) {
- const int peer_number = get_peer_number_of_enc_pk(chat, chat->moderation.sanctions[i].target_public_enc_key, true);
-
- if (peer_number == -1) {
- sanction = &chat->moderation.sanctions[i];
- memcpy(target_ext_pk, sanction->target_public_enc_key, ENC_PUBLIC_KEY_SIZE);
- memcpy(target_ext_pk + ENC_PUBLIC_KEY_SIZE, sanction->setter_public_sig_key, SIG_PUBLIC_KEY_SIZE);
- break;
- }
- }
-
- if (sanction == nullptr) {
- return false;
- }
-
if (!sanctions_list_remove_observer(&chat->moderation, sanction->target_public_enc_key, nullptr)) {
LOGGER_WARNING(chat->log, "Failed to remove entry from observer list");
return false;
}
- sanction = nullptr;
-
uint8_t data[MOD_SANCTIONS_CREDS_SIZE];
const uint16_t length = sanctions_creds_pack(&chat->moderation.sanctions_creds, data);
@@ -1112,6 +1142,33 @@ static bool prune_gc_sanctions_list(GC_Chat *chat)
return true;
}
+/** @brief Removes the first found offline sanctioned peer from the sanctions list and sends the
+ * event to the rest of the group.
+ *
+ * @retval false on failure or if no presently sanctioned peer is offline.
+ */
+non_null()
+static bool prune_gc_sanctions_list(GC_Chat *chat)
+{
+ if (chat->moderation.num_sanctions == 0) {
+ return true;
+ }
+
+ for (uint16_t i = 0; i < chat->moderation.num_sanctions; ++i) {
+ const int peer_number = get_peer_number_of_enc_pk(chat, chat->moderation.sanctions[i].target_public_enc_key, true);
+
+ if (peer_number == -1) {
+ const Mod_Sanction *sanction = &chat->moderation.sanctions[i];
+ uint8_t target_ext_pk[ENC_PUBLIC_KEY_SIZE + SIG_PUBLIC_KEY_SIZE];
+ memcpy(target_ext_pk, sanction->target_public_enc_key, ENC_PUBLIC_KEY_SIZE);
+ memcpy(target_ext_pk + ENC_PUBLIC_KEY_SIZE, sanction->setter_public_sig_key, SIG_PUBLIC_KEY_SIZE);
+ return prune_gc_sanctions_list_inner(chat, sanction, target_ext_pk);
+ }
+ }
+
+ return false;
+}
+
/** @brief Size of peer data that we pack for transfer (nick length must be accounted for separately).
* packed data consists of: nick length, nick, and status.
*/
@@ -1188,8 +1245,10 @@ static uint16_t pack_gc_shared_state(uint8_t *data, uint16_t length, const GC_Sh
net_pack_u32(data + packed_len, shared_state->version);
packed_len += sizeof(uint32_t);
- memcpy(data + packed_len, shared_state->founder_public_key, EXT_PUBLIC_KEY_SIZE);
- packed_len += EXT_PUBLIC_KEY_SIZE;
+ memcpy(data + packed_len, shared_state->founder_public_key.enc, ENC_PUBLIC_KEY_SIZE);
+ packed_len += ENC_PUBLIC_KEY_SIZE;
+ memcpy(data + packed_len, shared_state->founder_public_key.sig, SIG_PUBLIC_KEY_SIZE);
+ packed_len += SIG_PUBLIC_KEY_SIZE;
net_pack_u16(data + packed_len, shared_state->maxpeers);
packed_len += sizeof(uint16_t);
net_pack_u16(data + packed_len, shared_state->group_name_len);
@@ -1231,8 +1290,10 @@ static uint16_t unpack_gc_shared_state(GC_SharedState *shared_state, const uint8
net_unpack_u32(data + len_processed, &shared_state->version);
len_processed += sizeof(uint32_t);
- memcpy(shared_state->founder_public_key, data + len_processed, EXT_PUBLIC_KEY_SIZE);
- len_processed += EXT_PUBLIC_KEY_SIZE;
+ memcpy(shared_state->founder_public_key.enc, data + len_processed, ENC_PUBLIC_KEY_SIZE);
+ len_processed += ENC_PUBLIC_KEY_SIZE;
+ memcpy(shared_state->founder_public_key.sig, data + len_processed, SIG_PUBLIC_KEY_SIZE);
+ len_processed += SIG_PUBLIC_KEY_SIZE;
net_unpack_u16(data + len_processed, &shared_state->maxpeers);
len_processed += sizeof(uint16_t);
net_unpack_u16(data + len_processed, &shared_state->group_name_len);
@@ -1258,8 +1319,8 @@ static uint16_t unpack_gc_shared_state(GC_SharedState *shared_state, const uint8
memcpy(&voice_state, data + len_processed, sizeof(uint8_t));
len_processed += sizeof(uint8_t);
- shared_state->voice_state = (Group_Voice_State)voice_state;
- shared_state->privacy_state = (Group_Privacy_State)privacy_state;
+ group_voice_state_from_int(voice_state, &shared_state->voice_state);
+ group_privacy_state_from_int(privacy_state, &shared_state->privacy_state);
return len_processed;
}
@@ -1356,7 +1417,7 @@ static int make_gc_shared_state_packet(const GC_Chat *chat, uint8_t *data, uint1
return -1;
}
- return (int)(header_len + packed_len);
+ return header_len + packed_len;
}
/** @brief Creates a signature for the group's shared state in packed form.
@@ -1390,7 +1451,7 @@ static bool sign_gc_shared_state(GC_Chat *chat)
}
const int ret = crypto_sign_detached(chat->shared_state_sig, nullptr, shared_state, packed_len,
- get_sig_sk(chat->chat_secret_key));
+ get_sig_sk(&chat->chat_secret_key));
if (ret != 0) {
set_gc_shared_state_version(chat, chat->shared_state.version - 1);
@@ -1416,6 +1477,9 @@ non_null(1, 2, 3, 5, 6) nullable(4)
static int group_packet_unwrap(const Logger *log, const GC_Connection *gconn, uint8_t *data, uint64_t *message_id,
uint8_t *packet_type, const uint8_t *packet, uint16_t length)
{
+ assert(data != nullptr);
+ assert(packet != nullptr);
+
if (length <= CRYPTO_NONCE_SIZE) {
LOGGER_FATAL(log, "Invalid packet length: %u", length);
return -1;
@@ -1471,9 +1535,10 @@ static int group_packet_unwrap(const Logger *log, const GC_Connection *gconn, ui
int group_packet_wrap(
const Logger *log, const Random *rng, const uint8_t *self_pk, const uint8_t *shared_key, uint8_t *packet,
uint16_t packet_size, const uint8_t *data, uint16_t length, uint64_t message_id,
- uint8_t gp_packet_type, uint8_t net_packet_type)
+ uint8_t gp_packet_type, Net_Packet_Type net_packet_type)
{
- const uint16_t padding_len = group_packet_padding_length(length);
+ const uint16_t max_packet_size = group_packet_max_packet_size(net_packet_type);
+ const uint16_t padding_len = group_packet_padding_length(length, max_packet_size);
const uint16_t min_packet_size = net_packet_type == NET_PACKET_GC_LOSSLESS
? length + padding_len + CRYPTO_MAC_SIZE + 1 + ENC_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE + GC_MESSAGE_ID_BYTES + 1
: length + padding_len + CRYPTO_MAC_SIZE + 1 + ENC_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE + 1;
@@ -1483,8 +1548,8 @@ int group_packet_wrap(
return -1;
}
- if (length > MAX_GC_PACKET_CHUNK_SIZE) {
- LOGGER_ERROR(log, "Packet payload size (%u) exceeds maximum (%u)", length, MAX_GC_PACKET_CHUNK_SIZE);
+ if (length > max_packet_size) {
+ LOGGER_ERROR(log, "Packet payload size (%u) exceeds maximum (%u)", length, max_packet_size);
return -1;
}
@@ -1496,7 +1561,7 @@ int group_packet_wrap(
assert(padding_len < packet_size);
- memset(plain, 0, padding_len);
+ memzero(plain, padding_len);
uint16_t enc_header_len = sizeof(uint8_t);
plain[padding_len] = gp_packet_type;
@@ -1551,7 +1616,7 @@ non_null()
static bool send_lossy_group_packet(const GC_Chat *chat, const GC_Connection *gconn, const uint8_t *data,
uint16_t length, uint8_t packet_type)
{
- assert(length <= MAX_GC_PACKET_CHUNK_SIZE);
+ assert(length <= MAX_GC_CUSTOM_LOSSY_PACKET_SIZE);
if (!gconn->handshaked || gconn->pending_delete) {
return false;
@@ -1569,7 +1634,7 @@ static bool send_lossy_group_packet(const GC_Chat *chat, const GC_Connection *gc
}
const int len = group_packet_wrap(
- chat->log, chat->rng, chat->self_public_key, gconn->session_shared_key, packet,
+ chat->log, chat->rng, chat->self_public_key.enc, gconn->session_shared_key, packet,
packet_size, data, length, 0, packet_type, NET_PACKET_GC_LOSSY);
if (len < 0) {
@@ -1669,7 +1734,7 @@ static bool unpack_gc_sync_announce(GC_Chat *chat, const uint8_t *data, const ui
return false;
}
- if (memcmp(announce.peer_public_key, chat->self_public_key, ENC_PUBLIC_KEY_SIZE) == 0) {
+ if (memcmp(announce.peer_public_key, chat->self_public_key.enc, ENC_PUBLIC_KEY_SIZE) == 0) {
LOGGER_WARNING(chat->log, "Attempted to unpack our own announce");
return true;
}
@@ -1738,7 +1803,7 @@ static bool unpack_gc_sync_announce(GC_Chat *chat, const uint8_t *data, const ui
* Return -1 if the group is full or the peer failed to unpack.
* Return -2 if `peer_number` does not designate a valid peer.
*/
-non_null(1, 2, 4) nullable(6)
+non_null(1, 2) nullable(4, 6)
static int handle_gc_sync_response(const GC_Session *c, GC_Chat *chat, uint32_t peer_number, const uint8_t *data,
uint16_t length, void *userdata)
{
@@ -1779,7 +1844,6 @@ non_null() static bool send_peer_mod_list(const GC_Chat *chat, GC_Connection *gc
non_null() static bool send_peer_sanctions_list(const GC_Chat *chat, GC_Connection *gconn);
non_null() static bool send_peer_topic(const GC_Chat *chat, GC_Connection *gconn);
-
/** @brief Creates a sync announce for peer designated by `gconn` and puts it in `announce`, which
* must be zeroed by the caller.
*
@@ -1993,7 +2057,6 @@ static int handle_gc_sync_request(GC_Chat *chat, uint32_t peer_number, const uin
non_null() static void copy_self(const GC_Chat *chat, GC_Peer *peer);
non_null() static bool send_gc_peer_info_request(const GC_Chat *chat, GC_Connection *gconn);
-
/** @brief Shares our TCP relays with peer and adds shared relays to our connection with them.
*
* Returns true on success or if we're not connected to any TCP relays.
@@ -2080,16 +2143,17 @@ static int handle_gc_tcp_relays(GC_Chat *chat, GC_Connection *gconn, const uint8
non_null()
static bool send_gc_invite_request(const GC_Chat *chat, GC_Connection *gconn)
{
- uint16_t length = 0;
+ if (!chat_is_password_protected(chat)) {
+ return send_lossless_group_packet(chat, gconn, nullptr, 0, GP_INVITE_REQUEST);
+ }
+
uint8_t data[sizeof(uint16_t) + MAX_GC_PASSWORD_SIZE];
- if (chat_is_password_protected(chat)) {
- net_pack_u16(data, chat->shared_state.password_length);
- length += sizeof(uint16_t);
+ net_pack_u16(data, chat->shared_state.password_length);
+ uint16_t length = sizeof(uint16_t);
- memcpy(data + length, chat->shared_state.password, MAX_GC_PASSWORD_SIZE);
- length += MAX_GC_PASSWORD_SIZE;
- }
+ memcpy(data + length, chat->shared_state.password, MAX_GC_PASSWORD_SIZE);
+ length += MAX_GC_PASSWORD_SIZE;
return send_lossless_group_packet(chat, gconn, data, length, GP_INVITE_REQUEST);
}
@@ -2181,7 +2245,7 @@ static bool send_gc_invite_response_reject(const GC_Chat *chat, const GC_Connect
* Return -3 if we fail to send an invite response.
* Return -4 if peer_number does not designate a valid peer.
*/
-non_null()
+non_null(1) nullable(3)
static int handle_gc_invite_request(GC_Chat *chat, uint32_t peer_number, const uint8_t *data, uint16_t length)
{
if (chat->shared_state.version == 0) { // we aren't synced yet; ignore request
@@ -2234,34 +2298,64 @@ FAILED_INVITE:
return ret;
}
-/** @brief Sends a lossless packet of type and length to all confirmed peers. */
+/** @brief Sends a lossless packet of type and length to all confirmed peers.
+ *
+ * Return true if packet is successfully sent to at least one peer or the
+ * group is empty.
+ */
non_null()
-static void send_gc_lossless_packet_all_peers(const GC_Chat *chat, const uint8_t *data, uint16_t length, uint8_t type)
+static bool send_gc_lossless_packet_all_peers(const GC_Chat *chat, const uint8_t *data, uint16_t length, uint8_t type)
{
+ uint32_t sent = 0;
+ uint32_t confirmed_peers = 0;
+
for (uint32_t i = 1; i < chat->numpeers; ++i) {
GC_Connection *gconn = get_gc_connection(chat, i);
assert(gconn != nullptr);
- if (gconn->confirmed) {
- send_lossless_group_packet(chat, gconn, data, length, type);
+ if (!gconn->confirmed) {
+ continue;
+ }
+
+ ++confirmed_peers;
+
+ if (send_lossless_group_packet(chat, gconn, data, length, type)) {
+ ++sent;
}
}
+
+ return sent > 0 || confirmed_peers == 0;
}
-/** @brief Sends a lossy packet of type and length to all confirmed peers. */
+/** @brief Sends a lossy packet of type and length to all confirmed peers.
+ *
+ * Return true if packet is successfully sent to at least one peer or the
+ * group is empty.
+ */
non_null()
-static void send_gc_lossy_packet_all_peers(const GC_Chat *chat, const uint8_t *data, uint16_t length, uint8_t type)
+static bool send_gc_lossy_packet_all_peers(const GC_Chat *chat, const uint8_t *data, uint16_t length, uint8_t type)
{
+ uint32_t sent = 0;
+ uint32_t confirmed_peers = 0;
+
for (uint32_t i = 1; i < chat->numpeers; ++i) {
const GC_Connection *gconn = get_gc_connection(chat, i);
assert(gconn != nullptr);
- if (gconn->confirmed) {
- send_lossy_group_packet(chat, gconn, data, length, type);
+ if (!gconn->confirmed) {
+ continue;
+ }
+
+ ++confirmed_peers;
+
+ if (send_lossy_group_packet(chat, gconn, data, length, type)) {
+ ++sent;
}
}
+
+ return sent > 0 || confirmed_peers == 0;
}
/** @brief Creates packet with broadcast header info followed by data of length.
@@ -2301,11 +2395,11 @@ static bool send_gc_broadcast_message(const GC_Chat *chat, const uint8_t *data,
const uint16_t packet_len = make_gc_broadcast_header(data, length, packet, bc_type);
- send_gc_lossless_packet_all_peers(chat, packet, packet_len, GP_BROADCAST);
+ const bool ret = send_gc_lossless_packet_all_peers(chat, packet, packet_len, GP_BROADCAST);
free(packet);
- return true;
+ return ret;
}
non_null()
@@ -2431,8 +2525,7 @@ static int handle_gc_ping(GC_Chat *chat, GC_Connection *gconn, const uint8_t *da
do_gc_peer_state_sync(chat, gconn, data, length);
if (length > GC_PING_PACKET_MIN_DATA_SIZE) {
- IP_Port ip_port;
- memset(&ip_port, 0, sizeof(IP_Port));
+ IP_Port ip_port = {{{0}}};
if (unpack_ip_port(&ip_port, data + GC_PING_PACKET_MIN_DATA_SIZE,
length - GC_PING_PACKET_MIN_DATA_SIZE, false) > 0) {
@@ -2494,7 +2587,7 @@ static int handle_gc_status(const GC_Session *c, const GC_Chat *chat, GC_Peer *p
return 0;
}
-uint8_t gc_get_status(const GC_Chat *chat, uint32_t peer_id)
+uint8_t gc_get_status(const GC_Chat *chat, GC_Peer_Id peer_id)
{
const int peer_number = get_peer_number_of_peer_id(chat, peer_id);
@@ -2507,7 +2600,7 @@ uint8_t gc_get_status(const GC_Chat *chat, uint32_t peer_id)
return peer->status;
}
-uint8_t gc_get_role(const GC_Chat *chat, uint32_t peer_id)
+uint8_t gc_get_role(const GC_Chat *chat, GC_Peer_Id peer_id)
{
const int peer_number = get_peer_number_of_peer_id(chat, peer_id);
@@ -2523,7 +2616,7 @@ uint8_t gc_get_role(const GC_Chat *chat, uint32_t peer_id)
void gc_get_chat_id(const GC_Chat *chat, uint8_t *dest)
{
if (dest != nullptr) {
- memcpy(dest, get_chat_id(chat->chat_public_key), CHAT_ID_SIZE);
+ memcpy(dest, get_chat_id(&chat->chat_public_key), CHAT_ID_SIZE);
}
}
@@ -2759,9 +2852,7 @@ static bool broadcast_gc_shared_state(const GC_Chat *chat)
return false;
}
- send_gc_lossless_packet_all_peers(chat, packet, (uint16_t)packet_len, GP_SHARED_STATE);
-
- return true;
+ return send_gc_lossless_packet_all_peers(chat, packet, (uint16_t)packet_len, GP_SHARED_STATE);
}
/** @brief Helper function for `do_gc_shared_state_changes()`.
@@ -2781,7 +2872,7 @@ static void do_privacy_state_change(const GC_Session *c, GC_Chat *chat, void *us
}
} else {
kill_group_friend_connection(c, chat);
- cleanup_gca(c->announces_list, get_chat_id(chat->chat_public_key));
+ cleanup_gca(c->announces_list, get_chat_id(&chat->chat_public_key));
chat->join_type = HJ_PRIVATE;
}
@@ -2905,7 +2996,7 @@ static int handle_gc_shared_state(const GC_Session *c, GC_Chat *chat, GC_Connect
const uint16_t ss_length = length - SIGNATURE_SIZE;
if (crypto_sign_verify_detached(signature, ss_data, GC_PACKED_SHARED_STATE_SIZE,
- get_sig_pk(chat->chat_public_key)) == -1) {
+ get_sig_pk(&chat->chat_public_key)) == -1) {
LOGGER_DEBUG(chat->log, "Failed to validate shared state signature");
return handle_gc_shared_state_error(chat, gconn);
}
@@ -2919,7 +3010,7 @@ static int handle_gc_shared_state(const GC_Session *c, GC_Chat *chat, GC_Connect
return 0;
}
- GC_SharedState old_shared_state = chat->shared_state;
+ const GC_SharedState old_shared_state = chat->shared_state;
GC_SharedState new_shared_state;
if (unpack_gc_shared_state(&new_shared_state, ss_data, ss_length) == 0) {
@@ -2934,7 +3025,7 @@ static int handle_gc_shared_state(const GC_Session *c, GC_Chat *chat, GC_Connect
if (chat->shared_state.version == 0) { // init founder public sig key in moderation object
memcpy(chat->moderation.founder_public_sig_key,
- get_sig_pk(new_shared_state.founder_public_key), SIG_PUBLIC_KEY_SIZE);
+ get_sig_pk(&new_shared_state.founder_public_key), SIG_PUBLIC_KEY_SIZE);
}
chat->shared_state = new_shared_state;
@@ -3012,7 +3103,7 @@ static int handle_gc_mod_list(const GC_Session *c, GC_Chat *chat, const uint8_t
update_gc_peer_roles(chat);
if (chat->connection_state == CS_CONNECTED && c->moderation != nullptr) {
- c->moderation(c->messenger, chat->group_number, (uint32_t) -1, (uint32_t) -1, MV_MOD, userdata);
+ c->moderation(c->messenger, chat->group_number, gc_invalid_peer_id(), gc_invalid_peer_id(), MV_MOD, userdata);
}
return 0;
@@ -3133,7 +3224,7 @@ static int handle_gc_sanctions_list(const GC_Session *c, GC_Chat *chat, const ui
if (chat->connection_state == CS_CONNECTED) {
if (c->moderation != nullptr) {
- c->moderation(c->messenger, chat->group_number, (uint32_t) -1, (uint32_t) -1, MV_OBSERVER, userdata);
+ c->moderation(c->messenger, chat->group_number, gc_invalid_peer_id(), gc_invalid_peer_id(), MV_OBSERVER, userdata);
}
}
@@ -3222,7 +3313,7 @@ static int make_gc_sanctions_list_packet(const GC_Chat *chat, uint8_t *data, uin
return -1;
}
- return (int)(length + packed_len);
+ return length + packed_len;
}
/** @brief Sends the sanctions list to peer.
@@ -3282,11 +3373,11 @@ static bool broadcast_gc_sanctions_list(const GC_Chat *chat)
return false;
}
- send_gc_lossless_packet_all_peers(chat, packet, (uint16_t)packet_len, GP_SANCTIONS_LIST);
+ const bool ret = send_gc_lossless_packet_all_peers(chat, packet, (uint16_t)packet_len, GP_SANCTIONS_LIST);
free(packet);
- return true;
+ return ret;
}
/** @brief Re-signs all sanctions list entries signed by public_sig_key and broadcasts
@@ -3328,11 +3419,11 @@ static bool broadcast_gc_mod_list(const GC_Chat *chat)
return false;
}
- send_gc_lossless_packet_all_peers(chat, packet, length, GP_MOD_LIST);
+ const bool ret = send_gc_lossless_packet_all_peers(chat, packet, length, GP_MOD_LIST);
free(packet);
- return true;
+ return ret;
}
/** @brief Sends a parting signal to the group.
@@ -3394,7 +3485,7 @@ int gc_set_self_nick(const Messenger *m, int group_number, const uint8_t *nick,
return 0;
}
-bool gc_get_peer_nick(const GC_Chat *chat, uint32_t peer_id, uint8_t *name)
+bool gc_get_peer_nick(const GC_Chat *chat, GC_Peer_Id peer_id, uint8_t *name)
{
const int peer_number = get_peer_number_of_peer_id(chat, peer_id);
@@ -3411,7 +3502,7 @@ bool gc_get_peer_nick(const GC_Chat *chat, uint32_t peer_id, uint8_t *name)
return true;
}
-int gc_get_peer_nick_size(const GC_Chat *chat, uint32_t peer_id)
+int gc_get_peer_nick_size(const GC_Chat *chat, GC_Peer_Id peer_id)
{
const int peer_number = get_peer_number_of_peer_id(chat, peer_id);
@@ -3470,12 +3561,12 @@ static int get_gc_peer_public_key(const GC_Chat *chat, uint32_t peer_number, uin
return -2;
}
- memcpy(public_key, gconn->addr.public_key, ENC_PUBLIC_KEY_SIZE);
+ memcpy(public_key, gconn->addr.public_key.enc, ENC_PUBLIC_KEY_SIZE);
return 0;
}
-int gc_get_peer_public_key_by_peer_id(const GC_Chat *chat, uint32_t peer_id, uint8_t *public_key)
+int gc_get_peer_public_key_by_peer_id(const GC_Chat *chat, GC_Peer_Id peer_id, uint8_t *public_key)
{
const int peer_number = get_peer_number_of_peer_id(chat, peer_id);
@@ -3489,17 +3580,74 @@ int gc_get_peer_public_key_by_peer_id(const GC_Chat *chat, uint32_t peer_id, uin
return -2;
}
- memcpy(public_key, gconn->addr.public_key, ENC_PUBLIC_KEY_SIZE);
+ memcpy(public_key, gconn->addr.public_key.enc, ENC_PUBLIC_KEY_SIZE);
return 0;
}
-unsigned int gc_get_peer_connection_status(const GC_Chat *chat, uint32_t peer_id)
+/** @brief Puts a string of the IP associated with `ip_port` in `ip_str` if the
+ * connection is direct, otherwise puts a placeholder in the buffer indicating that
+ * the IP cannot be displayed.
+ */
+non_null()
+static void get_gc_ip_ntoa(const IP_Port *ip_port, Ip_Ntoa *ip_str)
+{
+ net_ip_ntoa(&ip_port->ip, ip_str);
+
+ if (!ip_str->ip_is_valid) {
+ ip_str->buf[0] = '-';
+ ip_str->buf[1] = '\0';
+ ip_str->length = 1;
+ }
+}
+
+int gc_get_peer_ip_address_size(const GC_Chat *chat, GC_Peer_Id peer_id)
{
const int peer_number = get_peer_number_of_peer_id(chat, peer_id);
+ const GC_Connection *gconn = get_gc_connection(chat, peer_number);
- if (peer_number_is_self(peer_number)) { // we cannot have a connection with ourselves
- return 0;
+ if (gconn == nullptr) {
+ return -1;
+ }
+
+ const IP_Port *ip_port = peer_number == 0 ? &chat->self_ip_port : &gconn->addr.ip_port;
+
+ Ip_Ntoa ip_str;
+ get_gc_ip_ntoa(ip_port, &ip_str);
+
+ return ip_str.length;
+}
+
+int gc_get_peer_ip_address(const GC_Chat *chat, GC_Peer_Id peer_id, uint8_t *ip_addr)
+{
+ const int peer_number = get_peer_number_of_peer_id(chat, peer_id);
+ const GC_Connection *gconn = get_gc_connection(chat, peer_number);
+
+ if (gconn == nullptr) {
+ return -1;
+ }
+
+ if (ip_addr == nullptr) {
+ return -2;
+ }
+
+ const IP_Port *ip_port = peer_number == 0 ? &chat->self_ip_port : &gconn->addr.ip_port;
+
+ Ip_Ntoa ip_str;
+ get_gc_ip_ntoa(ip_port, &ip_str);
+
+ assert(ip_str.length <= IP_NTOA_LEN);
+ memcpy(ip_addr, ip_str.buf, ip_str.length);
+
+ return 0;
+}
+
+unsigned int gc_get_peer_connection_status(const GC_Chat *chat, GC_Peer_Id peer_id)
+{
+ const int peer_number = get_peer_number_of_peer_id(chat, peer_id);
+
+ if (peer_number_is_self(peer_number)) {
+ return chat->self_udp_status == SELF_UDP_STATUS_NONE ? 1 : 2;
}
const GC_Connection *gconn = get_gc_connection(chat, peer_number);
@@ -3632,11 +3780,11 @@ static bool broadcast_gc_topic(const GC_Chat *chat)
return false;
}
- send_gc_lossless_packet_all_peers(chat, packet, packet_buf_size, GP_TOPIC);
+ const bool ret = send_gc_lossless_packet_all_peers(chat, packet, packet_buf_size, GP_TOPIC);
free(packet);
- return true;
+ return ret;
}
int gc_set_topic(GC_Chat *chat, const uint8_t *topic, uint16_t length)
@@ -3676,10 +3824,10 @@ int gc_set_topic(GC_Chat *chat, const uint8_t *topic, uint16_t length)
assert(topic != nullptr);
memcpy(chat->topic_info.topic, topic, length);
} else {
- memset(chat->topic_info.topic, 0, sizeof(chat->topic_info.topic));
+ memzero(chat->topic_info.topic, sizeof(chat->topic_info.topic));
}
- memcpy(chat->topic_info.public_sig_key, get_sig_pk(chat->self_public_key), SIG_PUBLIC_KEY_SIZE);
+ memcpy(chat->topic_info.public_sig_key, get_sig_pk(&chat->self_public_key), SIG_PUBLIC_KEY_SIZE);
chat->topic_info.checksum = get_gc_topic_checksum(&chat->topic_info);
@@ -3699,7 +3847,7 @@ int gc_set_topic(GC_Chat *chat, const uint8_t *topic, uint16_t length)
}
if (crypto_sign_detached(chat->topic_sig, nullptr, packed_topic, packet_buf_size,
- get_sig_sk(chat->self_secret_key)) == -1) {
+ get_sig_sk(&chat->self_secret_key)) == -1) {
goto ON_ERROR;
}
@@ -3746,6 +3894,7 @@ static bool update_gc_topic(GC_Chat *chat, const uint8_t *public_sig_key)
return true;
}
+ LOGGER_TRACE(chat->log, "founder is re-signing topic");
return gc_set_topic(chat, chat->topic_info.topic, chat->topic_info.length) == 0;
}
@@ -3855,7 +4004,7 @@ static int handle_gc_topic(const GC_Session *c, GC_Chat *chat, const GC_Peer *pe
if (!skip_callback && chat->connection_state == CS_CONNECTED && c->topic_change != nullptr) {
const int setter_peer_number = get_peer_number_of_sig_pk(chat, topic_info.public_sig_key);
- const uint32_t peer_id = setter_peer_number >= 0 ? chat->group[setter_peer_number].peer_id : 0;
+ const GC_Peer_Id peer_id = setter_peer_number >= 0 ? chat->group[setter_peer_number].peer_id : gc_unknown_peer_id();
c->topic_change(c->messenger, chat->group_number, peer_id, topic_info.topic, topic_info.length, userdata);
}
@@ -3914,6 +4063,11 @@ static int handle_gc_key_exchange(const GC_Chat *chat, GC_Connection *gconn, con
memcpy(response + 1, new_session_pk, ENC_PUBLIC_KEY_SIZE);
if (!send_lossless_group_packet(chat, gconn, response, sizeof(response), GP_KEY_ROTATION)) {
+ // Don't really care about zeroing the secret key here, because we failed, but
+ // we're doing it anyway for symmetry with the memzero+munlock below, where we
+ // really do care about it.
+ crypto_memzero(new_session_sk, sizeof(new_session_sk));
+ crypto_memunlock(new_session_sk, sizeof(new_session_sk));
return -3;
}
@@ -3923,6 +4077,7 @@ static int handle_gc_key_exchange(const GC_Chat *chat, GC_Connection *gconn, con
gcc_make_session_shared_key(gconn, sender_public_session_key);
+ crypto_memzero(new_session_sk, sizeof(new_session_sk));
crypto_memunlock(new_session_sk, sizeof(new_session_sk));
gconn->last_key_rotation = mono_time_get(chat->mono_time);
@@ -3960,17 +4115,11 @@ int gc_founder_set_password(GC_Chat *chat, const uint8_t *password, uint16_t pas
return -1;
}
- uint8_t *oldpasswd = nullptr;
const uint16_t oldlen = chat->shared_state.password_length;
+ uint8_t *oldpasswd = memdup(chat->shared_state.password, oldlen);
- if (oldlen > 0) {
- oldpasswd = (uint8_t *)malloc(oldlen);
-
- if (oldpasswd == nullptr) {
- return -4;
- }
-
- memcpy(oldpasswd, chat->shared_state.password, oldlen);
+ if (oldpasswd == nullptr && oldlen > 0) {
+ return -4;
}
if (!set_gc_password_local(chat, password, password_length)) {
@@ -4117,7 +4266,7 @@ static bool send_gc_set_mod(const GC_Chat *chat, const GC_Connection *gconn, boo
net_pack_bool(&data[0], add_mod);
- memcpy(data + 1, get_sig_pk(gconn->addr.public_key), SIG_PUBLIC_KEY_SIZE);
+ memcpy(data + 1, get_sig_pk(&gconn->addr.public_key), SIG_PUBLIC_KEY_SIZE);
if (!send_gc_broadcast_message(chat, data, length, GM_SET_MOD)) {
free(data);
@@ -4149,16 +4298,16 @@ static bool founder_gc_set_moderator(GC_Chat *chat, const GC_Connection *gconn,
}
}
- if (!mod_list_add_entry(&chat->moderation, get_sig_pk(gconn->addr.public_key))) {
+ if (!mod_list_add_entry(&chat->moderation, get_sig_pk(&gconn->addr.public_key))) {
return false;
}
} else {
- if (!mod_list_remove_entry(&chat->moderation, get_sig_pk(gconn->addr.public_key))) {
+ if (!mod_list_remove_entry(&chat->moderation, get_sig_pk(&gconn->addr.public_key))) {
return false;
}
- if (!update_gc_sanctions_list(chat, get_sig_pk(gconn->addr.public_key))
- || !update_gc_topic(chat, get_sig_pk(gconn->addr.public_key))) {
+ if (!update_gc_sanctions_list(chat, get_sig_pk(&gconn->addr.public_key))
+ || !update_gc_topic(chat, get_sig_pk(&gconn->addr.public_key))) {
return false;
}
}
@@ -4287,7 +4436,6 @@ static int handle_gc_set_observer(const GC_Session *c, GC_Chat *chat, uint32_t p
return -2;
}
-
if (ret == 1) {
return 0;
}
@@ -4374,7 +4522,7 @@ static bool mod_gc_set_observer(GC_Chat *chat, uint32_t peer_number, bool add_ob
Mod_Sanction sanction;
- if (!sanctions_list_make_entry(&chat->moderation, gconn->addr.public_key, &sanction, SA_OBSERVER)) {
+ if (!sanctions_list_make_entry(&chat->moderation, gconn->addr.public_key.enc, &sanction, SA_OBSERVER)) {
LOGGER_WARNING(chat->log, "sanctions_list_make_entry failed in mod_gc_set_observer");
return false;
}
@@ -4388,7 +4536,7 @@ static bool mod_gc_set_observer(GC_Chat *chat, uint32_t peer_number, bool add_ob
length += packed_len;
} else {
- if (!sanctions_list_remove_observer(&chat->moderation, gconn->addr.public_key, nullptr)) {
+ if (!sanctions_list_remove_observer(&chat->moderation, gconn->addr.public_key.enc, nullptr)) {
LOGGER_WARNING(chat->log, "failed to remove sanction");
return false;
}
@@ -4409,7 +4557,7 @@ static bool mod_gc_set_observer(GC_Chat *chat, uint32_t peer_number, bool add_ob
update_gc_peer_roles(chat);
- return send_gc_set_observer(chat, gconn->addr.public_key, sanction_data, length, add_obs);
+ return send_gc_set_observer(chat, gconn->addr.public_key.enc, sanction_data, length, add_obs);
}
/** @brief Sets the role of `peer_number` to `new_role`. If necessary this function will first
@@ -4476,7 +4624,7 @@ static bool apply_new_gc_role(GC_Chat *chat, uint32_t peer_number, Group_Role cu
return true;
}
-int gc_set_peer_role(const Messenger *m, int group_number, uint32_t peer_id, Group_Role new_role)
+int gc_set_peer_role(const Messenger *m, int group_number, GC_Peer_Id peer_id, Group_Role new_role)
{
const GC_Session *c = m->group_handler;
GC_Chat *chat = gc_get_group(c, group_number);
@@ -4672,7 +4820,7 @@ int gc_founder_set_privacy_state(const Messenger *m, int group_number, Group_Pri
}
if (new_privacy_state == GI_PRIVATE) {
- cleanup_gca(c->announces_list, get_chat_id(chat->chat_public_key));
+ cleanup_gca(c->announces_list, get_chat_id(&chat->chat_public_key));
kill_group_friend_connection(c, chat);
chat->join_type = HJ_PRIVATE;
} else {
@@ -4805,7 +4953,7 @@ static int handle_gc_message(const GC_Session *c, const GC_Chat *chat, const GC_
return 0;
}
-int gc_send_private_message(const GC_Chat *chat, uint32_t peer_id, uint8_t type, const uint8_t *message,
+int gc_send_private_message(const GC_Chat *chat, GC_Peer_Id peer_id, uint8_t type, const uint8_t *message,
uint16_t length)
{
if (length > MAX_GC_MESSAGE_SIZE) {
@@ -4896,20 +5044,10 @@ static int handle_gc_private_message(const GC_Session *c, const GC_Chat *chat, c
/** @brief Returns false if a custom packet is too large. */
static bool custom_gc_packet_length_is_valid(uint16_t length, bool lossless)
{
- if (lossless) {
- if (length > MAX_GC_CUSTOM_LOSSLESS_PACKET_SIZE) {
- return false;
- }
- } else {
- if (length > MAX_GC_CUSTOM_LOSSY_PACKET_SIZE) {
- return false;
- }
- }
-
- return true;
+ return length <= (lossless ? MAX_GC_CUSTOM_LOSSLESS_PACKET_SIZE : MAX_GC_CUSTOM_LOSSY_PACKET_SIZE);
}
-int gc_send_custom_private_packet(const GC_Chat *chat, bool lossless, uint32_t peer_id, const uint8_t *message,
+int gc_send_custom_private_packet(const GC_Chat *chat, bool lossless, GC_Peer_Id peer_id, const uint8_t *message,
uint16_t length)
{
if (!custom_gc_packet_length_is_valid(length, lossless)) {
@@ -4943,8 +5081,6 @@ int gc_send_custom_private_packet(const GC_Chat *chat, bool lossless, uint32_t p
return ret ? 0 : -5;
}
-
-
/** @brief Handles a custom private packet.
*
* @retval 0 if packet is handled correctly.
@@ -4987,13 +5123,15 @@ int gc_send_custom_packet(const GC_Chat *chat, bool lossless, const uint8_t *dat
return -3;
}
+ bool success;
+
if (lossless) {
- send_gc_lossless_packet_all_peers(chat, data, length, GP_CUSTOM_PACKET);
+ success = send_gc_lossless_packet_all_peers(chat, data, length, GP_CUSTOM_PACKET);
} else {
- send_gc_lossy_packet_all_peers(chat, data, length, GP_CUSTOM_PACKET);
+ success = send_gc_lossy_packet_all_peers(chat, data, length, GP_CUSTOM_PACKET);
}
- return 0;
+ return success ? 0 : -4;
}
/** @brief Handles a custom packet.
@@ -5093,12 +5231,12 @@ non_null()
static bool send_gc_kick_peer(const GC_Chat *chat, const GC_Connection *gconn)
{
uint8_t packet[ENC_PUBLIC_KEY_SIZE];
- memcpy(packet, gconn->addr.public_key, ENC_PUBLIC_KEY_SIZE);
+ memcpy(packet, gconn->addr.public_key.enc, ENC_PUBLIC_KEY_SIZE);
return send_gc_broadcast_message(chat, packet, ENC_PUBLIC_KEY_SIZE, GM_KICK_PEER);
}
-int gc_kick_peer(const Messenger *m, int group_number, uint32_t peer_id)
+int gc_kick_peer(const Messenger *m, int group_number, GC_Peer_Id peer_id)
{
const GC_Session *c = m->group_handler;
GC_Chat *chat = gc_get_group(c, group_number);
@@ -5211,7 +5349,7 @@ static int handle_gc_message_ack(const GC_Chat *chat, GC_Connection *gconn, cons
if (gcc_encrypt_and_send_lossless_packet(chat, gconn, gconn->send_array[idx].data,
gconn->send_array[idx].data_length,
gconn->send_array[idx].message_id,
- gconn->send_array[idx].packet_type)) {
+ gconn->send_array[idx].packet_type) == 0) {
gconn->send_array[idx].last_send_try = tm;
LOGGER_DEBUG(chat->log, "Re-sent requested packet %llu", (unsigned long long)message_id);
} else {
@@ -5250,7 +5388,7 @@ static int handle_gc_hs_response_ack(const GC_Chat *chat, GC_Connection *gconn)
return 0;
}
-int gc_set_ignore(const GC_Chat *chat, uint32_t peer_id, bool ignore)
+int gc_set_ignore(const GC_Chat *chat, GC_Peer_Id peer_id, bool ignore)
{
const int peer_number = get_peer_number_of_peer_id(chat, peer_id);
@@ -5452,12 +5590,12 @@ static int make_gc_handshake_packet(const GC_Chat *chat, const GC_Connection *gc
uint8_t request_type, uint8_t join_type, uint8_t *packet, size_t packet_size,
const Node_format *node)
{
- if (packet_size != GC_MIN_ENCRYPTED_HS_PAYLOAD_SIZE + sizeof(Node_format)) {
- LOGGER_FATAL(chat->log, "invalid packet size: %zu", packet_size);
+ if (chat == nullptr || gconn == nullptr || node == nullptr) {
return -1;
}
- if (chat == nullptr || gconn == nullptr || node == nullptr) {
+ if (packet_size != GC_MIN_ENCRYPTED_HS_PAYLOAD_SIZE + sizeof(Node_format)) {
+ LOGGER_FATAL(chat->log, "invalid packet size: %zu", packet_size);
return -1;
}
@@ -5468,7 +5606,7 @@ static int make_gc_handshake_packet(const GC_Chat *chat, const GC_Connection *gc
data[0] = handshake_type;
memcpy(data + length, gconn->session_public_key, ENC_PUBLIC_KEY_SIZE);
length += ENC_PUBLIC_KEY_SIZE;
- memcpy(data + length, get_sig_pk(chat->self_public_key), SIG_PUBLIC_KEY_SIZE);
+ memcpy(data + length, get_sig_pk(&chat->self_public_key), SIG_PUBLIC_KEY_SIZE);
length += SIG_PUBLIC_KEY_SIZE;
memcpy(data + length, &request_type, sizeof(uint8_t));
length += sizeof(uint8_t);
@@ -5484,8 +5622,8 @@ static int make_gc_handshake_packet(const GC_Chat *chat, const GC_Connection *gc
}
const int enc_len = wrap_group_handshake_packet(
- chat->log, chat->rng, chat->self_public_key, chat->self_secret_key,
- gconn->addr.public_key, packet, (uint16_t)packet_size, data, length);
+ chat->log, chat->rng, chat->self_public_key.enc, chat->self_secret_key.enc,
+ gconn->addr.public_key.enc, packet, (uint16_t)packet_size, data, length);
if (enc_len != GC_MIN_ENCRYPTED_HS_PAYLOAD_SIZE + nodes_size) {
LOGGER_WARNING(chat->log, "Failed to wrap handshake packet: %d", enc_len);
@@ -5509,8 +5647,7 @@ static bool send_gc_handshake_packet(const GC_Chat *chat, GC_Connection *gconn,
return false;
}
- Node_format node;
- memset(&node, 0, sizeof(node));
+ Node_format node = {{0}};
if (!gcc_copy_tcp_relay(chat->rng, &node, gconn)) {
LOGGER_TRACE(chat->log, "Failed to copy TCP relay during handshake (%u TCP relays)", gconn->tcp_relays_count);
@@ -5565,8 +5702,7 @@ static bool send_gc_oob_handshake_request(const GC_Chat *chat, const GC_Connecti
return false;
}
- Node_format node;
- memset(&node, 0, sizeof(node));
+ Node_format node = {{0}};
if (!gcc_copy_tcp_relay(chat->rng, &node, gconn)) {
LOGGER_WARNING(chat->log, "Failed to copy TCP relay");
@@ -5582,7 +5718,7 @@ static bool send_gc_oob_handshake_request(const GC_Chat *chat, const GC_Connecti
return false;
}
- return tcp_send_oob_packet_using_relay(chat->tcp_conn, gconn->oob_relay_pk, gconn->addr.public_key,
+ return tcp_send_oob_packet_using_relay(chat->tcp_conn, gconn->oob_relay_pk, gconn->addr.public_key.enc,
packet, (uint16_t)length) == 0;
}
@@ -5620,7 +5756,7 @@ static int handle_gc_handshake_response(const GC_Chat *chat, const uint8_t *send
gcc_make_session_shared_key(gconn, sender_session_pk);
- set_sig_pk(gconn->addr.public_key, data + ENC_PUBLIC_KEY_SIZE);
+ set_sig_pk(&gconn->addr.public_key, data + ENC_PUBLIC_KEY_SIZE);
gcc_set_recv_message_id(gconn, 2); // handshake response is always second packet
@@ -5691,13 +5827,13 @@ static int handle_gc_handshake_request(GC_Chat *chat, const IP_Port *ipp, const
return -1;
}
- if (chat->connection_O_metre >= GC_NEW_PEER_CONNECTION_LIMIT) {
+ if (chat->connection_o_metre >= GC_NEW_PEER_CONNECTION_LIMIT) {
chat->block_handshakes = true;
LOGGER_DEBUG(chat->log, "Handshake overflow. Blocking handshakes.");
return -1;
}
- ++chat->connection_O_metre;
+ ++chat->connection_o_metre;
const uint8_t *public_sig_key = data + ENC_PUBLIC_KEY_SIZE;
@@ -5779,7 +5915,7 @@ static int handle_gc_handshake_request(GC_Chat *chat, const IP_Port *ipp, const
gcc_make_session_shared_key(gconn, sender_session_pk);
- set_sig_pk(gconn->addr.public_key, public_sig_key);
+ set_sig_pk(&gconn->addr.public_key, public_sig_key);
if (join_type == HJ_PUBLIC && !is_public_chat(chat)) {
gcc_mark_for_deletion(gconn, chat->tcp_conn, GC_EXIT_TYPE_DISCONNECTED, nullptr, 0);
@@ -5815,7 +5951,7 @@ static int handle_gc_handshake_packet(GC_Chat *chat, const uint8_t *sender_pk, c
return -1;
}
- const int plain_len = unwrap_group_handshake_packet(chat->log, chat->self_secret_key, sender_pk, data,
+ const int plain_len = unwrap_group_handshake_packet(chat->log, chat->self_secret_key.enc, sender_pk, data,
data_buf_size, packet, length);
if (plain_len < GC_MIN_HS_PACKET_PAYLOAD_SIZE) {
@@ -6127,6 +6263,39 @@ static bool handle_gc_lossless_packet(const GC_Session *c, GC_Chat *chat, const
return true;
}
+non_null(1, 2, 3, 4, 6) nullable(8)
+static int handle_gc_lossy_packet_decoded(
+ const GC_Session *c, GC_Chat *chat, GC_Connection *gconn, const GC_Peer *peer,
+ uint8_t packet_type, const uint8_t *data, uint16_t payload_len, void *userdata)
+{
+ switch (packet_type) {
+ case GP_MESSAGE_ACK: {
+ return handle_gc_message_ack(chat, gconn, data, payload_len);
+ }
+
+ case GP_PING: {
+ return handle_gc_ping(chat, gconn, data, payload_len);
+ }
+
+ case GP_INVITE_RESPONSE_REJECT: {
+ return handle_gc_invite_response_reject(c, chat, data, payload_len, userdata);
+ }
+
+ case GP_CUSTOM_PACKET: {
+ return handle_gc_custom_packet(c, chat, peer, data, payload_len, false, userdata);
+ }
+
+ case GP_CUSTOM_PRIVATE_PACKET: {
+ return handle_gc_custom_private_packet(c, chat, peer, data, payload_len, false, userdata);
+ }
+
+ default: {
+ LOGGER_WARNING(chat->log, "Warning: handling invalid lossy group packet type 0x%02x", packet_type);
+ return -1;
+ }
+ }
+}
+
/** @brief Handles lossy groupchat message packets.
*
* This function assumes the length has already been validated.
@@ -6175,41 +6344,7 @@ static bool handle_gc_lossy_packet(const GC_Session *c, GC_Chat *chat, const uin
return false;
}
- int ret = -1;
- const uint16_t payload_len = (uint16_t)len;
-
- switch (packet_type) {
- case GP_MESSAGE_ACK: {
- ret = handle_gc_message_ack(chat, gconn, data, payload_len);
- break;
- }
-
- case GP_PING: {
- ret = handle_gc_ping(chat, gconn, data, payload_len);
- break;
- }
-
- case GP_INVITE_RESPONSE_REJECT: {
- ret = handle_gc_invite_response_reject(c, chat, data, payload_len, userdata);
- break;
- }
-
- case GP_CUSTOM_PACKET: {
- ret = handle_gc_custom_packet(c, chat, peer, data, payload_len, false, userdata);
- break;
- }
-
- case GP_CUSTOM_PRIVATE_PACKET: {
- ret = handle_gc_custom_private_packet(c, chat, peer, data, payload_len, false, userdata);
- break;
- }
-
- default: {
- LOGGER_WARNING(chat->log, "Warning: handling invalid lossy group packet type 0x%02x", packet_type);
- free(data);
- return false;
- }
- }
+ const int ret = handle_gc_lossy_packet_decoded(c, chat, gconn, peer, packet_type, data, (uint16_t)len, userdata);
free(data);
@@ -6245,7 +6380,7 @@ static bool group_can_handle_packets(const GC_Chat *chat)
*/
#define MIN_TCP_PACKET_SIZE (1 + ENC_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE + CRYPTO_MAC_SIZE)
non_null(1, 3) nullable(5)
-static int handle_gc_tcp_packet(void *object, int id, const uint8_t *packet, uint16_t length, void *userdata)
+static int handle_gc_tcp_packet(void *object, int crypt_connection_id, const uint8_t *packet, uint16_t length, void *userdata)
{
const Messenger *m = (Messenger *)object;
@@ -6255,13 +6390,13 @@ static int handle_gc_tcp_packet(void *object, int id, const uint8_t *packet, uin
if (length <= MIN_TCP_PACKET_SIZE) {
LOGGER_WARNING(m->log, "Got tcp packet with invalid length: %u (expected %u to %u)", length,
- MIN_TCP_PACKET_SIZE, MAX_GC_PACKET_CHUNK_SIZE + MIN_TCP_PACKET_SIZE + ENC_PUBLIC_KEY_SIZE);
+ MIN_TCP_PACKET_SIZE, MAX_GC_PACKET_INCOMING_CHUNK_SIZE + MIN_TCP_PACKET_SIZE + ENC_PUBLIC_KEY_SIZE);
return -1;
}
- if (length > MAX_GC_PACKET_CHUNK_SIZE + MIN_TCP_PACKET_SIZE + ENC_PUBLIC_KEY_SIZE) {
+ if (length > MAX_GC_PACKET_INCOMING_CHUNK_SIZE + MIN_TCP_PACKET_SIZE + ENC_PUBLIC_KEY_SIZE) {
LOGGER_WARNING(m->log, "Got tcp packet with invalid length: %u (expected %u to %u)", length,
- MIN_TCP_PACKET_SIZE, MAX_GC_PACKET_CHUNK_SIZE + MIN_TCP_PACKET_SIZE + ENC_PUBLIC_KEY_SIZE);
+ MIN_TCP_PACKET_SIZE, MAX_GC_PACKET_INCOMING_CHUNK_SIZE + MIN_TCP_PACKET_SIZE + ENC_PUBLIC_KEY_SIZE);
return -1;
}
@@ -6336,13 +6471,13 @@ static int handle_gc_tcp_oob_packet(void *object, const uint8_t *public_key, uns
if (length <= GC_MIN_HS_PACKET_PAYLOAD_SIZE) {
LOGGER_WARNING(m->log, "Got tcp oob packet with invalid length: %u (expected %u to %u)", length,
- GC_MIN_HS_PACKET_PAYLOAD_SIZE, MAX_GC_PACKET_CHUNK_SIZE + CRYPTO_MAC_SIZE + CRYPTO_NONCE_SIZE);
+ GC_MIN_HS_PACKET_PAYLOAD_SIZE, MAX_GC_PACKET_INCOMING_CHUNK_SIZE + CRYPTO_MAC_SIZE + CRYPTO_NONCE_SIZE);
return -1;
}
- if (length > MAX_GC_PACKET_CHUNK_SIZE + CRYPTO_MAC_SIZE + CRYPTO_NONCE_SIZE) {
+ if (length > MAX_GC_PACKET_INCOMING_CHUNK_SIZE + CRYPTO_MAC_SIZE + CRYPTO_NONCE_SIZE) {
LOGGER_WARNING(m->log, "Got tcp oob packet with invalid length: %u (expected %u to %u)", length,
- GC_MIN_HS_PACKET_PAYLOAD_SIZE, MAX_GC_PACKET_CHUNK_SIZE + CRYPTO_MAC_SIZE + CRYPTO_NONCE_SIZE);
+ GC_MIN_HS_PACKET_PAYLOAD_SIZE, MAX_GC_PACKET_INCOMING_CHUNK_SIZE + CRYPTO_MAC_SIZE + CRYPTO_NONCE_SIZE);
return -1;
}
@@ -6381,7 +6516,7 @@ static int handle_gc_tcp_oob_packet(void *object, const uint8_t *public_key, uns
#define MIN_UDP_PACKET_SIZE (1 + ENC_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE + CRYPTO_MAC_SIZE)
non_null(1, 2, 3) nullable(5)
-static int handle_gc_udp_packet(void *object, const IP_Port *ipp, const uint8_t *packet, uint16_t length,
+static int handle_gc_udp_packet(void *object, const IP_Port *source, const uint8_t *packet, uint16_t length,
void *userdata)
{
const Messenger *m = (Messenger *)object;
@@ -6392,13 +6527,13 @@ static int handle_gc_udp_packet(void *object, const IP_Port *ipp, const uint8_t
if (length <= MIN_UDP_PACKET_SIZE) {
LOGGER_WARNING(m->log, "Got UDP packet with invalid length: %u (expected %u to %u)", length,
- MIN_UDP_PACKET_SIZE, MAX_GC_PACKET_CHUNK_SIZE + MIN_UDP_PACKET_SIZE + ENC_PUBLIC_KEY_SIZE);
+ MIN_UDP_PACKET_SIZE, MAX_GC_PACKET_INCOMING_CHUNK_SIZE + MIN_UDP_PACKET_SIZE + ENC_PUBLIC_KEY_SIZE);
return -1;
}
- if (length > MAX_GC_PACKET_CHUNK_SIZE + MIN_UDP_PACKET_SIZE + ENC_PUBLIC_KEY_SIZE) {
+ if (length > MAX_GC_PACKET_INCOMING_CHUNK_SIZE + MIN_UDP_PACKET_SIZE + ENC_PUBLIC_KEY_SIZE) {
LOGGER_WARNING(m->log, "Got UDP packet with invalid length: %u (expected %u to %u)", length,
- MIN_UDP_PACKET_SIZE, MAX_GC_PACKET_CHUNK_SIZE + MIN_UDP_PACKET_SIZE + ENC_PUBLIC_KEY_SIZE);
+ MIN_UDP_PACKET_SIZE, MAX_GC_PACKET_INCOMING_CHUNK_SIZE + MIN_UDP_PACKET_SIZE + ENC_PUBLIC_KEY_SIZE);
return -1;
}
@@ -6446,7 +6581,7 @@ static int handle_gc_udp_packet(void *object, const IP_Port *ipp, const uint8_t
payload_len = payload_len - ENC_PUBLIC_KEY_SIZE;
payload = payload + ENC_PUBLIC_KEY_SIZE;
- ret = handle_gc_handshake_packet(chat, sender_pk, ipp, payload, payload_len, true, userdata) != -1;
+ ret = handle_gc_handshake_packet(chat, sender_pk, source, payload, payload_len, true, userdata) != -1;
break;
}
@@ -6577,7 +6712,7 @@ static bool peer_delete(const GC_Session *c, GC_Chat *chat, uint32_t peer_number
// We need to save some peer info for the callback before deleting it
const bool peer_confirmed = peer->gconn.confirmed;
- const uint32_t peer_id = peer->peer_id;
+ const GC_Peer_Id peer_id = peer->peer_id;
uint8_t nick[MAX_GC_NICK_SIZE];
const uint16_t nick_length = peer->nick_length;
const GC_Exit_Info exit_info = peer->gconn.exit_info;
@@ -6655,9 +6790,9 @@ int peer_add(GC_Chat *chat, const IP_Port *ipp, const uint8_t *public_key)
return -2;
}
- const uint32_t peer_id = get_new_peer_id(chat);
+ const GC_Peer_Id peer_id = get_new_peer_id(chat);
- if (peer_id == UINT32_MAX) {
+ if (!gc_peer_id_is_valid(peer_id)) {
LOGGER_WARNING(chat->log, "Failed to add peer: all peer ID's are taken?");
return -1;
}
@@ -6724,9 +6859,9 @@ int peer_add(GC_Chat *chat, const IP_Port *ipp, const uint8_t *public_key)
create_gc_session_keypair(chat->log, chat->rng, gconn->session_public_key, gconn->session_secret_key);
if (peer_number > 0) {
- memcpy(gconn->addr.public_key, public_key, ENC_PUBLIC_KEY_SIZE); // we get the sig key in the handshake
+ memcpy(gconn->addr.public_key.enc, public_key, ENC_PUBLIC_KEY_SIZE); // we get the sig key in the handshake
} else {
- memcpy(gconn->addr.public_key, chat->self_public_key, EXT_PUBLIC_KEY_SIZE);
+ gconn->addr.public_key = chat->self_public_key;
}
const uint64_t tm = mono_time_get(chat->mono_time);
@@ -6738,9 +6873,9 @@ int peer_add(GC_Chat *chat, const IP_Port *ipp, const uint8_t *public_key)
gconn->tcp_connection_num = tcp_connection_num;
gconn->last_sent_ip_time = tm;
gconn->last_sent_ping_time = tm - (GC_PING_TIMEOUT / 2) + (peer_number % (GC_PING_TIMEOUT / 2));
- gconn->self_is_closer = id_closest(get_chat_id(chat->chat_public_key),
- get_enc_key(chat->self_public_key),
- get_enc_key(gconn->addr.public_key)) == 1;
+ gconn->self_is_closer = id_closest(get_chat_id(&chat->chat_public_key),
+ get_enc_key(&chat->self_public_key),
+ get_enc_key(&gconn->addr.public_key)) == 1;
return peer_number;
}
@@ -6884,23 +7019,30 @@ non_null(1, 2) nullable(3)
static void do_peer_delete(const GC_Session *c, GC_Chat *chat, void *userdata)
{
for (uint32_t i = 1; i < chat->numpeers; ++i) {
- const GC_Connection *gconn = get_gc_connection(chat, i);
+ GC_Connection *gconn = get_gc_connection(chat, i);
assert(gconn != nullptr);
- if (gconn->pending_delete) {
- const GC_Exit_Info *exit_info = &gconn->exit_info;
+ if (!gconn->pending_delete) {
+ continue;
+ }
- if (exit_info->exit_type == GC_EXIT_TYPE_TIMEOUT && gconn->confirmed) {
- add_gc_peer_timeout_list(chat, gconn);
- }
+ if (!gconn->delete_this_iteration) {
+ gconn->delete_this_iteration = true;
+ continue;
+ }
- if (!peer_delete(c, chat, i, userdata)) {
- LOGGER_ERROR(chat->log, "Failed to delete peer %u", i);
- }
+ const GC_Exit_Info *exit_info = &gconn->exit_info;
- if (i >= chat->numpeers) {
- break;
- }
+ if (exit_info->exit_type == GC_EXIT_TYPE_TIMEOUT && gconn->confirmed) {
+ add_gc_peer_timeout_list(chat, gconn);
+ }
+
+ if (!peer_delete(c, chat, i, userdata)) {
+ LOGGER_ERROR(chat->log, "Failed to delete peer %u", i);
+ }
+
+ if (i >= chat->numpeers) {
+ break;
}
}
}
@@ -6961,12 +7103,12 @@ static bool ping_peer(const GC_Chat *chat, const GC_Connection *gconn)
if (!send_lossy_group_packet(chat, gconn, data, packed_len, GP_PING)) {
free(data);
- return true;
+ return false;
}
free(data);
- return false;
+ return true;
}
/**
@@ -7015,7 +7157,7 @@ static void do_gc_ping_and_key_rotation(GC_Chat *chat)
non_null()
static void do_new_connection_cooldown(GC_Chat *chat)
{
- if (chat->connection_O_metre == 0) {
+ if (chat->connection_o_metre == 0) {
return;
}
@@ -7023,9 +7165,9 @@ static void do_new_connection_cooldown(GC_Chat *chat)
if (chat->connection_cooldown_timer < tm) {
chat->connection_cooldown_timer = tm;
- --chat->connection_O_metre;
+ --chat->connection_o_metre;
- if (chat->connection_O_metre == 0 && chat->block_handshakes) {
+ if (chat->connection_o_metre == 0 && chat->block_handshakes) {
chat->block_handshakes = false;
LOGGER_DEBUG(chat->log, "Unblocking handshakes");
}
@@ -7165,6 +7307,10 @@ void do_gc(GC_Session *c, void *userdata)
do_new_connection_cooldown(chat);
do_peer_delete(c, chat, userdata);
+
+ if (chat->flag_exit) { // should always come last as it modifies the chats array
+ group_delete(c, chat);
+ }
}
}
@@ -7212,7 +7358,9 @@ static int get_new_group_index(GC_Session *c)
c->chats[new_index] = empty_gc_chat;
- memset(&c->chats[new_index].saved_invites, -1, sizeof(c->chats[new_index].saved_invites));
+ for (size_t i = 0; i < sizeof(c->chats[new_index].saved_invites) / sizeof(*c->chats[new_index].saved_invites); ++i) {
+ c->chats[new_index].saved_invites[i] = -1;
+ }
++c->chats_index;
@@ -7250,7 +7398,7 @@ static bool init_gc_tcp_connection(const GC_Session *c, GC_Chat *chat)
{
const Messenger *m = c->messenger;
- chat->tcp_conn = new_tcp_connections(chat->log, chat->rng, m->ns, chat->mono_time, chat->self_secret_key,
+ chat->tcp_conn = new_tcp_connections(chat->log, chat->mem, chat->rng, m->ns, chat->mono_time, chat->self_secret_key.enc,
&m->options.proxy_info);
if (chat->tcp_conn == nullptr) {
@@ -7267,7 +7415,7 @@ static bool init_gc_tcp_connection(const GC_Session *c, GC_Chat *chat)
/** Initializes default shared state values. */
non_null()
-static void init_gc_shared_state(GC_Chat *chat, const Group_Privacy_State privacy_state)
+static void init_gc_shared_state(GC_Chat *chat, Group_Privacy_State privacy_state)
{
chat->shared_state.maxpeers = MAX_GC_PEERS_DEFAULT;
chat->shared_state.privacy_state = privacy_state;
@@ -7283,7 +7431,7 @@ non_null()
static bool init_gc_shared_state_founder(GC_Chat *chat, Group_Privacy_State privacy_state, const uint8_t *group_name,
uint16_t name_length)
{
- memcpy(chat->shared_state.founder_public_key, chat->self_public_key, EXT_PUBLIC_KEY_SIZE);
+ chat->shared_state.founder_public_key = chat->self_public_key;
memcpy(chat->shared_state.group_name, group_name, name_length);
chat->shared_state.group_name_len = name_length;
chat->shared_state.privacy_state = privacy_state;
@@ -7300,11 +7448,12 @@ non_null()
static void init_gc_moderation(GC_Chat *chat)
{
memcpy(chat->moderation.founder_public_sig_key,
- get_sig_pk(chat->shared_state.founder_public_key), SIG_PUBLIC_KEY_SIZE);
- memcpy(chat->moderation.self_public_sig_key, get_sig_pk(chat->self_public_key), SIG_PUBLIC_KEY_SIZE);
- memcpy(chat->moderation.self_secret_sig_key, get_sig_pk(chat->self_secret_key), SIG_SECRET_KEY_SIZE);
+ get_sig_pk(&chat->shared_state.founder_public_key), SIG_PUBLIC_KEY_SIZE);
+ memcpy(chat->moderation.self_public_sig_key, get_sig_pk(&chat->self_public_key), SIG_PUBLIC_KEY_SIZE);
+ memcpy(chat->moderation.self_secret_sig_key, get_sig_sk(&chat->self_secret_key), SIG_SECRET_KEY_SIZE);
chat->moderation.shared_state_version = chat->shared_state.version;
chat->moderation.log = chat->log;
+ chat->moderation.mem = chat->mem;
}
non_null()
@@ -7332,6 +7481,7 @@ static int create_new_group(GC_Session *c, const uint8_t *nick, size_t nick_leng
GC_Chat *chat = &c->chats[group_number];
chat->log = m->log;
+ chat->mem = m->mem;
chat->rng = m->rng;
const uint64_t tm = mono_time_get(m->mono_time);
@@ -7350,12 +7500,15 @@ static int create_new_group(GC_Session *c, const uint8_t *nick, size_t nick_leng
return -1;
}
+ init_gc_shared_state(chat, privacy_state);
+ init_gc_moderation(chat);
+
if (!init_gc_tcp_connection(c, chat)) {
group_delete(c, chat);
return -1;
}
- if (peer_add(chat, nullptr, chat->self_public_key) != 0) { /* you are always peer_number/index 0 */
+ if (peer_add(chat, nullptr, chat->self_public_key.enc) != 0) { /* you are always peer_number/index 0 */
group_delete(c, chat);
return -1;
}
@@ -7368,10 +7521,7 @@ static int create_new_group(GC_Session *c, const uint8_t *nick, size_t nick_leng
self_gc_set_status(chat, GS_NONE);
self_gc_set_role(chat, founder ? GR_FOUNDER : GR_USER);
self_gc_set_confirmed(chat, true);
- self_gc_set_ext_public_key(chat, chat->self_public_key);
-
- init_gc_shared_state(chat, privacy_state);
- init_gc_moderation(chat);
+ self_gc_set_ext_public_key(chat, &chat->self_public_key);
return group_number;
}
@@ -7476,10 +7626,15 @@ int gc_group_load(GC_Session *c, Bin_Unpack *bu)
chat->net = m->net;
chat->mono_time = m->mono_time;
chat->log = m->log;
+ chat->mem = m->mem;
chat->rng = m->rng;
chat->last_ping_interval = tm;
chat->friend_connection_id = -1;
+ // Initialise these first, because we may need to log/dealloc things on cleanup.
+ chat->moderation.log = m->log;
+ chat->moderation.mem = m->mem;
+
if (!gc_load_unpack_group(chat, bu)) {
LOGGER_ERROR(chat->log, "Failed to unpack group");
return -1;
@@ -7505,8 +7660,8 @@ int gc_group_load(GC_Session *c, Bin_Unpack *bu)
return group_number;
}
-int gc_group_add(GC_Session *c, Group_Privacy_State privacy_state, const uint8_t *group_name,
- uint16_t group_name_length,
+int gc_group_add(GC_Session *c, Group_Privacy_State privacy_state,
+ const uint8_t *group_name, uint16_t group_name_length,
const uint8_t *nick, size_t nick_length)
{
if (group_name_length > MAX_GC_GROUP_NAME_SIZE) {
@@ -7537,9 +7692,9 @@ int gc_group_add(GC_Session *c, Group_Privacy_State privacy_state, const uint8_t
return -3;
}
- crypto_memlock(chat->chat_secret_key, sizeof(chat->chat_secret_key));
+ crypto_memlock(&chat->chat_secret_key, sizeof(chat->chat_secret_key));
- create_extended_keypair(chat->chat_public_key, chat->chat_secret_key);
+ create_extended_keypair(&chat->chat_public_key, &chat->chat_secret_key, chat->rng);
if (!init_gc_shared_state_founder(chat, privacy_state, group_name, group_name_length)) {
group_delete(c, chat);
@@ -7604,7 +7759,7 @@ int gc_group_join(GC_Session *c, const uint8_t *chat_id, const uint8_t *nick, si
return -1;
}
- if (!expand_chat_id(chat->chat_public_key, chat_id)) {
+ if (!expand_chat_id(&chat->chat_public_key, chat_id)) {
group_delete(c, chat);
return -1;
}
@@ -7636,7 +7791,9 @@ bool gc_disconnect_from_group(const GC_Session *c, GC_Chat *chat)
chat->connection_state = CS_DISCONNECTED;
- send_gc_broadcast_message(chat, nullptr, 0, GM_PEER_EXIT);
+ if (!send_gc_broadcast_message(chat, nullptr, 0, GM_PEER_EXIT)) {
+ LOGGER_DEBUG(chat->log, "Failed to broadcast group exit packet");
+ }
for (uint32_t i = 1; i < chat->numpeers; ++i) {
GC_Connection *gconn = get_gc_connection(chat, i);
@@ -7712,13 +7869,12 @@ int gc_invite_friend(const GC_Session *c, GC_Chat *chat, int32_t friend_number,
packet[0] = GP_FRIEND_INVITE;
packet[1] = GROUP_INVITE;
- memcpy(packet + 2, get_chat_id(chat->chat_public_key), CHAT_ID_SIZE);
+ memcpy(packet + 2, get_chat_id(&chat->chat_public_key), CHAT_ID_SIZE);
uint16_t length = 2 + CHAT_ID_SIZE;
- memcpy(packet + length, chat->self_public_key, ENC_PUBLIC_KEY_SIZE);
+ memcpy(packet + length, chat->self_public_key.enc, ENC_PUBLIC_KEY_SIZE);
length += ENC_PUBLIC_KEY_SIZE;
-
memcpy(packet + length, chat->shared_state.group_name, group_name_length);
length += group_name_length;
@@ -7759,10 +7915,10 @@ static int send_gc_invite_accepted_packet(const Messenger *m, const GC_Chat *cha
packet[0] = GP_FRIEND_INVITE;
packet[1] = GROUP_INVITE_ACCEPTED;
- memcpy(packet + 2, get_chat_id(chat->chat_public_key), CHAT_ID_SIZE);
+ memcpy(packet + 2, get_chat_id(&chat->chat_public_key), CHAT_ID_SIZE);
uint16_t length = 2 + CHAT_ID_SIZE;
- memcpy(packet + length, chat->self_public_key, ENC_PUBLIC_KEY_SIZE);
+ memcpy(packet + length, chat->self_public_key.enc, ENC_PUBLIC_KEY_SIZE);
length += ENC_PUBLIC_KEY_SIZE;
if (!send_group_invite_packet(m, friend_number, packet, length)) {
@@ -7982,7 +8138,7 @@ bool handle_gc_invite_accepted_packet(const GC_Session *c, int friend_number, co
uint8_t out_data[GC_JOIN_DATA_LENGTH + (GCC_MAX_TCP_SHARED_RELAYS * PACKED_NODE_SIZE_IP6)];
memcpy(out_data, chat_id, CHAT_ID_SIZE);
- memcpy(out_data + CHAT_ID_SIZE, chat->self_public_key, ENC_PUBLIC_KEY_SIZE);
+ memcpy(out_data + CHAT_ID_SIZE, chat->self_public_key.enc, ENC_PUBLIC_KEY_SIZE);
if (num_tcp_relays > 0) {
const uint32_t tcp_relays_added = add_gc_tcp_relays(chat, gconn, tcp_relays, num_tcp_relays);
@@ -8039,7 +8195,7 @@ int gc_accept_invite(GC_Session *c, int32_t friend_number, const uint8_t *data,
return -2;
}
- if (!expand_chat_id(chat->chat_public_key, chat_id)) {
+ if (!expand_chat_id(&chat->chat_public_key, chat_id)) {
group_delete(c, chat);
return -2;
}
@@ -8093,7 +8249,7 @@ GC_Session *new_dht_groupchats(Messenger *m)
return c;
}
-static void group_cleanup(GC_Session *c, GC_Chat *chat)
+static void group_cleanup(const GC_Session *c, GC_Chat *chat)
{
kill_group_friend_connection(c, chat);
@@ -8111,8 +8267,8 @@ static void group_cleanup(GC_Session *c, GC_Chat *chat)
chat->group = nullptr;
}
- crypto_memunlock(chat->self_secret_key, sizeof(chat->self_secret_key));
- crypto_memunlock(chat->chat_secret_key, sizeof(chat->chat_secret_key));
+ crypto_memunlock(&chat->self_secret_key, sizeof(chat->self_secret_key));
+ crypto_memunlock(&chat->chat_secret_key, sizeof(chat->chat_secret_key));
crypto_memunlock(chat->shared_state.password, sizeof(chat->shared_state.password));
}
@@ -8143,14 +8299,21 @@ static void group_delete(GC_Session *c, GC_Chat *chat)
c->chats_index = i;
if (!realloc_groupchats(c, c->chats_index)) {
- LOGGER_ERROR(chat->log, "Failed to reallocate groupchats array");
+ LOGGER_ERROR(c->messenger->log, "Failed to reallocate groupchats array");
}
}
}
int gc_group_exit(GC_Session *c, GC_Chat *chat, const uint8_t *message, uint16_t length)
{
- const int ret = group_can_handle_packets(chat) ? send_gc_self_exit(chat, message, length) : 0;
+ chat->flag_exit = true;
+ return group_can_handle_packets(chat) ? send_gc_self_exit(chat, message, length) : 0;
+}
+
+non_null()
+static int kill_group(GC_Session *c, GC_Chat *chat)
+{
+ const int ret = gc_group_exit(c, chat, nullptr, 0);
group_delete(c, chat);
return ret;
}
@@ -8168,11 +8331,9 @@ void kill_dht_groupchats(GC_Session *c)
continue;
}
- if (group_can_handle_packets(chat)) {
- send_gc_self_exit(chat, nullptr, 0);
+ if (kill_group(c, chat) != 0) {
+ LOGGER_WARNING(c->messenger->log, "Failed to send group exit packet");
}
-
- group_cleanup(c, chat);
}
networking_registerhandler(c->messenger->net, NET_PACKET_GC_LOSSY, nullptr, nullptr);
@@ -8236,7 +8397,7 @@ GC_Chat *gc_get_group_by_public_key(const GC_Session *c, const uint8_t *public_k
continue;
}
- if (memcmp(public_key, get_chat_id(chat->chat_public_key), CHAT_ID_SIZE) == 0) {
+ if (memcmp(public_key, get_chat_id(&chat->chat_public_key), CHAT_ID_SIZE) == 0) {
return chat;
}
}
@@ -8254,7 +8415,7 @@ static bool group_exists(const GC_Session *c, const uint8_t *chat_id)
continue;
}
- if (memcmp(get_chat_id(chat->chat_public_key), chat_id, CHAT_ID_SIZE) == 0) {
+ if (memcmp(get_chat_id(&chat->chat_public_key), chat_id, CHAT_ID_SIZE) == 0) {
return true;
}
}
@@ -8280,10 +8441,10 @@ static void create_gc_session_keypair(const Logger *log, const Random *rng, uint
non_null()
static bool create_new_chat_ext_keypair(GC_Chat *chat)
{
- crypto_memlock(chat->self_secret_key, sizeof(chat->self_secret_key));
+ crypto_memlock(&chat->self_secret_key, sizeof(chat->self_secret_key));
- if (!create_extended_keypair(chat->self_public_key, chat->self_secret_key)) {
- crypto_memunlock(chat->self_secret_key, sizeof(chat->self_secret_key));
+ if (!create_extended_keypair(&chat->self_public_key, &chat->self_secret_key, chat->rng)) {
+ crypto_memunlock(&chat->self_secret_key, sizeof(chat->self_secret_key));
return false;
}
@@ -8407,4 +8568,3 @@ int gc_add_peers_from_announces(GC_Chat *chat, const GC_Announce *announces, uin
return added_peers;
}
-#endif // VANILLA_NACL