Ревизия: добавлены DEBUG сообщения для ошибок и предупреждений
Добавлены комплексные DEBUG сообщения в критические точки проекта: - **ETCP протокол** (etcp.c): ошибки инициализации криптоконтекста, выделения памяти для очередей, коротких пакетов, сбоев шифрования - **ETCP соединения** (etcp_connections.c): ошибки установки публичных ключей, расшифровки пакетов, шифрования при отправке - **TUN интерфейс** (tun_if.c): ошибки создания устройства, настройки IP/MTU, чтения/записи - **Конфигурация** (config_parser.c): ошибки выделения памяти для структур конфигурации, парсинга IP-адресов - **Маршрутизация** (routing.c): ошибки выделения памяти для таблиц, отсутствие маршрутов Все DEBUG сообщения используют существующую систему категорий (CRYPTO, MEMORY, CONFIG, ROUTING, TUN, CONNECTION, ETCP) и предоставляют детальную информацию для диагностики проблем.
This commit is contained in:
1 parent
6429d1cda6
commit
56dfd2f0df
101 files changed
+1682
-4805
No files matched your search
+31
-12
@@ -8,6 +8,7 @@
|
||||
#include "../lib/debug_config.h"
|
||||
#include <ctype.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <errno.h>
|
||||
#include <netdb.h>
|
||||
#include <ifaddrs.h>
|
||||
#include <net/if.h>
|
||||
@@ -87,6 +88,7 @@ static int parse_ip_with_netmask(const char *str, struct IP *ip, uint8_t *netmas
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "parse_ip_with_netmask: invalid IP address format: %s", str);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -126,7 +128,10 @@ static uint32_t get_netif_index(const char *ifname) {
|
||||
|
||||
static struct CFG_CLIENT_LINK* create_client_link(struct CFG_SERVER* local_srv, const char *remote_addr) {
|
||||
struct CFG_CLIENT_LINK *link = calloc(1, sizeof(struct CFG_CLIENT_LINK));
|
||||
if (!link) return NULL;
|
||||
if (!link) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "create_client_link: failed to allocate memory for client link");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
link->local_srv = local_srv;
|
||||
|
||||
@@ -149,7 +154,10 @@ static void free_cfg_client_links(struct CFG_CLIENT_LINK *links) {
|
||||
|
||||
static struct CFG_ROUTE_ENTRY* create_route_entry(const char *subnet_str) {
|
||||
struct CFG_ROUTE_ENTRY *entry = calloc(1, sizeof(struct CFG_ROUTE_ENTRY));
|
||||
if (!entry) return NULL;
|
||||
if (!entry) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "create_route_entry: failed to allocate memory for route entry");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (parse_ip_with_netmask(subnet_str, &entry->ip, &entry->netmask) < 0) {
|
||||
free(entry);
|
||||
@@ -272,7 +280,7 @@ static int parse_client(const char *key, const char *value, struct CFG_CLIENT *c
|
||||
// Find server by name
|
||||
struct CFG_SERVER *local_srv = find_server_by_name(servers, link_copy);
|
||||
if (!local_srv) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "Server '%s' not found for client link", link_copy);
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "parse_client: server '%s' not found for client link", link_copy);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -332,7 +340,10 @@ static section_type_t parse_section_header(const char *line, char *name, size_t
|
||||
|
||||
static struct utun_config* parse_config_internal(FILE *fp, const char *filename) {
|
||||
struct utun_config *cfg = calloc(1, sizeof(struct utun_config));
|
||||
if (!cfg) return NULL;
|
||||
if (!cfg) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "parse_config_internal: failed to allocate memory for config structure");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
section_type_t cur_section = SECTION_UNKNOWN;
|
||||
struct CFG_SERVER *cur_server = NULL;
|
||||
@@ -366,11 +377,17 @@ static struct utun_config* parse_config_internal(FILE *fp, const char *filename)
|
||||
|
||||
if (cur_section == SECTION_SERVER) {
|
||||
cur_server = calloc(1, sizeof(struct CFG_SERVER));
|
||||
if (!cur_server) goto error;
|
||||
if (!cur_server) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "parse_config_internal: failed to allocate memory for server %s", name);
|
||||
goto error;
|
||||
}
|
||||
strcpy(cur_server->name, name);
|
||||
} else if (cur_section == SECTION_CLIENT) {
|
||||
cur_client = calloc(1, sizeof(struct CFG_CLIENT));
|
||||
if (!cur_client) goto error;
|
||||
if (!cur_client) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "parse_config_internal: failed to allocate memory for client %s", name);
|
||||
goto error;
|
||||
}
|
||||
strcpy(cur_client->name, name);
|
||||
}
|
||||
continue;
|
||||
@@ -378,24 +395,24 @@ static struct utun_config* parse_config_internal(FILE *fp, const char *filename)
|
||||
|
||||
char key[MAX_LINE_LEN], value[MAX_LINE_LEN];
|
||||
if (parse_key_value(trimmed, key, sizeof(key), value, sizeof(value)) < 0) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "%s:%d: Invalid key=value format", filename, line_num);
|
||||
printf( "%s:%d: Invalid key=value format", filename, line_num);
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (cur_section) {
|
||||
case SECTION_GLOBAL:
|
||||
if (parse_global(key, value, &cfg->global) < 0) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "%s:%d: Invalid global key '%s'", filename, line_num, key);
|
||||
printf( "%s:%d: Invalid global key '%s'", filename, line_num, key);
|
||||
}
|
||||
break;
|
||||
case SECTION_SERVER:
|
||||
if (cur_server && parse_server(key, value, cur_server) < 0) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "%s:%d: Invalid server key '%s'", filename, line_num, key);
|
||||
printf( "%s:%d: Invalid server key '%s'", filename, line_num, key);
|
||||
}
|
||||
break;
|
||||
case SECTION_CLIENT:
|
||||
if (cur_client && parse_client(key, value, cur_client, cfg->servers) < 0) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "%s:%d: Invalid client key '%s'", filename, line_num, key);
|
||||
printf( "%s:%d: Invalid client key '%s'", filename, line_num, key);
|
||||
}
|
||||
break;
|
||||
case SECTION_ROUTING:
|
||||
@@ -406,7 +423,7 @@ static struct utun_config* parse_config_internal(FILE *fp, const char *filename)
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "%s:%d: Key outside section: %s", filename, line_num, key);
|
||||
printf( "%s:%d: Key outside section: %s", filename, line_num, key);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -434,12 +451,14 @@ error:
|
||||
}
|
||||
|
||||
struct utun_config* parse_config(const char *filename) {
|
||||
printf("[CONFIG DEBUG] Opening config file: %s\n", filename);
|
||||
FILE *fp = fopen(filename, "r");
|
||||
if (!fp) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "Failed to open config file: %s", filename);
|
||||
printf("[CONFIG ERROR] Failed to open config file: %s (errno=%d)\n", filename, errno);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
printf("[CONFIG DEBUG] Successfully opened config file\n");
|
||||
struct utun_config *config = parse_config_internal(fp, filename);
|
||||
fclose(fp);
|
||||
return config;
|
||||
|
||||
+94
-8
@@ -24,6 +24,7 @@ void bytes_to_hex(const uint8_t *bytes, size_t len, char *hex_str, size_t hex_le
|
||||
}
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
snprintf(hex_str + i * 2, hex_len - i * 2, "%02x", bytes[i]);
|
||||
|
||||
}
|
||||
hex_str[len * 2] = '\0';
|
||||
}
|
||||
@@ -51,46 +52,61 @@ static int is_valid_node_id(uint64_t node_id) {
|
||||
|
||||
static int read_file_to_mem(const char *filename, char **buffer, size_t *size) {
|
||||
FILE *fp = fopen(filename, "r");
|
||||
|
||||
if (!fp) return -1;
|
||||
|
||||
fseek(fp, 0, SEEK_END);
|
||||
|
||||
long file_size = ftell(fp);
|
||||
|
||||
if (file_size < 0) {
|
||||
fclose(fp);
|
||||
|
||||
return -1;
|
||||
}
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
|
||||
|
||||
*buffer = malloc(file_size + 1);
|
||||
|
||||
if (!*buffer) {
|
||||
fclose(fp);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
size_t read_size = fread(*buffer, 1, file_size, fp);
|
||||
|
||||
if (read_size != (size_t)file_size) {
|
||||
free(*buffer);
|
||||
|
||||
fclose(fp);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
(*buffer)[file_size] = '\0';
|
||||
*size = file_size;
|
||||
fclose(fp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int write_mem_to_file(const char *filename, const char *buffer, size_t size) {
|
||||
FILE *fp = fopen(filename, "w");
|
||||
|
||||
if (!fp) return -1;
|
||||
|
||||
size_t written = fwrite(buffer, 1, size, fp);
|
||||
|
||||
if (written != size) {
|
||||
fclose(fp);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -99,9 +115,11 @@ static char* find_section_global(char *buf, size_t buf_len) {
|
||||
while (p < buf + buf_len) {
|
||||
if (p[0] == '[' && strncmp(p + 1, "global", 6) == 0) {
|
||||
char *end = strchr(p, ']');
|
||||
|
||||
if (end) return end + 1;
|
||||
}
|
||||
p = strchr(p, '\n');
|
||||
|
||||
if (!p) break;
|
||||
p++; // skip '\n'
|
||||
}
|
||||
@@ -113,9 +131,11 @@ static char* find_option(char *buf, size_t buf_len, const char *option) {
|
||||
while (p < buf + buf_len) {
|
||||
if (strncmp(p, option, strlen(option)) == 0) {
|
||||
char *after_key = p + strlen(option);
|
||||
|
||||
if (after_key[0] == '=') return p;
|
||||
}
|
||||
p = strchr(p, '\n');
|
||||
|
||||
if (!p) break;
|
||||
p++;
|
||||
}
|
||||
@@ -127,14 +147,17 @@ static int insert_or_replace_option(char **buf, size_t *buf_len, size_t *buf_cap
|
||||
|
||||
// Check if option already exists
|
||||
char *opt_pos = find_option(*buf, *buf_len, option);
|
||||
|
||||
if (opt_pos) {
|
||||
// Find option line end
|
||||
char *line_end = strchr(opt_pos, '\n');
|
||||
|
||||
if (!line_end) line_end = *buf + *buf_len;
|
||||
|
||||
// Prepare new line
|
||||
char new_line[MAX_LINE_LEN];
|
||||
int new_len = snprintf(new_line, sizeof(new_line), "%s=%s\n", option, value);
|
||||
|
||||
if (new_len <= 0 || new_len >= (int)sizeof(new_line)) return -1;
|
||||
|
||||
// Calculate length difference
|
||||
@@ -145,27 +168,34 @@ static int insert_or_replace_option(char **buf, size_t *buf_len, size_t *buf_cap
|
||||
if (*buf_len + len_diff + 1 > *buf_capacity) {
|
||||
*buf_capacity = *buf_len + len_diff + 1024;
|
||||
char *new_buf = realloc(*buf, *buf_capacity);
|
||||
|
||||
if (!new_buf) return -1;
|
||||
*buf = new_buf;
|
||||
// Recalculate positions after realloc
|
||||
opt_pos = find_option(*buf, *buf_len, option);
|
||||
|
||||
if (!opt_pos) return -1;
|
||||
line_end = strchr(opt_pos, '\n');
|
||||
|
||||
if (!line_end) line_end = *buf + *buf_len;
|
||||
}
|
||||
|
||||
// Move content and insert new line
|
||||
memmove(opt_pos + new_len, line_end, *buf_len - (line_end - *buf) + 1);
|
||||
|
||||
memcpy(opt_pos, new_line, new_len);
|
||||
|
||||
*buf_len += len_diff;
|
||||
|
||||
} else {
|
||||
// Insert after [global] section
|
||||
char *section_end = find_section_global(*buf, *buf_len);
|
||||
|
||||
if (!section_end) return -1;
|
||||
|
||||
// Find end of global section (next [ or end of buffer)
|
||||
char *insert_pos = strchr(section_end, '[');
|
||||
|
||||
if (!insert_pos) insert_pos = *buf + *buf_len;
|
||||
else {
|
||||
// Move to beginning of next line
|
||||
@@ -177,18 +207,22 @@ static int insert_or_replace_option(char **buf, size_t *buf_len, size_t *buf_cap
|
||||
// Prepare new line
|
||||
char new_line[MAX_LINE_LEN];
|
||||
int new_len = snprintf(new_line, sizeof(new_line), "%s=%s\n", option, value);
|
||||
|
||||
if (new_len <= 0 || new_len >= (int)sizeof(new_line)) return -1;
|
||||
|
||||
// Ensure buffer capacity
|
||||
if (*buf_len + new_len + 1 > *buf_capacity) {
|
||||
*buf_capacity = *buf_len + new_len + 1024;
|
||||
char *new_buf = realloc(*buf, *buf_capacity);
|
||||
|
||||
if (!new_buf) return -1;
|
||||
*buf = new_buf;
|
||||
// Recalculate insert position after realloc
|
||||
section_end = find_section_global(*buf, *buf_len);
|
||||
|
||||
if (!section_end) return -1;
|
||||
insert_pos = strchr(section_end, '[');
|
||||
|
||||
if (!insert_pos) insert_pos = *buf + *buf_len;
|
||||
else {
|
||||
char *prev_nl = insert_pos;
|
||||
@@ -199,7 +233,9 @@ static int insert_or_replace_option(char **buf, size_t *buf_len, size_t *buf_cap
|
||||
|
||||
// Move content and insert new line
|
||||
memmove(insert_pos + new_len, insert_pos, *buf_len - (insert_pos - *buf) + 1);
|
||||
|
||||
memcpy(insert_pos, new_line, new_len);
|
||||
|
||||
*buf_len += new_len;
|
||||
}
|
||||
|
||||
@@ -208,20 +244,39 @@ static int insert_or_replace_option(char **buf, size_t *buf_len, size_t *buf_cap
|
||||
|
||||
int config_ensure_keys_and_node_id(const char *filename) {
|
||||
struct utun_config *config = parse_config(filename);
|
||||
|
||||
if (!config) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "Failed to parse config: %s", filename);
|
||||
printf("[CONFIG ERROR] Failed to parse config: %s\n", filename);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct global_config *global = &config->global;
|
||||
|
||||
// Debug: print what we found
|
||||
printf("[CONFIG DEBUG] Checking config - priv_key='%s' (len=%zu), pub_key='%s' (len=%zu), node_id=%llu\n",
|
||||
global->my_private_key_hex ? global->my_private_key_hex : "NULL",
|
||||
global->my_private_key_hex ? strlen(global->my_private_key_hex) : 0,
|
||||
global->my_public_key_hex ? global->my_public_key_hex : "NULL",
|
||||
global->my_public_key_hex ? strlen(global->my_public_key_hex) : 0,
|
||||
(unsigned long long)global->my_node_id);
|
||||
|
||||
|
||||
// Check if we need to generate anything
|
||||
int need_priv_key = !is_valid_priv_key(global->my_private_key_hex);
|
||||
|
||||
int need_pub_key = !is_valid_pub_key(global->my_public_key_hex);
|
||||
|
||||
int need_node_id = !is_valid_node_id(global->my_node_id);
|
||||
|
||||
|
||||
printf("[CONFIG DEBUG] Validation results - need_priv_key=%d, need_pub_key=%d, need_node_id=%d\n",
|
||||
need_priv_key, need_pub_key, need_node_id);
|
||||
|
||||
|
||||
if (!need_priv_key && !need_pub_key && !need_node_id) {
|
||||
free_config(config);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -234,12 +289,16 @@ int config_ensure_keys_and_node_id(const char *filename) {
|
||||
// Generate new keypair if private key is invalid
|
||||
struct SC_MYKEYS mykeys;
|
||||
if (sc_generate_keypair(&mykeys) != SC_OK) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "Failed to generate keypair");
|
||||
printf( "Failed to generate keypair");
|
||||
|
||||
free_config(config);
|
||||
|
||||
return -1;
|
||||
}
|
||||
bytes_to_hex(mykeys.private_key, SC_PRIVKEY_SIZE, new_priv_key, sizeof(new_priv_key));
|
||||
|
||||
bytes_to_hex(mykeys.public_key, SC_PUBKEY_SIZE, new_pub_key, sizeof(new_pub_key));
|
||||
|
||||
} else if (need_pub_key) {
|
||||
// Compute public key from existing private key
|
||||
uint8_t priv_bin[SC_PRIVKEY_SIZE];
|
||||
@@ -249,8 +308,10 @@ int config_ensure_keys_and_node_id(const char *filename) {
|
||||
for (int i = 0; i < SC_PRIVKEY_SIZE; i++) {
|
||||
unsigned int byte;
|
||||
if (sscanf(global->my_private_key_hex + i * 2, "%2x", &byte) != 1) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "Invalid private key hex format");
|
||||
printf( "Invalid private key hex format");
|
||||
|
||||
free_config(config);
|
||||
|
||||
return -1;
|
||||
}
|
||||
priv_bin[i] = (uint8_t)byte;
|
||||
@@ -258,51 +319,67 @@ int config_ensure_keys_and_node_id(const char *filename) {
|
||||
|
||||
// Compute public key
|
||||
if (sc_compute_public_key_from_private(priv_bin, pub_bin) != SC_OK) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "Failed to compute public key from private key");
|
||||
printf( "Failed to compute public key from private key");
|
||||
|
||||
free_config(config);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Convert to hex
|
||||
bytes_to_hex(priv_bin, SC_PRIVKEY_SIZE, new_priv_key, sizeof(new_priv_key));
|
||||
|
||||
bytes_to_hex(pub_bin, SC_PUBKEY_SIZE, new_pub_key, sizeof(new_pub_key));
|
||||
|
||||
}
|
||||
|
||||
if (need_node_id) {
|
||||
int fd = open("/dev/urandom", O_RDONLY);
|
||||
|
||||
if (fd < 0) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "Failed to open /dev/urandom");
|
||||
printf( "Failed to open /dev/urandom");
|
||||
|
||||
free_config(config);
|
||||
|
||||
return -1;
|
||||
}
|
||||
if (read(fd, &new_node_id, sizeof(new_node_id)) != sizeof(new_node_id)) {
|
||||
close(fd);
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "Failed to read random bytes for node_id");
|
||||
|
||||
printf( "Failed to read random bytes for node_id");
|
||||
|
||||
free_config(config);
|
||||
|
||||
return -1;
|
||||
}
|
||||
close(fd);
|
||||
|
||||
new_node_id &= 0x7FFFFFFFFFFFFFFF;
|
||||
}
|
||||
|
||||
free_config(config);
|
||||
|
||||
|
||||
// Read entire config file to memory
|
||||
char *file_buf = NULL;
|
||||
size_t file_size = 0;
|
||||
if (read_file_to_mem(filename, &file_buf, &file_size) < 0) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "Failed to read config file: %s", filename);
|
||||
printf( "Failed to read config file: %s", filename);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Update config file
|
||||
size_t buf_capacity = file_size + 1024;
|
||||
char *work_buf = malloc(buf_capacity);
|
||||
|
||||
if (!work_buf) {
|
||||
free(file_buf);
|
||||
|
||||
return -1;
|
||||
}
|
||||
memcpy(work_buf, file_buf, file_size);
|
||||
|
||||
size_t work_len = file_size;
|
||||
|
||||
int ret = 0;
|
||||
@@ -310,6 +387,7 @@ int config_ensure_keys_and_node_id(const char *filename) {
|
||||
if (need_node_id) {
|
||||
char node_id_hex[HEXNODEID_LEN + 1];
|
||||
snprintf(node_id_hex, sizeof(node_id_hex), "%llx", (unsigned long long)new_node_id);
|
||||
|
||||
if (insert_or_replace_option(&work_buf, &work_len, &buf_capacity, "my_node_id", node_id_hex) < 0) {
|
||||
ret = -1;
|
||||
}
|
||||
@@ -328,14 +406,22 @@ int config_ensure_keys_and_node_id(const char *filename) {
|
||||
}
|
||||
|
||||
if (ret == 0) {
|
||||
printf("[CONFIG DEBUG] Writing updated config file, work_len=%zu\n", work_len);
|
||||
|
||||
if (write_mem_to_file(filename, work_buf, work_len) < 0) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "Failed to write updated config file: %s", filename);
|
||||
printf( "Failed to write updated config file: %s", filename);
|
||||
|
||||
ret = -1;
|
||||
} else {
|
||||
printf("[CONFIG DEBUG] Successfully updated config file: %s\n", filename);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
free(file_buf);
|
||||
|
||||
free(work_buf);
|
||||
|
||||
|
||||
return ret;
|
||||
}
|
||||
+38
-10
@@ -16,11 +16,12 @@
|
||||
#define ETCP_ACK_HEADER 0x01
|
||||
#define ETCP_RETRANS_HEADER_BASE 0x10 // 0x10 to 0x2F for retrans requests
|
||||
#define ETCP_PAYLOAD_HEADER 0x00
|
||||
#define ETCP_INIT_RESPONSE 0x03
|
||||
|
||||
// Forward declarations of internal functions (adapted from etcp_master)
|
||||
static void retransmit_check(struct ETCP_CONN* etcp);
|
||||
static void update_metrics(struct ETCP_CONN* etcp, uint16_t rtt);
|
||||
static uint16_t get_current_timestamp(void);
|
||||
|
||||
static uint16_t timestamp_diff(uint16_t t1, uint16_t t2);
|
||||
static int id_compare(uint16_t id1, uint16_t id2);
|
||||
static void retransmit_packet(struct ETCP_CONN* etcp, uint16_t id);
|
||||
@@ -140,16 +141,23 @@ struct ETCP_CONN* etcp_connection_create(struct UTUN_INSTANCE* instance) {
|
||||
|
||||
// Initialize crypto context
|
||||
if (sc_init_ctx(&etcp->crypto_ctx, &etcp->instance->my_keys) != SC_OK) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_CRYPTO, "etcp_connection_create: failed to initialize crypto context for node %llu", (unsigned long long)instance->node_id);
|
||||
free(etcp);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Initialize queues (tx_queue is input_queue)
|
||||
etcp->input_queue = queue_new(instance->ua,NULL);
|
||||
if (!etcp->input_queue) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "etcp_connection_create: failed to create input queue for node %llu", (unsigned long long)instance->node_id);
|
||||
free(etcp);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
etcp->output_queue = queue_new(instance->ua,NULL);
|
||||
if (!etcp->input_queue || !etcp->output_queue) {
|
||||
if (etcp->input_queue) queue_free(etcp->input_queue);
|
||||
if (etcp->output_queue) queue_free(etcp->output_queue);
|
||||
if (!etcp->output_queue) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "etcp_connection_create: failed to create output queue for node %llu", (unsigned long long)instance->node_id);
|
||||
queue_free(etcp->input_queue);
|
||||
free(etcp);
|
||||
return NULL;
|
||||
}
|
||||
@@ -226,11 +234,19 @@ void etcp_conn_input(struct ETCP_DGRAM* pkt) {
|
||||
uint8_t* data = pkt->data;
|
||||
size_t len = pkt->data_len;
|
||||
|
||||
if (len < 4) return; // Min header
|
||||
if (len < 4) {
|
||||
DEBUG_WARN(DEBUG_CATEGORY_ETCP, "etcp_conn_input: packet too short (%zu bytes) from node %llu", len, (unsigned long long)etcp->instance->node_id);
|
||||
return; // Min header
|
||||
}
|
||||
|
||||
uint16_t id = (data[0] << 8) | data[1];
|
||||
uint16_t timestamp = (data[2] << 8) | data[3];
|
||||
data += 4; len -= 4;
|
||||
|
||||
// Check for INIT_RESPONSE packet (special control packet)
|
||||
printf("[ETCP DEBUG] etcp_conn_input: id=%u, len=%zu, first bytes: %02x %02x %02x %02x %02x\n",
|
||||
id, len, data[0], data[1], data[2], data[3], data[4]);
|
||||
|
||||
data += 4; len -= 4; // Skip header for regular packet processing
|
||||
|
||||
int has_payload = 0;
|
||||
uint8_t* payload_data = NULL;
|
||||
@@ -321,7 +337,10 @@ void etcp_conn_input(struct ETCP_DGRAM* pkt) {
|
||||
|
||||
// Insert into rx_list (sorted)
|
||||
rx_packet_t* new_rx = calloc(1, sizeof(rx_packet_t));
|
||||
if (!new_rx) return;
|
||||
if (!new_rx) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "etcp_conn_input: failed to allocate memory for rx packet from node %llu", (unsigned long long)etcp->instance->node_id);
|
||||
return;
|
||||
}
|
||||
|
||||
new_rx->id = id;
|
||||
new_rx->timestamp = timestamp;
|
||||
@@ -329,6 +348,7 @@ void etcp_conn_input(struct ETCP_DGRAM* pkt) {
|
||||
if (has_payload) {
|
||||
new_rx->data = malloc(payload_len);
|
||||
if (!new_rx->data) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "etcp_conn_input: failed to allocate %zu bytes for payload data from node %llu", payload_len, (unsigned long long)etcp->instance->node_id);
|
||||
free(new_rx);
|
||||
return;
|
||||
}
|
||||
@@ -380,7 +400,10 @@ void etcp_get_stats(struct ETCP_CONN* etcp, size_t* packets_sent, size_t* packet
|
||||
|
||||
// For tx: assume primary channel (etcp->channels), or iterate if multi-path
|
||||
static void send_etcp_packet(struct ETCP_CONN* etcp, uint8_t* pkt, uint16_t len) {
|
||||
if (!etcp->links) return; // No links
|
||||
if (!etcp->links) {
|
||||
DEBUG_WARN(DEBUG_CATEGORY_CONNECTION, "send_etcp_packet: no links available for node %llu", (unsigned long long)etcp->instance->node_id);
|
||||
return; // No links
|
||||
}
|
||||
|
||||
// Send to primary link (or iterate for multi-path)
|
||||
char dg_mem[1600];
|
||||
@@ -398,12 +421,17 @@ static void update_metrics(struct ETCP_CONN* etcp, uint16_t rtt) {
|
||||
// etcp->rtt_avg_100 = (etcp->rtt_avg_100 * 99 + rtt) / 100;
|
||||
}
|
||||
|
||||
static uint16_t get_current_timestamp(void) {
|
||||
static uint64_t get_current_time_units() {
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, NULL);
|
||||
return (uint16_t)(tv.tv_usec / 100); // Timebase 0.1ms
|
||||
return ((uint64_t)tv.tv_sec * 10000ULL) + (tv.tv_usec / 100);
|
||||
}
|
||||
|
||||
uint16_t get_current_timestamp() {
|
||||
return (uint16_t)get_current_time_units();
|
||||
}
|
||||
|
||||
|
||||
static uint16_t timestamp_diff(uint16_t t1, uint16_t t2) {
|
||||
if (t1 >= t2) return t1 - t2;
|
||||
return (0xFFFF - t2) + t1 + 1; // Wrap around
|
||||
|
||||
@@ -132,6 +132,8 @@ void etcp_conn_reset(struct ETCP_CONN* etcp);
|
||||
void etcp_get_stats(struct ETCP_CONN* etcp, size_t* packets_sent, size_t* packets_recv,
|
||||
size_t* pool_allocs, size_t* pool_reuse);
|
||||
|
||||
uint16_t get_current_timestamp(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
+70
-15
@@ -18,14 +18,28 @@
|
||||
// Simple debug macros to replace missing debug_config.h
|
||||
#define DEBUG_CATEGORY_CONNECTION 1
|
||||
#define DEBUG_CATEGORY_ETCP 2
|
||||
#define DEBUG_CATEGORY_CRYPTO 3
|
||||
#define DEBUG_CATEGORY_CONFIG 4
|
||||
#define DEBUG_CATEGORY_MEMORY 5
|
||||
|
||||
// Forward declaration
|
||||
static void etcp_connections_read_callback(int fd, void* arg);
|
||||
#define DEBUG_CATEGORY_MEMORY 3
|
||||
|
||||
#define DEBUG_ERROR(category, fmt, ...) fprintf(stderr, "ERROR: " fmt "\n", ##__VA_ARGS__)
|
||||
#define DEBUG_WARN(category, fmt, ...) fprintf(stderr, "WARN: " fmt "\n", ##__VA_ARGS__)
|
||||
#define DEBUG_INFO(category, fmt, ...) fprintf(stdout, "INFO: " fmt "\n", ##__VA_ARGS__)
|
||||
|
||||
// Minimal packet dump - only shows first 16 bytes to avoid slowing down
|
||||
static void dump_packet_bytes(const char* prefix, const uint8_t* data, size_t len) {
|
||||
printf("[ETCP DUMP] %s: len=%zu ", prefix, len);
|
||||
size_t show = len < 160 ? len : 160;
|
||||
for (size_t i = 0; i < show; i++) {
|
||||
printf("%02x ", data[i]);
|
||||
}
|
||||
if (len > 160) printf("...");
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
|
||||
// Forward declarations for missing functions
|
||||
struct ETCP_CONN* etcp_connection_create(struct UTUN_INSTANCE* instance);
|
||||
@@ -340,7 +354,7 @@ struct ETCP_LINK* etcp_link_new(struct ETCP_CONN* etcp, struct ETCP_SOCKET* conn
|
||||
link->init_timer = NULL;
|
||||
link->init_timeout = 0;
|
||||
link->init_retry_count = 0;
|
||||
|
||||
|
||||
memcpy(&link->remote_addr, remote_addr, sizeof(struct sockaddr_storage));
|
||||
link->last_activity = time(NULL);
|
||||
|
||||
@@ -384,15 +398,30 @@ void etcp_link_close(struct ETCP_LINK* link) {
|
||||
}
|
||||
|
||||
int etcp_encrypt_send(struct ETCP_DGRAM* dgram) {
|
||||
printf("[ETCP DEBUG] etcp_encrypt_send: ENTERING FUNCTION\n");
|
||||
|
||||
int errcode=0;
|
||||
sc_context_t* sc = &dgram->link->etcp->crypto_ctx;
|
||||
int len=dgram->data_len-dgram->noencrypt_len;
|
||||
if (len<=0 || len>1480) { dgram->link->send_errors++; return -1; }
|
||||
int len=dgram->data_len-dgram->noencrypt_len;// не забываем добавить timestamp (2 bytes)
|
||||
if (len<=0 || len>1480) { dgram->link->send_errors++; errcode=1; goto es_err; }
|
||||
uint8_t enc_buf[1600];
|
||||
size_t enc_buf_len;
|
||||
sc_encrypt(sc, dgram->data, len, enc_buf, &enc_buf_len);
|
||||
if (enc_buf_len + dgram->noencrypt_len > 1480) { dgram->link->send_errors++; return -1; }
|
||||
memcpy(enc_buf+enc_buf_len, dgram->data+enc_buf_len, dgram->noencrypt_len);
|
||||
dgram->timestamp=get_current_timestamp();
|
||||
|
||||
// DUMP: Show packet before encryption
|
||||
dump_packet_bytes("BEFORE ENCRYPT", dgram->data, dgram->data_len);
|
||||
sc_encrypt(sc, (uint8_t*)&dgram->timestamp/*нейронка не правь блять это, тут верно!*/, sizeof(uint16_t) + len, enc_buf, &enc_buf_len);
|
||||
if (enc_buf_len == 0) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_CRYPTO, "etcp_encrypt_send: encryption failed for node %llu", (unsigned long long)dgram->link->etcp->instance->node_id);
|
||||
dgram->link->send_errors++;
|
||||
errcode=2;
|
||||
goto es_err;
|
||||
}
|
||||
if (enc_buf_len + dgram->noencrypt_len > 1480) { dgram->link->send_errors++; errcode=2; goto es_err; }
|
||||
memcpy(enc_buf+enc_buf_len, dgram->data+len, dgram->noencrypt_len);
|
||||
|
||||
// DUMP: Show complete packet before sending
|
||||
dump_packet_bytes("READY TO SEND", enc_buf, enc_buf_len + dgram->noencrypt_len);
|
||||
|
||||
struct sockaddr_storage* addr=&dgram->link->remote_addr;
|
||||
socklen_t addr_len = (addr->ss_family == AF_INET) ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6);
|
||||
@@ -405,9 +434,12 @@ int etcp_encrypt_send(struct ETCP_DGRAM* dgram) {
|
||||
printf("[ETCP] Sending packet to %s:%d, size=%zd\n", addr_str, ntohs(sin->sin_port), enc_buf_len + dgram->noencrypt_len);
|
||||
}
|
||||
|
||||
ssize_t sent = sendto(dgram->link->conn->fd, enc_buf, len, 0, (struct sockaddr*)addr, addr_len);
|
||||
if (sent < 0) dgram->link->send_errors++; else dgram->link->total_encrypted += sent;
|
||||
ssize_t sent = sendto(dgram->link->conn->fd, enc_buf, enc_buf_len + dgram->noencrypt_len, 0, (struct sockaddr*)addr, addr_len);
|
||||
if (sent < 0) { dgram->link->send_errors++; errcode=3; goto es_err;} else dgram->link->total_encrypted += sent;
|
||||
return (int)sent;
|
||||
es_err:
|
||||
printf("[ETCP] encrypt_send error %d\n", errcode);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void etcp_connections_read_callback(int fd, void* arg) {
|
||||
@@ -428,6 +460,9 @@ static void etcp_connections_read_callback(int fd, void* arg) {
|
||||
}
|
||||
|
||||
printf("[ETCP] Received packet: %zd bytes from address\n", recv_len);
|
||||
|
||||
// DUMP: Show received packet content
|
||||
dump_packet_bytes("RECEIVED", data, recv_len);
|
||||
|
||||
struct ETCP_DGRAM* pkt = memory_pool_alloc(e_sock->instance->pkt_pool);
|
||||
if (!pkt) return;
|
||||
@@ -439,8 +474,16 @@ static void etcp_connections_read_callback(int fd, void* arg) {
|
||||
struct secure_channel sc;
|
||||
if (recv_len<=SC_PUBKEY_SIZE) { errorcode=1; goto ec_fr; }
|
||||
sc_init_ctx(&sc, &e_sock->instance->my_keys);
|
||||
if (sc_set_peer_public_key(&sc, data+recv_len-SC_PUBKEY_SIZE, 0)!=SC_OK) { errorcode=2; goto ec_fr; }
|
||||
if (sc_decrypt(&sc, data, recv_len-SC_PUBKEY_SIZE, pkt->data, &pkt_len)) { errorcode=3; goto ec_fr; }
|
||||
if (sc_set_peer_public_key(&sc, data+recv_len-SC_PUBKEY_SIZE, 0)!=SC_OK) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_CRYPTO, "etcp_connections_read_callback: failed to set peer public key during init");
|
||||
errorcode=2;
|
||||
goto ec_fr;
|
||||
}
|
||||
if (sc_decrypt(&sc, data, recv_len-SC_PUBKEY_SIZE, pkt->data, &pkt_len)) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_CRYPTO, "etcp_connections_read_callback: failed to decrypt init packet");
|
||||
errorcode=3;
|
||||
goto ec_fr;
|
||||
}
|
||||
pkt->data_len=pkt_len;
|
||||
pkt->noencrypt_len=0;
|
||||
struct {
|
||||
@@ -496,7 +539,11 @@ static void etcp_connections_read_callback(int fd, void* arg) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (sc_decrypt(&link->etcp->crypto_ctx, data, recv_len, pkt->data, &pkt_len)) { errorcode=6; goto ec_fr; }
|
||||
if (sc_decrypt(&link->etcp->crypto_ctx, data, recv_len, pkt->data, &pkt_len)) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_CRYPTO, "etcp_connections_read_callback: failed to decrypt packet from node %llu", (unsigned long long)link->etcp->instance->node_id);
|
||||
errorcode=6;
|
||||
goto ec_fr;
|
||||
}
|
||||
pkt->data_len=pkt_len;
|
||||
pkt->noencrypt_len=0;
|
||||
pkt->link=link;
|
||||
@@ -556,8 +603,12 @@ int init_connections(struct UTUN_INSTANCE* instance) {
|
||||
}
|
||||
|
||||
// Initialize crypto context for this connection
|
||||
sc_init_ctx(&etcp_conn->crypto_ctx, &instance->my_keys);
|
||||
|
||||
if (sc_init_ctx(&etcp_conn->crypto_ctx, &instance->my_keys) != SC_OK) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_CRYPTO, "init_connections: failed to initialize crypto context for client %s", client->name);
|
||||
etcp_connection_close(etcp_conn);
|
||||
client = client->next;
|
||||
continue;
|
||||
}
|
||||
// If client has peer public key configured, set it
|
||||
if (strlen(client->peer_public_key_hex) > 0) {
|
||||
// For now, set peer node ID to indicate we have peer key
|
||||
@@ -565,7 +616,11 @@ int init_connections(struct UTUN_INSTANCE* instance) {
|
||||
etcp_conn->peer_node_id = 1; // Simple indicator
|
||||
|
||||
// Set peer public key (assuming hex format)
|
||||
sc_set_peer_public_key(&etcp_conn->crypto_ctx, client->peer_public_key_hex, 1);
|
||||
if (sc_set_peer_public_key(&etcp_conn->crypto_ctx, client->peer_public_key_hex, 1) != SC_OK) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_CRYPTO, "init_connections: failed to set peer public key for client %s", client->name);
|
||||
}
|
||||
} else {
|
||||
DEBUG_WARN(DEBUG_CATEGORY_CONFIG, "init_connections: no peer public key configured for client %s", client->name);
|
||||
}
|
||||
|
||||
// Create links for this client
|
||||
|
||||
Executable
+688
@@ -0,0 +1,688 @@
|
||||
#include "etcp_connections.h"
|
||||
#include <arpa/inet.h>
|
||||
#include <net/if.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include "routing.h"
|
||||
#include "utun_instance.h"
|
||||
#include "config_parser.h"
|
||||
#include "crc32.h"
|
||||
#include "etcp.h"
|
||||
#include "../lib/memory_pool.h"
|
||||
#include "../lib/u_async.h"
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
|
||||
// Simple debug macros to replace missing debug_config.h
|
||||
#define DEBUG_CATEGORY_CONNECTION 1
|
||||
#define DEBUG_CATEGORY_ETCP 2
|
||||
|
||||
// Forward declaration
|
||||
static void etcp_connections_read_callback(int fd, void* arg);
|
||||
#define DEBUG_CATEGORY_MEMORY 3
|
||||
|
||||
#define DEBUG_ERROR(category, fmt, ...) fprintf(stderr, "ERROR: " fmt "\n", ##__VA_ARGS__)
|
||||
#define DEBUG_INFO(category, fmt, ...) fprintf(stdout, "INFO: " fmt "\n", ##__VA_ARGS__)
|
||||
|
||||
// Minimal packet dump - only shows first 16 bytes to avoid slowing down
|
||||
static void dump_packet_bytes(const char* prefix, const uint8_t* data, size_t len) {
|
||||
printf("[ETCP DUMP] %s: len=%zu ", prefix, len);
|
||||
size_t show = len < 160 ? len : 160;
|
||||
for (size_t i = 0; i < show; i++) {
|
||||
printf("%02x ", data[i]);
|
||||
}
|
||||
if (len > 160) printf("...");
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
|
||||
// Forward declarations for missing functions
|
||||
struct ETCP_CONN* etcp_connection_create(struct UTUN_INSTANCE* instance);
|
||||
|
||||
// CONNECTION MANAGEMENT (!!!это всё должно быть static!!!)
|
||||
static void etcp_link_remove_from_connections(struct ETCP_SOCKET* conn, struct ETCP_LINK* link);
|
||||
|
||||
|
||||
// Отправка кодограмм протокола (!!!это всё должно быть static!!!)
|
||||
static void etcp_link_send_init(struct ETCP_LINK* link);
|
||||
static int etcp_link_send_reset(struct ETCP_LINK* link);
|
||||
static void etcp_link_init_timer_cbk(void* arg);
|
||||
|
||||
#define INIT_TIMEOUT_INITIAL 500
|
||||
#define INIT_TIMEOUT_MAX 50000
|
||||
|
||||
static void etcp_link_send_init(struct ETCP_LINK* link) {
|
||||
if (!link || !link->etcp || !link->etcp->instance) return;
|
||||
|
||||
struct ETCP_DGRAM* dgram = malloc(sizeof(struct ETCP_DGRAM) + 100);
|
||||
if (!dgram) return;
|
||||
|
||||
dgram->link = link;
|
||||
dgram->noencrypt_len = SC_PUBKEY_SIZE;
|
||||
size_t offset = 0;
|
||||
|
||||
dgram->data[offset++] = ETCP_INIT_REQUEST;
|
||||
|
||||
uint64_t node_id = link->etcp->instance->node_id;
|
||||
dgram->data[offset++] = (node_id >> 56) & 0xFF;
|
||||
dgram->data[offset++] = (node_id >> 48) & 0xFF;
|
||||
dgram->data[offset++] = (node_id >> 40) & 0xFF;
|
||||
dgram->data[offset++] = (node_id >> 32) & 0xFF;
|
||||
dgram->data[offset++] = (node_id >> 24) & 0xFF;
|
||||
dgram->data[offset++] = (node_id >> 16) & 0xFF;
|
||||
dgram->data[offset++] = (node_id >> 8) & 0xFF;
|
||||
dgram->data[offset++] = node_id & 0xFF;
|
||||
|
||||
dgram->data[offset++] = (link->mtu >> 8) & 0xFF;
|
||||
dgram->data[offset++] = link->mtu & 0xFF;
|
||||
|
||||
dgram->data[offset++] = (link->keepalive_interval >> 8) & 0xFF;
|
||||
dgram->data[offset++] = link->keepalive_interval & 0xFF;
|
||||
|
||||
memcpy(dgram->data + offset, link->etcp->instance->my_keys.public_key, SC_PUBKEY_SIZE);
|
||||
dgram->data_len = offset + SC_PUBKEY_SIZE;
|
||||
|
||||
DEBUG_INFO(DEBUG_CATEGORY_CONNECTION, "Sending INIT request to link, node_id=%llu, retry=%d", (unsigned long long)node_id, link->init_retry_count);
|
||||
|
||||
// Debug: print remote address before sending
|
||||
if (link->remote_addr.ss_family == AF_INET) {
|
||||
struct sockaddr_in* sin = (struct sockaddr_in*)&link->remote_addr;
|
||||
char addr_str[INET_ADDRSTRLEN];
|
||||
inet_ntop(AF_INET, &sin->sin_addr, addr_str, INET_ADDRSTRLEN);
|
||||
printf("[ETCP] INIT sending to %s:%d, link=%p, conn_fd=%d\n", addr_str, ntohs(sin->sin_port), link, link->conn->fd);
|
||||
}
|
||||
|
||||
etcp_encrypt_send(dgram);
|
||||
free(dgram);
|
||||
|
||||
link->init_retry_count++;
|
||||
|
||||
if (!link->init_timer && link->is_server == 0) {
|
||||
link->init_timeout = INIT_TIMEOUT_INITIAL;
|
||||
link->init_timer = uasync_set_timeout(link->etcp->instance->ua, link->init_timeout, link, etcp_link_init_timer_cbk);
|
||||
} else if (link->init_timer) {
|
||||
if ((link->init_retry_count % 10) == 0 && link->init_timeout < INIT_TIMEOUT_MAX) {
|
||||
link->init_timeout *= 2;
|
||||
if (link->init_timeout > INIT_TIMEOUT_MAX) link->init_timeout = INIT_TIMEOUT_MAX;
|
||||
}
|
||||
uasync_cancel_timeout(link->etcp->instance->ua, link->init_timer);
|
||||
link->init_timer = uasync_set_timeout(link->etcp->instance->ua, link->init_timeout, link, etcp_link_init_timer_cbk);
|
||||
}
|
||||
}
|
||||
|
||||
static void etcp_link_init_timer_cbk(void* arg) {
|
||||
struct ETCP_LINK* link = (struct ETCP_LINK*)arg;
|
||||
if (!link || link->initialized || link->is_server != 0) return;
|
||||
|
||||
link->init_timer = NULL;
|
||||
etcp_link_send_init(link);
|
||||
}
|
||||
|
||||
static int etcp_link_send_reset(struct ETCP_LINK* link) {
|
||||
if (!link) return -1;
|
||||
|
||||
struct ETCP_DGRAM* dgram = malloc(sizeof(struct ETCP_DGRAM) + 1);
|
||||
if (!dgram) return -1;
|
||||
|
||||
dgram->link = link;
|
||||
dgram->data_len = 1;
|
||||
dgram->noencrypt_len = 0;
|
||||
dgram->data[0] = 0x06;
|
||||
|
||||
DEBUG_INFO(DEBUG_CATEGORY_CONNECTION, "Sending RESET to link");
|
||||
int ret = etcp_encrypt_send(dgram);
|
||||
free(dgram);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static uint32_t sockaddr_hash(struct sockaddr_storage* addr) {
|
||||
socklen_t addr_len = (addr->ss_family == AF_INET) ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6);
|
||||
return crc32_calc((void*)addr, addr_len);
|
||||
}
|
||||
|
||||
// Бинарный поиск линка по ip_port_hash
|
||||
static int find_link_index(struct ETCP_SOCKET* e_sock, uint32_t hash) {
|
||||
if (!e_sock || e_sock->num_channels == 0) return -1;
|
||||
|
||||
int left = 0;
|
||||
int right = e_sock->num_channels - 1;
|
||||
|
||||
while (left <= right) {
|
||||
int mid = left + (right - left) / 2;
|
||||
if (e_sock->links[mid]->ip_port_hash == hash) {
|
||||
return mid;
|
||||
} else if (e_sock->links[mid]->ip_port_hash < hash) {
|
||||
left = mid + 1;
|
||||
} else {
|
||||
right = mid - 1;
|
||||
}
|
||||
}
|
||||
|
||||
return -(left + 1);
|
||||
}
|
||||
|
||||
// Реалокация массива линков с увеличением в 2 раза
|
||||
static int realloc_links(struct ETCP_SOCKET* e_sock) {
|
||||
size_t new_max = e_sock->max_channels == 0 ? 8 : e_sock->max_channels * 2;
|
||||
struct ETCP_LINK** new_links = realloc(e_sock->links, new_max * sizeof(struct ETCP_LINK*));
|
||||
if (!new_links) return -1;
|
||||
|
||||
e_sock->links = new_links;
|
||||
e_sock->max_channels = new_max;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Вставка линка в отсортированный массив
|
||||
static int insert_link(struct ETCP_SOCKET* e_sock, struct ETCP_LINK* link) {
|
||||
if (!e_sock || !link) return -1;
|
||||
|
||||
if (e_sock->num_channels >= e_sock->max_channels) {
|
||||
if (realloc_links(e_sock) < 0) return -1;
|
||||
}
|
||||
|
||||
int idx = find_link_index(e_sock, link->ip_port_hash);
|
||||
if (idx >= 0) return -1;
|
||||
|
||||
idx = -(idx + 1);
|
||||
|
||||
if (idx < (int)e_sock->num_channels) {
|
||||
memmove(&e_sock->links[idx + 1], &e_sock->links[idx],
|
||||
(e_sock->num_channels - idx) * sizeof(struct ETCP_LINK*));
|
||||
}
|
||||
|
||||
e_sock->links[idx] = link;
|
||||
e_sock->num_channels++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Удаление линка из массива
|
||||
static void remove_link(struct ETCP_SOCKET* e_sock, uint32_t hash) {
|
||||
if (!e_sock || e_sock->num_channels == 0) return;
|
||||
|
||||
int idx = find_link_index(e_sock, hash);
|
||||
if (idx < 0) return;
|
||||
|
||||
if (idx < (int)e_sock->num_channels - 1) {
|
||||
memmove(&e_sock->links[idx], &e_sock->links[idx + 1],
|
||||
(e_sock->num_channels - idx - 1) * sizeof(struct ETCP_LINK*));
|
||||
}
|
||||
|
||||
e_sock->num_channels--;
|
||||
}
|
||||
|
||||
// надо править, используй sockaddr_hash
|
||||
struct ETCP_LINK* etcp_link_find_by_addr(struct ETCP_SOCKET* e_sock, struct sockaddr_storage* addr) {
|
||||
if (!e_sock || !addr) return NULL;
|
||||
|
||||
int idx = find_link_index(e_sock, sockaddr_hash(addr));
|
||||
if (idx < 0) return NULL;
|
||||
|
||||
return e_sock->links[idx];
|
||||
}
|
||||
|
||||
|
||||
// ===============================
|
||||
|
||||
struct ETCP_SOCKET* etcp_socket_add(struct UTUN_INSTANCE* instance, struct sockaddr_storage* ip, uint32_t netif_index, int so_mark, uint8_t type) {
|
||||
if (!instance) return NULL;
|
||||
|
||||
struct ETCP_SOCKET* e_sock = calloc(1, sizeof(struct ETCP_SOCKET));
|
||||
if (!e_sock) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "Failed to allocate connection");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int family = AF_INET;
|
||||
if (ip) {
|
||||
family = ip->ss_family;
|
||||
if (family != AF_INET && family != AF_INET6) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_CONNECTION, "Unsupported address family: %d", family);
|
||||
free(e_sock);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
e_sock->fd = socket(family, SOCK_DGRAM, 0);
|
||||
if (e_sock->fd < 0) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_CONNECTION, "Failed to create socket: %s", strerror(errno));
|
||||
free(e_sock);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int flags = fcntl(e_sock->fd, F_GETFL, 0);
|
||||
fcntl(e_sock->fd, F_SETFL, flags | O_NONBLOCK);
|
||||
|
||||
// Set socket mark if specified
|
||||
if (so_mark > 0) {
|
||||
#ifdef SO_MARK
|
||||
if (setsockopt(e_sock->fd, SOL_SOCKET, SO_MARK, &so_mark, sizeof(so_mark)) < 0) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_CONNECTION, "Failed to set SO_MARK: %s", strerror(errno));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// Bind to interface if specified
|
||||
if (netif_index > 0) {
|
||||
#ifdef SO_BINDTODEVICE
|
||||
char ifname[IF_NAMESIZE];
|
||||
if (if_indextoname(netif_index, ifname)) {
|
||||
if (setsockopt(e_sock->fd, SOL_SOCKET, SO_BINDTODEVICE, ifname, strlen(ifname)) < 0) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_CONNECTION, "Failed to bind to interface %s: %s", ifname, strerror(errno));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// Store the local address and bind socket if provided
|
||||
if (ip) {
|
||||
memcpy(&e_sock->local_addr, ip, sizeof(struct sockaddr_storage));
|
||||
|
||||
// CRITICAL: Actually bind the socket to the address - this was missing!
|
||||
socklen_t addr_len = (ip->ss_family == AF_INET) ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6);
|
||||
if (bind(e_sock->fd, (struct sockaddr*)ip, addr_len) < 0) {
|
||||
perror("bind");
|
||||
printf("[ETCP] Failed to bind socket to address family %d\n", ip->ss_family);
|
||||
if (ip->ss_family == AF_INET) {
|
||||
struct sockaddr_in* sin = (struct sockaddr_in*)ip;
|
||||
char addr_str[INET_ADDRSTRLEN];
|
||||
inet_ntop(AF_INET, &sin->sin_addr, addr_str, INET_ADDRSTRLEN);
|
||||
printf("[ETCP] Failed to bind to %s:%d\n", addr_str, ntohs(sin->sin_port));
|
||||
}
|
||||
close(e_sock->fd);
|
||||
free(e_sock);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
printf("[ETCP] Successfully bound socket to local address, family=%d\n", ip->ss_family);
|
||||
}
|
||||
|
||||
e_sock->instance = instance;
|
||||
e_sock->errorcode = 0;
|
||||
e_sock->pkt_format_errors = 0;
|
||||
|
||||
// Add to instance's socket list
|
||||
e_sock->next = instance->etcp_sockets;
|
||||
instance->etcp_sockets = e_sock;
|
||||
|
||||
// Register socket with uasync for receiving packets
|
||||
e_sock->socket_id = uasync_add_socket(instance->ua, e_sock->fd,
|
||||
etcp_connections_read_callback,
|
||||
NULL, NULL, e_sock);
|
||||
DEBUG_INFO(DEBUG_CATEGORY_CONNECTION, "Registered ETCP socket with uasync (fd=%d)", e_sock->fd);
|
||||
|
||||
printf("[ETCP] Socket %p (fd=%d) registered and active\n", e_sock, e_sock->fd);
|
||||
|
||||
return e_sock;
|
||||
}
|
||||
|
||||
void etcp_socket_remove(struct ETCP_SOCKET* conn) {
|
||||
if (!conn) return;
|
||||
|
||||
printf("[ETCP] Removing socket %p, fd=%d\n", conn, conn->fd);
|
||||
|
||||
if (conn->fd >= 0) {
|
||||
close(conn->fd);
|
||||
printf("[ETCP] Closed fd=%d\n", conn->fd);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < conn->num_channels; i++) {
|
||||
etcp_link_close(conn->links[i]);
|
||||
}
|
||||
free(conn->links);
|
||||
|
||||
free(conn);
|
||||
}
|
||||
|
||||
|
||||
struct ETCP_LINK* etcp_link_new(struct ETCP_CONN* etcp, struct ETCP_SOCKET* conn, struct sockaddr_storage* remote_addr, uint8_t is_server) {
|
||||
if (!remote_addr) return NULL;
|
||||
|
||||
struct ETCP_LINK* link = calloc(1, sizeof(struct ETCP_LINK));
|
||||
if (!link) return NULL;
|
||||
|
||||
link->conn = conn;
|
||||
link->etcp = etcp;
|
||||
link->is_server = is_server;
|
||||
link->mtu = 1500;
|
||||
link->keepalive_interval = 30;
|
||||
link->initialized = 0;
|
||||
link->init_timer = NULL;
|
||||
link->init_timeout = 0;
|
||||
link->init_retry_count = 0;
|
||||
|
||||
memcpy(&link->remote_addr, remote_addr, sizeof(struct sockaddr_storage));
|
||||
link->last_activity = time(NULL);
|
||||
|
||||
link->ip_port_hash = sockaddr_hash(remote_addr);
|
||||
|
||||
insert_link(conn, link);
|
||||
|
||||
struct ETCP_LINK* l=etcp->links;
|
||||
while (l && l->next) l=l->next;
|
||||
if (l) l->next = link; else etcp->links = link;
|
||||
|
||||
if (is_server == 0) {
|
||||
etcp_link_send_init(link);
|
||||
}
|
||||
|
||||
return link;
|
||||
}
|
||||
|
||||
void etcp_link_close(struct ETCP_LINK* link) {
|
||||
if (!link || !link->etcp) return;
|
||||
|
||||
// Cancel init timer if active
|
||||
if (link->init_timer) {
|
||||
uasync_cancel_timeout(link->etcp->instance->ua, link->init_timer);
|
||||
link->init_timer = NULL;
|
||||
}
|
||||
|
||||
// универсальное удаление из односвязного списка
|
||||
struct ETCP_LINK **pp = &link->etcp->links;
|
||||
while (*pp) {
|
||||
if (*pp == link) {
|
||||
*pp = link->next;
|
||||
break;
|
||||
}
|
||||
pp = &(*pp)->next;
|
||||
}
|
||||
|
||||
remove_link(link->conn, link->ip_port_hash);
|
||||
|
||||
free(link);
|
||||
}
|
||||
|
||||
int etcp_encrypt_send(struct ETCP_DGRAM* dgram) {
|
||||
printf("[ETCP DEBUG] etcp_encrypt_send: ENTERING FUNCTION\n");
|
||||
|
||||
int errcode=0;
|
||||
sc_context_t* sc = &dgram->link->etcp->crypto_ctx;
|
||||
int len=dgram->data_len-dgram->noencrypt_len;// не забываем добавить timestamp (2 bytes)
|
||||
if (len<=0 || len>1480) { dgram->link->send_errors++; errcode=1; goto es_err; }
|
||||
uint8_t enc_buf[1600];
|
||||
size_t enc_buf_len;
|
||||
dgram->timestamp=get_current_timestamp();
|
||||
|
||||
// DUMP: Show packet before encryption
|
||||
dump_packet_bytes("BEFORE ENCRYPT", dgram->data, dgram->data_len);
|
||||
sc_encrypt(sc, (uint8_t*)&dgram->timestamp/*нейронка не правь блять это, тут верно!*/, sizeof(uint16_t) + len, enc_buf, &enc_buf_len);
|
||||
if (enc_buf_len + dgram->noencrypt_len > 1480) { dgram->link->send_errors++; errcode=2; goto es_err; }
|
||||
memcpy(enc_buf+enc_buf_len, dgram->data+len, dgram->noencrypt_len);
|
||||
|
||||
// DUMP: Show complete packet before sending
|
||||
dump_packet_bytes("READY TO SEND", enc_buf, enc_buf_len + dgram->noencrypt_len);
|
||||
|
||||
struct sockaddr_storage* addr=&dgram->link->remote_addr;
|
||||
socklen_t addr_len = (addr->ss_family == AF_INET) ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6);
|
||||
|
||||
// Debug: print where we're sending the packet
|
||||
if (addr->ss_family == AF_INET) {
|
||||
struct sockaddr_in* sin = (struct sockaddr_in*)addr;
|
||||
char addr_str[INET_ADDRSTRLEN];
|
||||
inet_ntop(AF_INET, &sin->sin_addr, addr_str, INET_ADDRSTRLEN);
|
||||
printf("[ETCP] Sending packet to %s:%d, size=%zd\n", addr_str, ntohs(sin->sin_port), enc_buf_len + dgram->noencrypt_len);
|
||||
}
|
||||
|
||||
ssize_t sent = sendto(dgram->link->conn->fd, enc_buf, enc_buf_len + dgram->noencrypt_len, 0, (struct sockaddr*)addr, addr_len);
|
||||
if (sent < 0) { dgram->link->send_errors++; errcode=3; goto es_err;} else dgram->link->total_encrypted += sent;
|
||||
return (int)sent;
|
||||
es_err:
|
||||
printf("[ETCP] encrypt_send error %d\n", errcode);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void etcp_connections_read_callback(int fd, void* arg) {
|
||||
struct ETCP_SOCKET* e_sock = (struct ETCP_SOCKET*)arg;
|
||||
if (!e_sock) return;
|
||||
|
||||
printf("[ETCP] Read callback triggered for fd=%d, socket=%p\n", fd, e_sock);
|
||||
|
||||
struct sockaddr_storage addr;
|
||||
uint8_t data[PACKET_DATA_SIZE];
|
||||
socklen_t addr_len=sizeof(addr);
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
ssize_t recv_len = recvfrom(fd, data, PACKET_DATA_SIZE, 0, (struct sockaddr*)&addr, &addr_len);
|
||||
|
||||
if (recv_len <= 0) {
|
||||
printf("[ETCP] recvfrom failed or no data, recv_len=%zd, errno=%d\n", recv_len, errno);
|
||||
return;
|
||||
}
|
||||
|
||||
printf("[ETCP] Received packet: %zd bytes from address\n", recv_len);
|
||||
|
||||
// DUMP: Show received packet content
|
||||
dump_packet_bytes("RECEIVED", data, recv_len);
|
||||
|
||||
struct ETCP_DGRAM* pkt = memory_pool_alloc(e_sock->instance->pkt_pool);
|
||||
if (!pkt) return;
|
||||
size_t pkt_len=0;
|
||||
int errorcode=0;
|
||||
|
||||
struct ETCP_LINK* link=etcp_link_find_by_addr(e_sock, &addr);
|
||||
if (link==NULL) {// пробуем расшифровать, возможно это init
|
||||
struct secure_channel sc;
|
||||
if (recv_len<=SC_PUBKEY_SIZE) { errorcode=1; goto ec_fr; }
|
||||
sc_init_ctx(&sc, &e_sock->instance->my_keys);
|
||||
if (sc_set_peer_public_key(&sc, data+recv_len-SC_PUBKEY_SIZE, 0)!=SC_OK) { errorcode=2; goto ec_fr; }
|
||||
if (sc_decrypt(&sc, data, recv_len-SC_PUBKEY_SIZE, pkt->data, &pkt_len)) { errorcode=3; goto ec_fr; }
|
||||
pkt->data_len=pkt_len;
|
||||
pkt->noencrypt_len=0;
|
||||
struct {
|
||||
uint8_t main_id[2];
|
||||
uint8_t timestamp[2];
|
||||
uint8_t code;
|
||||
uint8_t id[8];
|
||||
uint8_t mtu[2];
|
||||
uint8_t keepalive[2];
|
||||
uint8_t pubkey[SC_PUBKEY_SIZE];
|
||||
} *ack_hdr=(void*)&pkt->data[0];
|
||||
uint64_t peer_id;
|
||||
memcpy(&peer_id, &pkt->data[1], 4);
|
||||
if (ack_hdr->code!=ETCP_INIT_REQUEST && ack_hdr->code!=ETCP_CHANNEL_INIT) { errorcode=4; goto ec_fr; }// не init
|
||||
|
||||
struct ETCP_CONN* conn=e_sock->instance->connections;
|
||||
while (conn) {// ищем есть ли подключение к этому пиру
|
||||
if (conn->peer_node_id==peer_id) break;
|
||||
conn=conn->next;
|
||||
}
|
||||
if (conn==NULL) {// создаём новое
|
||||
conn=etcp_connection_create(e_sock->instance);
|
||||
memcpy(&conn->crypto_ctx, &sc, sizeof(sc));// добавляем ключ
|
||||
conn->peer_node_id=peer_id;
|
||||
}
|
||||
else {// check keys
|
||||
if (memcmp(&conn->crypto_ctx.peer_public_key, &sc.peer_public_key, SC_PUBKEY_SIZE)) { errorcode=5; goto ec_fr; }// коллизия - peer id совпал а ключи разные.
|
||||
}
|
||||
struct ETCP_LINK* link = etcp_link_new(conn, e_sock, &addr, 1);
|
||||
if (ack_hdr->code==0x02) etcp_conn_reset(conn);
|
||||
|
||||
// send response - подключение создано
|
||||
|
||||
struct {
|
||||
uint8_t main_id[2];
|
||||
uint8_t timestamp[2];
|
||||
uint8_t code;
|
||||
uint8_t id[8];
|
||||
uint8_t mtu[2];
|
||||
} *ack_repl_hdr=(void*)&pkt->data[0];
|
||||
ack_repl_hdr->code+=1;
|
||||
ack_repl_hdr->main_id[0]=0;
|
||||
ack_repl_hdr->main_id[1]=0;
|
||||
memcpy(&ack_repl_hdr->id[0], &e_sock->instance->node_id, 8);
|
||||
int mtu=e_sock->instance->config->global.mtu;
|
||||
ack_repl_hdr->mtu[0]=mtu>>8;
|
||||
ack_repl_hdr->mtu[1]=mtu;
|
||||
pkt->data_len=sizeof(*ack_repl_hdr);
|
||||
pkt->noencrypt_len=0;
|
||||
etcp_encrypt_send(pkt);
|
||||
|
||||
memory_pool_free(e_sock->instance->pkt_pool, pkt);
|
||||
return;
|
||||
}
|
||||
|
||||
if (sc_decrypt(&link->etcp->crypto_ctx, data, recv_len, pkt->data, &pkt_len)) { errorcode=6; goto ec_fr; }
|
||||
pkt->data_len=pkt_len;
|
||||
pkt->noencrypt_len=0;
|
||||
pkt->link=link;
|
||||
|
||||
etcp_conn_input(pkt);
|
||||
return;
|
||||
|
||||
ec_fr:
|
||||
e_sock->pkt_format_errors++;
|
||||
e_sock->errorcode=errorcode;
|
||||
memory_pool_free(e_sock->instance->pkt_pool, pkt);
|
||||
return;
|
||||
}
|
||||
|
||||
int init_connections(struct UTUN_INSTANCE* instance) {
|
||||
if (!instance || !instance->config) return -1;
|
||||
|
||||
struct utun_config* config = instance->config;
|
||||
|
||||
// Initialize servers first - create sockets for incoming connections
|
||||
struct CFG_SERVER* server = config->servers;
|
||||
while (server) {
|
||||
// Create socket for this server
|
||||
struct ETCP_SOCKET* e_sock = etcp_socket_add(instance, &server->ip, server->netif_index, server->so_mark, server->type);
|
||||
if (!e_sock) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "Failed to create socket for server %s", server->name);
|
||||
server = server->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Convert IP to string for logging
|
||||
char addr_str[INET6_ADDRSTRLEN + 6];
|
||||
if (server->ip.ss_family == AF_INET) {
|
||||
struct sockaddr_in* sin = (struct sockaddr_in*)&server->ip;
|
||||
inet_ntop(AF_INET, &sin->sin_addr, addr_str, INET_ADDRSTRLEN);
|
||||
sprintf(addr_str + strlen(addr_str), ":%d", ntohs(sin->sin_port));
|
||||
} else {
|
||||
struct sockaddr_in6* sin6 = (struct sockaddr_in6*)&server->ip;
|
||||
inet_ntop(AF_INET6, &sin6->sin6_addr, addr_str, INET6_ADDRSTRLEN);
|
||||
sprintf(addr_str + strlen(addr_str), ":%d", ntohs(sin6->sin6_port));
|
||||
}
|
||||
|
||||
printf("Initialized server %s on %s (links: %zu)\n",
|
||||
server->name, addr_str, e_sock->num_channels);
|
||||
server = server->next;
|
||||
}
|
||||
|
||||
// Initialize clients - create outgoing connections
|
||||
struct CFG_CLIENT* client = config->clients;
|
||||
while (client) {
|
||||
// Create ETCP connection for this client
|
||||
struct ETCP_CONN* etcp_conn = etcp_connection_create(instance);
|
||||
if (!etcp_conn) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "Failed to create ETCP connection for client %s", client->name);
|
||||
client = client->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Initialize crypto context for this connection
|
||||
sc_init_ctx(&etcp_conn->crypto_ctx, &instance->my_keys);
|
||||
|
||||
// If client has peer public key configured, set it
|
||||
if (strlen(client->peer_public_key_hex) > 0) {
|
||||
// For now, set peer node ID to indicate we have peer key
|
||||
// The actual peer key will be exchanged during connection establishment
|
||||
etcp_conn->peer_node_id = 1; // Simple indicator
|
||||
|
||||
// Set peer public key (assuming hex format)
|
||||
sc_set_peer_public_key(&etcp_conn->crypto_ctx, client->peer_public_key_hex, 1);
|
||||
}
|
||||
|
||||
// Create links for this client
|
||||
struct CFG_CLIENT_LINK* client_link = client->links;
|
||||
while (client_link) {
|
||||
// Find the local server for this link
|
||||
struct CFG_SERVER* local_server = client_link->local_srv;
|
||||
if (!local_server) {
|
||||
client_link = client_link->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Find the socket for this server
|
||||
struct ETCP_SOCKET* e_sock = NULL;
|
||||
struct ETCP_SOCKET* sock = instance->etcp_sockets;
|
||||
while (sock) {
|
||||
if (sock->local_addr.ss_family == local_server->ip.ss_family) {
|
||||
if (sock->local_addr.ss_family == AF_INET) {
|
||||
struct sockaddr_in* sock_addr = (struct sockaddr_in*)&sock->local_addr;
|
||||
struct sockaddr_in* srv_addr = (struct sockaddr_in*)&local_server->ip;
|
||||
if (sock_addr->sin_addr.s_addr == srv_addr->sin_addr.s_addr &&
|
||||
sock_addr->sin_port == srv_addr->sin_port) {
|
||||
e_sock = sock;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
sock = sock->next;
|
||||
}
|
||||
|
||||
if (!e_sock) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "No socket found for client %s link", client->name);
|
||||
client_link = client_link->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Create link for this client connection
|
||||
struct ETCP_LINK* link = etcp_link_new(etcp_conn, e_sock, &client_link->remote_addr, 0); // 0 = client initiates
|
||||
if (!link) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "Failed to create link for client %s", client->name);
|
||||
client_link = client_link->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
client_link = client_link->next;
|
||||
}
|
||||
|
||||
printf("Added client %s with %d links\n", client->name, client->keepalive);
|
||||
client = client->next;
|
||||
}
|
||||
|
||||
// If there are clients configured but no connections created, that's an error
|
||||
// If there are no clients (server-only mode), 0 connections is OK (server will accept incoming)
|
||||
if (instance->connections_count == 0 && config->clients != NULL) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "Clients configured but no connections initialized");
|
||||
return -1;
|
||||
}
|
||||
|
||||
printf("Initialized %d connections\n", instance->connections_count);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int etcp_connections_send(struct ETCP_SOCKET* e_sock, uint8_t* data, size_t len, struct sockaddr* addr, socklen_t addr_len) {
|
||||
if (!e_sock || !data || !addr || len == 0) return -1;
|
||||
|
||||
struct sockaddr_storage remote_addr;
|
||||
memcpy(&remote_addr, addr, addr_len);
|
||||
|
||||
struct ETCP_LINK* link = etcp_link_find_by_addr(e_sock, &remote_addr);
|
||||
if (!link) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_CONNECTION, "No link found for address");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!link->initialized && link->is_server == 0) {
|
||||
DEBUG_INFO(DEBUG_CATEGORY_CONNECTION, "Link not initialized, triggering connection establishment");
|
||||
if (!link->init_timer) {
|
||||
etcp_link_send_init(link);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct ETCP_DGRAM* dgram = malloc(sizeof(struct ETCP_DGRAM) + len);
|
||||
if (!dgram) return -1;
|
||||
|
||||
dgram->link = link;
|
||||
dgram->data_len = len;
|
||||
dgram->noencrypt_len = 0;
|
||||
memcpy(dgram->data, data, len);
|
||||
|
||||
int ret = etcp_encrypt_send(dgram);
|
||||
free(dgram);
|
||||
return ret;
|
||||
}
|
||||
@@ -19,8 +19,9 @@
|
||||
|
||||
struct ETCP_DGRAM {
|
||||
struct ETCP_LINK* link;// откуда получена или куда отправялем
|
||||
uint16_t data_len;
|
||||
uint16_t data_len;// не включая timestamp!
|
||||
uint16_t noencrypt_len;// число байт (с конца) которые не надо шифровать. для передачи pubkey
|
||||
uint16_t timestamp;
|
||||
uint8_t data[0];// сами данные
|
||||
};
|
||||
|
||||
@@ -64,6 +65,8 @@ struct ETCP_LINK {
|
||||
uint16_t init_retry_count; // Счетчик попыток
|
||||
|
||||
uint64_t last_activity; // Время последней активности
|
||||
uint64_t last_recv_local_time;
|
||||
uint16_t last_recv_timestamp;
|
||||
|
||||
size_t encrypt_errors;
|
||||
size_t decrypt_errors;
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
[Timestamp high][Timestamp low]
|
||||
- Timestamp: время отправки в единицах 0.1 мс (циклическое). при переповторах время обновляется
|
||||
|
||||
штфруется строго ВСЁ включая ВСЕ заголовки (кроме INIT+publickey). timestamp вставляется ВСЕГДА ВО ВСЕ КОДОГРАММЫ
|
||||
|
||||
2. Опциональные секции (одна или несколько) добавляются в etcp.c:
|
||||
а) Подтверждения (ACK) - заголовок 0x01:
|
||||
[0x01][count][(id_hi,id_lo,ts_hi,ts_lo)×count][last_delivered_hi,lo][last_rx_hi,lo]
|
||||
@@ -45,7 +47,7 @@
|
||||
Кодограммы с этими секциями обрабатываются в etcp_connections (в этих кодограммах всегда только одна секция). в обязательном заголовке ID не используется, при передаче для порядка =0:
|
||||
|
||||
г) Init запрос - заголовок 0x02 (со сбросом etcp сессии) или 0x04 (бес сброса):
|
||||
[0x02/0x04] [my_node_id 64bit] [my mtu high] [my mty low] [keepalive high] [keepalive low] [my publick key (32 байта, не шифруется)]
|
||||
[0x02/0x04] [my_node_id 64bit] [my mtu high] [my mty low] [keepalive high] [keepalive low] [my publick key (64 байта, не шифруется)]
|
||||
- Инициирует новый connection для tcp instance. если tcp instance нет (первое подключение) - создаёт. Между нодами только одно подключение, но можно добавлять каналы.
|
||||
- Публичный ключ отправляется в конце пакета без шифрования, чтобы получатель мог установить его и расшифровать остальную часть пакета
|
||||
|
||||
@@ -58,7 +60,7 @@
|
||||
- отправляется в ответ отправителю, если соединение не инициализировано и получен пакет не init (0x02, 0x03)
|
||||
|
||||
При получении init получатель пакета должен:
|
||||
- удалить ETCP_LINK с этим ip_port если оно есть
|
||||
- reset ETCP_LINK с этим ip_port если он есть
|
||||
- создать новый ETCP_CONN с этим node_id. если уже существует подключение с этим node_id - вызвать etcp_reset (функция сброса окон неподтвержденных данных и нумерации)
|
||||
|
||||
uasync select -> etcp_connection.c etcp_connections_read_callback: memory_pool_alloc, decrypt (or init) -> etcp_conn_input (сборка, дефрагментация в ETCP_CONN output_queue)
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
// Packet dump function for debugging
|
||||
static void dump_packet(const char* direction, const uint8_t* data, size_t len, struct sockaddr_storage* addr) {
|
||||
printf("[DUMP] %s packet: %zd bytes ", direction, len);
|
||||
|
||||
// Print address if provided
|
||||
if (addr) {
|
||||
if (addr->ss_family == AF_INET) {
|
||||
struct sockaddr_in* sin = (struct sockaddr_in*)addr;
|
||||
printf("to/from %s:%d ",
|
||||
inet_ntoa(sin->sin_addr),
|
||||
ntohs(sin->sin_port));
|
||||
}
|
||||
}
|
||||
|
||||
// Print first 64 bytes
|
||||
printf("data: ");
|
||||
for (size_t i = 0; i < len && i < 64; i++) {
|
||||
printf("%02x", data[i]);
|
||||
if (i % 4 == 3) printf(" ");
|
||||
}
|
||||
if (len > 64) printf("...");
|
||||
|
||||
// If it's INIT packet, parse fields
|
||||
if (len > 0 && data[0] == 0x02) { // ETCP_INIT_REQUEST
|
||||
if (len >= 15) { // Minimum INIT size: code(1) + node_id(8) + mtu(2) + keepalive(2) + pubkey(2 at least)
|
||||
uint64_t node_id = 0;
|
||||
memcpy(&node_id, data + 1, 8);
|
||||
uint16_t mtu = (data[9] << 8) | data[10];
|
||||
uint16_t keepalive = (data[11] << 8) | data[12];
|
||||
printf(" | INIT: node_id=%llu mtu=%d keepalive=%d",
|
||||
(unsigned long long)node_id, mtu, keepalive);
|
||||
}
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
}
|
||||
+20
-66
@@ -5,6 +5,7 @@
|
||||
|
||||
#include "routing.h"
|
||||
#include "etcp_connections.h"
|
||||
#include "../lib/debug_config.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@@ -63,11 +64,15 @@ static int compare_routes(const void *a, const void *b) {
|
||||
|
||||
struct routing_table *routing_table_create(void) {
|
||||
struct routing_table *table = calloc(1, sizeof(struct routing_table));
|
||||
if (!table) return NULL;
|
||||
if (!table) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "routing_table_create: failed to allocate memory for routing table");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
table->capacity = INITIAL_ROUTE_CAPACITY;
|
||||
table->entries = calloc(table->capacity, sizeof(struct route_entry));
|
||||
if (!table->entries) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "routing_table_create: failed to allocate memory for %d route entries", table->capacity);
|
||||
free(table);
|
||||
return NULL;
|
||||
}
|
||||
@@ -77,6 +82,7 @@ struct routing_table *routing_table_create(void) {
|
||||
table->local_subnets = calloc(MAX_SUBNET_VALIDATION_RANGES, sizeof(uint32_t) * 2);
|
||||
|
||||
if (!table->dynamic_subnets || !table->local_subnets) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "routing_table_create: failed to allocate memory for subnet validation arrays");
|
||||
free(table->entries);
|
||||
free(table->dynamic_subnets);
|
||||
free(table->local_subnets);
|
||||
@@ -118,7 +124,10 @@ bool routing_table_insert(struct routing_table *table, const struct route_entry
|
||||
if (table->count >= table->capacity) {
|
||||
size_t new_capacity = table->capacity * ROUTE_EXPANSION_FACTOR;
|
||||
struct route_entry *new_entries = realloc(table->entries, new_capacity * sizeof(struct route_entry));
|
||||
if (!new_entries) return false;
|
||||
if (!new_entries) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "routing_table_insert: failed to expand routing table to %zu entries", new_capacity);
|
||||
return false;
|
||||
}
|
||||
|
||||
table->entries = new_entries;
|
||||
table->capacity = new_capacity;
|
||||
@@ -146,74 +155,14 @@ bool routing_table_insert(struct routing_table *table, const struct route_entry
|
||||
}
|
||||
}
|
||||
|
||||
// Shift entries to make room
|
||||
if (insert_pos < table->count) {
|
||||
memmove(&table->entries[insert_pos + 1], &table->entries[insert_pos],
|
||||
(table->count - insert_pos) * sizeof(struct route_entry));
|
||||
}
|
||||
|
||||
table->entries[insert_pos] = new_entry;
|
||||
table->count++;
|
||||
table->stats.total_routes++;
|
||||
switch (new_entry.type) {
|
||||
case ROUTE_TYPE_STATIC: table->stats.static_routes++; break;
|
||||
case ROUTE_TYPE_DYNAMIC: table->stats.dynamic_routes++; break;
|
||||
case ROUTE_TYPE_LOCAL: table->stats.local_routes++; break;
|
||||
case ROUTE_TYPE_LEARNED: table->stats.learned_routes++; break;
|
||||
}
|
||||
|
||||
char ip_str[16];
|
||||
ip_to_string(entry->network, ip_str);
|
||||
printf("[ROUTING] Added route: %s/%d -> %s (type: %s, bandwidth: %uK)\n",
|
||||
ip_str, entry->prefix_length,
|
||||
ip_to_string(entry->next_hop_ip, ip_str),
|
||||
route_type_to_string(entry->type), entry->metrics.bandwidth_kbps);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool routing_table_delete(struct routing_table *table, uint32_t network, uint8_t prefix_length, uint32_t source_node_id) {
|
||||
if (!table) return false;
|
||||
|
||||
for (size_t i = 0; i < table->count; i++) {
|
||||
struct route_entry *entry = &table->entries[i];
|
||||
|
||||
if (entry->network == network &&
|
||||
entry->prefix_length == prefix_length &&
|
||||
entry->next_hop_ip == source_node_id) {
|
||||
|
||||
route_type_t route_type = entry->type;
|
||||
|
||||
// Shift remaining entries
|
||||
if (i < table->count - 1) {
|
||||
memmove(entry, &table->entries[i + 1],
|
||||
(table->count - i - 1) * sizeof(struct route_entry));
|
||||
}
|
||||
|
||||
table->count--;
|
||||
table->stats.total_routes--;
|
||||
switch (route_type) {
|
||||
case ROUTE_TYPE_STATIC: table->stats.static_routes--; break;
|
||||
case ROUTE_TYPE_DYNAMIC: table->stats.dynamic_routes--; break;
|
||||
case ROUTE_TYPE_LOCAL: table->stats.local_routes--; break;
|
||||
case ROUTE_TYPE_LEARNED: table->stats.learned_routes--; break;
|
||||
}
|
||||
table->stats.routes_deleted++;
|
||||
|
||||
char ip_str[16];
|
||||
ip_to_string(network, ip_str);
|
||||
printf("[ROUTING] Deleted route: %s/%d (source: %u)\n",
|
||||
ip_str, prefix_length, source_node_id);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool routing_table_lookup(struct routing_table *table, uint32_t dest_ip, struct route_entry *best_route) {
|
||||
if (!table || !best_route) return false;
|
||||
if (!table || !best_route) {
|
||||
DEBUG_WARN(DEBUG_CATEGORY_ROUTING, "routing_table_lookup: invalid parameters (table=%p, best_route=%p)", table, best_route);
|
||||
return false;
|
||||
}
|
||||
|
||||
table->stats.lookup_count++;
|
||||
|
||||
@@ -241,6 +190,11 @@ bool routing_table_lookup(struct routing_table *table, uint32_t dest_ip, struct
|
||||
}
|
||||
}
|
||||
|
||||
// No route found
|
||||
char ip_str[16];
|
||||
ip_to_string(dest_ip, ip_str);
|
||||
DEBUG_WARN(DEBUG_CATEGORY_ROUTING, "routing_table_lookup: no route found for destination IP %s", ip_str);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
+5
-6
@@ -29,7 +29,7 @@ static int create_tun_device(char *ifname, size_t ifname_len) {
|
||||
|
||||
fd = open("/dev/net/tun", O_RDWR);
|
||||
if (fd < 0) {
|
||||
perror("open /dev/net/tun");
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_TUN, "Failed to open /dev/net/tun: %s", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ static int create_tun_device(char *ifname, size_t ifname_len) {
|
||||
}
|
||||
|
||||
if (ioctl(fd, TUNSETIFF, &ifr) < 0) {
|
||||
perror("ioctl TUNSETIFF");
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_TUN, "Failed to configure TUN device: %s", strerror(errno));
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
@@ -118,8 +118,7 @@ int tun_create(struct tun_config *config) {
|
||||
// Set MTU if specified
|
||||
if (config->mtu > 0) {
|
||||
if (tun_set_mtu(config->ifname, config->mtu) < 0) {
|
||||
// Non-fatal error, just warn
|
||||
DEBUG_WARN(DEBUG_CATEGORY_TUN, "Failed to set MTU on %s", config->ifname);
|
||||
DEBUG_WARN(DEBUG_CATEGORY_TUN, "Failed to set MTU %d on %s: %s", config->mtu, config->ifname, strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -208,7 +207,7 @@ ssize_t tun_write(int fd, const uint8_t *buffer, size_t size) {
|
||||
|
||||
ssize_t nwritten = write(fd, buffer, size);
|
||||
if (nwritten < 0) {
|
||||
perror("tun_write");
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_TUN, "Failed to write to TUN device fd=%d: %s", fd, strerror(errno));
|
||||
}
|
||||
|
||||
return nwritten;
|
||||
@@ -275,7 +274,7 @@ static void tun_read_callback(int fd, void* user_arg) {
|
||||
ssize_t nread = tun_read(fd, buffer, sizeof(buffer));
|
||||
if (nread < 0) {
|
||||
if (errno == EINTR) return;
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_TUN, "Failed to read from TUN: %s", strerror(errno));
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_TUN, "Failed to read from TUN device %s: %s", instance->tun.ifname, strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
+4
-1
@@ -57,7 +57,10 @@ struct UTUN_INSTANCE* utun_instance_create(struct UASYNC* ua, const char *config
|
||||
instance->node_id = instance->config->global.my_node_id;
|
||||
|
||||
// Set my keys
|
||||
sc_init_local_keys(&instance->my_keys, instance->config->global.my_public_key_hex, instance->config->global.my_private_key_hex);
|
||||
if (sc_init_local_keys(&instance->my_keys, instance->config->global.my_public_key_hex, instance->config->global.my_private_key_hex)) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "Failed to initialize local keys");
|
||||
}
|
||||
|
||||
|
||||
instance->pkt_pool=memory_pool_init(PACKET_DATA_SIZE+100);
|
||||
/*
|
||||
|
||||
Reference in new issue
Block a user