Squashed 'external/toxcore/c-toxcore/' changes from 1828c5356..c9cdae001

c9cdae001 fix(toxav): remove extra copy of video frame on encode
4f6d4546b test: Improve the fake network library.
a2581e700 refactor(toxcore): generate `Friend_Request` and `Dht_Nodes_Response`
2aaa11770 refactor(toxcore): use Tox_Memory in generated events
5c367452b test(toxcore): fix incorrect mutex in tox_scenario_get_time
8f92e710f perf: Add a timed limit of number of cookie requests.
695b6417a test: Add some more simulated network support.
815ae9ce9 test(toxcore): fix thread-safety in scenario framework
6d85c754e test(toxcore): add unit tests for net_crypto
9c22e79cc test(support): add SimulatedEnvironment for deterministic testing
f34fcb195 chore: Update windows Dockerfile to debian stable (trixie).
ece0e8980 fix(group_moderation): allow validating unsorted sanction list signatures
a4fa754d7 refactor: rename struct Packet to struct Net_Packet
d6f330f85 cleanup: Fix some warnings from coverity.
e206bffa2 fix(group_chats): fix sync packets reverting topics
0e4715598 test: Add new scenario testing framework.
668291f44 refactor(toxcore): decouple Network_Funcs from sockaddr via IP_Port
fc4396cef fix: potential division by zero in toxav and unsafe hex parsing
8e8b352ab refactor: Add nullable annotations to struct members.
7740bb421 refactor: decouple net_crypto from DHT
1936d4296 test: add benchmark for toxav audio and video
46bfdc2df fix: correct printf format specifiers for unsigned integers
REVERT: 1828c5356 fix(toxav): remove extra copy of video frame on encode

git-subtree-dir: external/toxcore/c-toxcore
git-subtree-split: c9cdae001341e701fca980c9bb9febfeb95d2902
This commit is contained in:
Green Sky
2026-01-11 14:42:31 +01:00
parent e95f2cbb1c
commit 565efa4f39
328 changed files with 19057 additions and 13982 deletions

View File

@@ -13,7 +13,7 @@
#include <pthread.h>
#include <string.h>
#include "DHT.h"
#include "DHT.h" // Node_format
#include "LAN_discovery.h"
#include "TCP_client.h"
#include "TCP_connection.h"
@@ -35,7 +35,7 @@ typedef struct Packet_Data {
} Packet_Data;
typedef struct Packets_Array {
Packet_Data *buffer[CRYPTO_PACKET_BUFFER_SIZE];
Packet_Data *_Nullable buffer[CRYPTO_PACKET_BUFFER_SIZE];
uint32_t buffer_start;
uint32_t buffer_end; /* packet numbers in array: `{buffer_start, buffer_end)` */
} Packets_Array;
@@ -66,7 +66,7 @@ typedef struct Crypto_Connection {
uint64_t cookie_request_number; /* number used in the cookie request packets for this connection */
uint8_t dht_public_key[CRYPTO_PUBLIC_KEY_SIZE]; /* The dht public key of the peer */
uint8_t *temp_packet; /* Where the cookie request/handshake packet is stored while it is being sent. */
uint8_t *_Nullable temp_packet; /* Where the cookie request/handshake packet is stored while it is being sent. */
uint16_t temp_packet_length;
uint64_t temp_packet_sent_time; /* The time at which the last temp_packet was sent in ms. */
uint32_t temp_packet_num_sent;
@@ -81,16 +81,16 @@ typedef struct Crypto_Connection {
Packets_Array send_array;
Packets_Array recv_array;
connection_status_cb *connection_status_callback;
void *connection_status_callback_object;
connection_status_cb *_Nullable connection_status_callback;
void *_Nullable connection_status_callback_object;
int connection_status_callback_id;
connection_data_cb *connection_data_callback;
void *connection_data_callback_object;
connection_data_cb *_Nullable connection_data_callback;
void *_Nullable connection_data_callback_object;
int connection_data_callback_id;
connection_lossy_data_cb *connection_lossy_data_callback;
void *connection_lossy_data_callback_object;
connection_lossy_data_cb *_Nullable connection_lossy_data_callback;
void *_Nullable connection_lossy_data_callback_object;
int connection_lossy_data_callback_id;
uint64_t last_request_packet_sent;
@@ -124,25 +124,27 @@ typedef struct Crypto_Connection {
bool maximum_speed_reached;
dht_pk_cb *dht_pk_callback;
void *dht_pk_callback_object;
dht_pk_cb *_Nullable dht_pk_callback;
void *_Nullable dht_pk_callback_object;
uint32_t dht_pk_callback_number;
} Crypto_Connection;
static const Crypto_Connection empty_crypto_connection = {{0}};
struct Net_Crypto {
const Logger *log;
const Memory *mem;
const Random *rng;
Mono_Time *mono_time;
const Network *ns;
const Logger *_Nonnull log;
const Memory *_Nonnull mem;
const Random *_Nonnull rng;
Mono_Time *_Nonnull mono_time;
const Network *_Nonnull ns;
Networking_Core *net;
DHT *dht;
TCP_Connections *tcp_c;
void *_Nonnull dht;
const Net_Crypto_DHT_Funcs *_Nonnull dht_funcs;
Crypto_Connection *crypto_connections;
TCP_Connections *_Nonnull tcp_c;
Crypto_Connection *_Nullable crypto_connections;
uint32_t crypto_connections_length; /* Length of connections array. */
@@ -153,13 +155,17 @@ struct Net_Crypto {
/* The secret key used for cookies */
uint8_t secret_symmetric_key[CRYPTO_SYMMETRIC_KEY_SIZE];
new_connection_cb *new_connection_callback;
void *new_connection_callback_object;
new_connection_cb *_Nullable new_connection_callback;
void *_Nullable new_connection_callback_object;
/* The current optimal sleep time */
uint32_t current_sleep_time;
BS_List ip_port_list;
/* Rate limiter for cookie requests */
uint64_t cookie_request_last_time;
uint32_t cookie_request_tokens;
};
const uint8_t *nc_get_self_public_key(const Net_Crypto *c)
@@ -202,6 +208,11 @@ static bool crypt_connection_id_is_valid(const Net_Crypto *_Nonnull c, int crypt
#define COOKIE_REQUEST_LENGTH (uint16_t)(1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE + COOKIE_REQUEST_PLAIN_LENGTH + CRYPTO_MAC_SIZE)
#define COOKIE_RESPONSE_LENGTH (uint16_t)(1 + CRYPTO_NONCE_SIZE + COOKIE_LENGTH + sizeof(uint64_t) + CRYPTO_MAC_SIZE)
/** Maximum number of tokens in the bucket for cookie request rate limiting. */
#define COOKIE_REQUEST_MAX_TOKENS 10
/** Interval in milliseconds to generate one token for cookie request rate limiting. */
#define COOKIE_REQUEST_TOKEN_INTERVAL 100
/** @brief Create a cookie request packet and put it in packet.
*
* dht_public_key is the dht public key of the other
@@ -218,12 +229,16 @@ static int create_cookie_request(const Net_Crypto *_Nonnull c, uint8_t *_Nonnull
memcpy(plain, c->self_public_key, CRYPTO_PUBLIC_KEY_SIZE);
memzero(plain + CRYPTO_PUBLIC_KEY_SIZE, CRYPTO_PUBLIC_KEY_SIZE);
memcpy(plain + (CRYPTO_PUBLIC_KEY_SIZE * 2), &number, sizeof(uint64_t));
const uint8_t *tmp_shared_key = dht_get_shared_key_sent(c->dht, dht_public_key);
const uint8_t *tmp_shared_key = c->dht_funcs->get_shared_key_sent(c->dht, dht_public_key);
if (tmp_shared_key == nullptr) {
LOGGER_ERROR(c->log, "Failed to get shared key for cookie request");
return -1;
}
memcpy(shared_key, tmp_shared_key, CRYPTO_SHARED_KEY_SIZE);
uint8_t nonce[CRYPTO_NONCE_SIZE];
random_nonce(c->rng, nonce);
packet[0] = NET_PACKET_COOKIE_REQUEST;
memcpy(packet + 1, dht_get_self_public_key(c->dht), CRYPTO_PUBLIC_KEY_SIZE);
memcpy(packet + 1, c->dht_funcs->get_self_public_key(c->dht), CRYPTO_PUBLIC_KEY_SIZE);
memcpy(packet + 1 + CRYPTO_PUBLIC_KEY_SIZE, nonce, CRYPTO_NONCE_SIZE);
const int len = encrypt_data_symmetric(c->mem, shared_key, nonce, plain, sizeof(plain),
packet + 1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE);
@@ -330,12 +345,17 @@ static int handle_cookie_request(const Net_Crypto *_Nonnull c, uint8_t *_Nonnull
}
memcpy(dht_public_key, packet + 1, CRYPTO_PUBLIC_KEY_SIZE);
const uint8_t *tmp_shared_key = dht_get_shared_key_sent(c->dht, dht_public_key);
const uint8_t *tmp_shared_key = c->dht_funcs->get_shared_key_sent(c->dht, dht_public_key);
if (tmp_shared_key == nullptr) {
LOGGER_ERROR(c->log, "Failed to get shared key for cookie response");
return -1;
}
memcpy(shared_key, tmp_shared_key, CRYPTO_SHARED_KEY_SIZE);
const int len = decrypt_data_symmetric(c->mem, shared_key, packet + 1 + CRYPTO_PUBLIC_KEY_SIZE,
packet + 1 + CRYPTO_PUBLIC_KEY_SIZE + CRYPTO_NONCE_SIZE, COOKIE_REQUEST_PLAIN_LENGTH + CRYPTO_MAC_SIZE,
request_plain);
if (len != COOKIE_REQUEST_PLAIN_LENGTH) {
return -1;
}
@@ -347,7 +367,32 @@ static int handle_cookie_request(const Net_Crypto *_Nonnull c, uint8_t *_Nonnull
static int udp_handle_cookie_request(void *_Nonnull object, const IP_Port *_Nonnull source, const uint8_t *_Nonnull packet, uint16_t length,
void *_Nullable userdata)
{
const Net_Crypto *c = (const Net_Crypto *)object;
Net_Crypto *c = (Net_Crypto *)object;
const uint64_t current_time = mono_time_get_ms(c->mono_time);
// Add 1 token every 100ms
const uint64_t new_tokens = (current_time - c->cookie_request_last_time) / COOKIE_REQUEST_TOKEN_INTERVAL;
if (new_tokens > 0) {
c->cookie_request_tokens += new_tokens;
if (c->cookie_request_tokens > COOKIE_REQUEST_MAX_TOKENS) {
c->cookie_request_tokens = COOKIE_REQUEST_MAX_TOKENS;
// Full bucket, reset time anchor to now so we stop accumulating until consumed
c->cookie_request_last_time = current_time;
} else {
// Advance time anchor by the exact time consumed to generate these tokens
// to preserve the remainder (precision)
c->cookie_request_last_time += new_tokens * COOKIE_REQUEST_TOKEN_INTERVAL;
}
}
if (c->cookie_request_tokens == 0) {
return 0;
}
--c->cookie_request_tokens;
uint8_t request_plain[COOKIE_REQUEST_PLAIN_LENGTH];
uint8_t shared_key[CRYPTO_SHARED_KEY_SIZE];
uint8_t dht_public_key[CRYPTO_PUBLIC_KEY_SIZE];
@@ -505,16 +550,19 @@ static bool handle_crypto_handshake(const Net_Crypto *_Nonnull c, uint8_t *_Nonn
uint8_t *_Nonnull dht_public_key, uint8_t *_Nonnull cookie, const uint8_t *_Nonnull packet, uint16_t length, const uint8_t *_Nullable expected_real_pk)
{
if (length != HANDSHAKE_PACKET_LENGTH) {
LOGGER_WARNING(c->log, "Handshake length mismatch: %u != %u", length, (unsigned int)HANDSHAKE_PACKET_LENGTH);
return false;
}
uint8_t cookie_plain[COOKIE_DATA_LENGTH];
if (open_cookie(c->mem, c->mono_time, cookie_plain, packet + 1, c->secret_symmetric_key) != 0) {
LOGGER_WARNING(c->log, "Failed to open cookie");
return false;
}
if (expected_real_pk != nullptr && !pk_equal(cookie_plain, expected_real_pk)) {
LOGGER_WARNING(c->log, "Expected real pk mismatch");
return false;
}
@@ -527,10 +575,12 @@ static bool handle_crypto_handshake(const Net_Crypto *_Nonnull c, uint8_t *_Nonn
HANDSHAKE_PACKET_LENGTH - (1 + COOKIE_LENGTH + CRYPTO_NONCE_SIZE), plain);
if (len != sizeof(plain)) {
LOGGER_WARNING(c->log, "Failed to decrypt handshake data");
return false;
}
if (!crypto_sha512_eq(cookie_hash, plain + CRYPTO_NONCE_SIZE + CRYPTO_PUBLIC_KEY_SIZE)) {
LOGGER_WARNING(c->log, "Cookie hash mismatch");
return false;
}
@@ -2240,7 +2290,7 @@ uint32_t copy_connected_tcp_relays_index(const Net_Crypto *c, Node_format *tcp_r
return tcp_copy_connected_relays_index(c->tcp_c, tcp_relays, num, idx);
}
static void do_tcp(Net_Crypto *_Nonnull c, void *_Nonnull userdata)
static void do_tcp(Net_Crypto *_Nonnull c, void *_Nullable userdata)
{
do_tcp_connections(c->log, c->tcp_c, userdata);
@@ -2911,9 +2961,9 @@ void load_secret_key(Net_Crypto *c, const uint8_t *sk)
* Sets all the global connection variables to their default values.
*/
Net_Crypto *new_net_crypto(const Logger *log, const Memory *mem, const Random *rng, const Network *ns,
Mono_Time *mono_time, Networking_Core *net, DHT *dht, const TCP_Proxy_Info *proxy_info, Net_Profile *tcp_np)
Mono_Time *mono_time, Networking_Core *net, void *dht, const Net_Crypto_DHT_Funcs *dht_funcs, const TCP_Proxy_Info *proxy_info, Net_Profile *tcp_np)
{
if (dht == nullptr) {
if (dht == nullptr || dht_funcs == nullptr || dht_funcs->get_shared_key_sent == nullptr || dht_funcs->get_self_public_key == nullptr || dht_funcs->get_self_secret_key == nullptr) {
return nullptr;
}
@@ -2930,18 +2980,21 @@ Net_Crypto *new_net_crypto(const Logger *log, const Memory *mem, const Random *r
temp->ns = ns;
temp->net = net;
temp->tcp_c = new_tcp_connections(log, mem, rng, ns, mono_time, dht_get_self_secret_key(dht), proxy_info, tcp_np);
temp->dht = dht;
temp->dht_funcs = dht_funcs;
if (temp->tcp_c == nullptr) {
TCP_Connections *const tcp_c = new_tcp_connections(log, mem, rng, ns, mono_time, dht_funcs->get_self_secret_key(dht), proxy_info, tcp_np);
if (tcp_c == nullptr) {
mem_delete(mem, temp);
return nullptr;
}
temp->tcp_c = tcp_c;
set_packet_tcp_connection_callback(temp->tcp_c, &tcp_data_callback, temp);
set_oob_packet_tcp_connection_callback(temp->tcp_c, &tcp_oob_callback, temp);
temp->dht = dht;
new_keys(temp);
new_symmetric_key(rng, temp->secret_symmetric_key);
@@ -2954,6 +3007,9 @@ Net_Crypto *new_net_crypto(const Logger *log, const Memory *mem, const Random *r
bs_list_init(&temp->ip_port_list, mem, sizeof(IP_Port), 8, ipport_cmp_handler);
temp->cookie_request_tokens = COOKIE_REQUEST_MAX_TOKENS;
temp->cookie_request_last_time = mono_time_get_ms(mono_time);
return temp;
}
@@ -3020,3 +3076,13 @@ void kill_net_crypto(Net_Crypto *c)
crypto_memzero(c, sizeof(Net_Crypto));
mem_delete(mem, c);
}
void nc_testonly_get_secrets(const Net_Crypto *c, int conn_id, uint8_t *shared_key, uint8_t *sent_nonce, uint8_t *recv_nonce)
{
const Crypto_Connection *conn = get_crypto_connection(c, conn_id);
if (conn != nullptr) {
memcpy(shared_key, conn->shared_key, CRYPTO_SHARED_KEY_SIZE);
memcpy(sent_nonce, conn->sent_nonce, CRYPTO_NONCE_SIZE);
memcpy(recv_nonce, conn->recv_nonce, CRYPTO_NONCE_SIZE);
}
}