ETCP_CONNECTIONS: add encryption support with secure channel (AES-CCM), nonce, counters. Simplified architecture by removing socket wrappers and integrating uasync_add_socket. pubkey exchange moved to INIT packet only. Added statistics counters.
This commit is contained in:
1 parent
3f0a23aa93
commit
20e5401ec9
13 files changed
+675
-58
No files matched your search
+14
-2
@@ -12,6 +12,14 @@
|
||||
#define MAX_LINE_LEN 1024
|
||||
#define INITIAL_ARRAY_CAPACITY 8
|
||||
|
||||
void bytes_to_hex(const uint8_t *bytes, size_t len, char *hex_str, size_t hex_len) {
|
||||
if (!bytes || !hex_str || hex_len < len * 2 + 1) return;
|
||||
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';
|
||||
}
|
||||
|
||||
typedef enum {
|
||||
SECTION_UNKNOWN,
|
||||
SECTION_GLOBAL,
|
||||
@@ -106,6 +114,10 @@ static int add_route(struct utun_config *cfg, const char *server, const char *cl
|
||||
static int parse_global(const char *key, const char *value, struct global_config *global) {
|
||||
if (strcmp(key, "my_private_key") == 0) return assign_string(global->my_private_key_hex, MAX_KEY_LEN, value);
|
||||
if (strcmp(key, "my_public_key") == 0) return assign_string(global->my_public_key_hex, MAX_KEY_LEN, value);
|
||||
if (strcmp(key, "my_node_id") == 0) {
|
||||
global->my_node_id = strtoull(value, NULL, 16);
|
||||
return 0;
|
||||
}
|
||||
if (strcmp(key, "tun_ip") == 0) return assign_string(global->tun_ip, MAX_ADDR_LEN, value);
|
||||
if (strcmp(key, "mtu") == 0) { global->mtu = atoi(value); return 0; }
|
||||
if (strcmp(key, "control_ip") == 0) return assign_string(global->control_ip, MAX_ADDR_LEN, value);
|
||||
@@ -143,8 +155,7 @@ static int parse_client(const char *key, const char *value, struct client_config
|
||||
|
||||
if (strcmp(key, "from") == 0) return assign_string(cli->from, MAX_CONN_NAME_LEN, value);
|
||||
if (strcmp(key, "to_addr") == 0) return assign_string(cli->to_addr, MAX_ADDR_LEN, value);
|
||||
// Support for test config format: addr1, addr2
|
||||
if (strncmp(key, "addr", 4) == 0) return assign_string(cli->to_addr, MAX_ADDR_LEN, value);
|
||||
if (strcmp(key, "peer_public_key") == 0) return assign_string(cli->peer_public_key_hex, MAX_KEY_LEN, value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -333,6 +344,7 @@ void print_config(const struct utun_config *cfg) {
|
||||
printf("Global:\n");
|
||||
printf(" Private key: %s\n", g->my_private_key_hex);
|
||||
printf(" Public key: %s\n", g->my_public_key_hex);
|
||||
printf(" Node ID: %llx\n", (unsigned long long)g->my_node_id);
|
||||
printf(" TUN IP: %s\n", g->tun_ip);
|
||||
printf(" MTU: %d\n", g->mtu);
|
||||
printf(" Control: %s:%u\n", g->control_ip, g->control_port);
|
||||
|
||||
@@ -32,6 +32,7 @@ struct client_config {
|
||||
char name[MAX_CONN_NAME_LEN];
|
||||
char from[MAX_CONN_NAME_LEN];
|
||||
char to_addr[MAX_ADDR_LEN];
|
||||
char peer_public_key_hex[MAX_KEY_LEN];
|
||||
};
|
||||
|
||||
struct route_pair {
|
||||
@@ -50,6 +51,7 @@ struct connection_config_v2 {
|
||||
struct global_config {
|
||||
char my_private_key_hex[MAX_KEY_LEN];
|
||||
char my_public_key_hex[MAX_KEY_LEN];
|
||||
uint64_t my_node_id;
|
||||
char tun_ip[MAX_ADDR_LEN];
|
||||
int mtu;
|
||||
char control_ip[MAX_ADDR_LEN];
|
||||
@@ -77,6 +79,8 @@ void free_config(struct utun_config *config);
|
||||
void print_config(const struct utun_config *config);
|
||||
int update_config_keys(const char *filename, const char *priv_key, const char *pub_key);
|
||||
|
||||
void bytes_to_hex(const uint8_t *bytes, size_t len, char *hex_str, size_t hex_len);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,293 @@
|
||||
// config_updater.c - Configuration file updater implementation
|
||||
#define _POSIX_C_SOURCE 200809L
|
||||
#include "config_updater.h"
|
||||
#include "config_parser.h"
|
||||
#include "secure_channel.h"
|
||||
#include "debug_config.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#define HEXKEY_LEN 64 // 32 bytes * 2 hex chars
|
||||
#define HEXNODEID_LEN 16 // 8 bytes * 2 hex chars
|
||||
#define MAX_LINE_LEN 1024
|
||||
|
||||
static int is_valid_hex_key(const char *key) {
|
||||
if (!key || strlen(key) != HEXKEY_LEN) return 0;
|
||||
for (int i = 0; i < HEXKEY_LEN; i++) {
|
||||
if (!isxdigit((unsigned char)key[i])) return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int is_valid_node_id(uint64_t node_id) {
|
||||
return node_id != 0;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
static char* find_section_global(char *buf, size_t buf_len) {
|
||||
char *p = buf;
|
||||
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'
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static char* find_option(char *buf, size_t buf_len, const char *option) {
|
||||
char *p = buf;
|
||||
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++;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int insert_or_replace_option(char **buf, size_t *buf_len, size_t *buf_capacity, const char *option, const char *value) {
|
||||
if (!buf || !*buf || !buf_len || !buf_capacity || !option || !value) return -1;
|
||||
|
||||
// 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
|
||||
size_t old_line_len = line_end - opt_pos + 1;
|
||||
long len_diff = new_len - old_line_len;
|
||||
|
||||
// Ensure buffer capacity
|
||||
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
|
||||
char *prev_nl = insert_pos;
|
||||
while (prev_nl > *buf && *prev_nl != '\n') prev_nl--;
|
||||
if (*prev_nl == '\n') insert_pos = prev_nl + 1;
|
||||
}
|
||||
|
||||
// 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;
|
||||
while (prev_nl > *buf && *prev_nl != '\n') prev_nl--;
|
||||
if (*prev_nl == '\n') insert_pos = prev_nl + 1;
|
||||
}
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
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);
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct global_config *global = &config->global;
|
||||
|
||||
// Check if we need to generate anything
|
||||
int need_priv_key = !is_valid_hex_key(global->my_private_key_hex);
|
||||
int need_pub_key = !is_valid_hex_key(global->my_public_key_hex);
|
||||
int need_node_id = !is_valid_node_id(global->my_node_id);
|
||||
|
||||
if (!need_priv_key && !need_pub_key && !need_node_id) {
|
||||
free_config(config);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Generate keys if needed
|
||||
char new_priv_key[HEXKEY_LEN + 1] = {0};
|
||||
char new_pub_key[HEXKEY_LEN + 1] = {0};
|
||||
uint64_t new_node_id = 0;
|
||||
|
||||
if (need_priv_key || need_pub_key) {
|
||||
struct secure_channel ctx;
|
||||
if (sc_generate_keypair(&ctx) != SC_OK) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "Failed to generate keypair");
|
||||
free_config(config);
|
||||
return -1;
|
||||
}
|
||||
bytes_to_hex(ctx.private_key, SC_PRIVKEY_SIZE, new_priv_key, sizeof(new_priv_key));
|
||||
bytes_to_hex(ctx.public_key, 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");
|
||||
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");
|
||||
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);
|
||||
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;
|
||||
|
||||
if (need_priv_key) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
if (need_priv_key && ret == 0) {
|
||||
if (insert_or_replace_option(&work_buf, &work_len, &buf_capacity, "my_private_key", new_priv_key) < 0) {
|
||||
ret = -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (need_pub_key && ret == 0) {
|
||||
if (insert_or_replace_option(&work_buf, &work_len, &buf_capacity, "my_public_key", new_pub_key) < 0) {
|
||||
ret = -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (ret == 0) {
|
||||
if (write_mem_to_file(filename, work_buf, work_len) < 0) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "Failed to write updated config file: %s", filename);
|
||||
ret = -1;
|
||||
}
|
||||
}
|
||||
|
||||
free(file_buf);
|
||||
free(work_buf);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
// config_updater.h - Configuration file updater
|
||||
#ifndef CONFIG_UPDATER_H
|
||||
#define CONFIG_UPDATER_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// Ensures config file has valid my_private_key, my_public_key, and my_node_id
|
||||
// If any are missing or invalid, generates and updates them
|
||||
// Returns 0 on success, -1 on error
|
||||
int config_ensure_keys_and_node_id(const char *filename);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // CONFIG_UPDATER_H
|
||||
@@ -34,6 +34,11 @@ struct ETCP_CONN {
|
||||
|
||||
// Криптография и состояние
|
||||
struct secure_channel* crypto_ctx;
|
||||
|
||||
// Информация о пире (для клиентов)
|
||||
uint64_t peer_node_id; // Node ID пира
|
||||
uint8_t has_peer_key; // Флаг наличия публичного ключа пира
|
||||
uint8_t peer_public_key[SC_PUBKEY_SIZE]; // Публичный ключ пира (бинарный)
|
||||
|
||||
struct ll_queue* input_queue;// отправитель -> input_queue -> etcp -> etcp_channel -> отправка (etcp_sockets)
|
||||
struct ll_queue* output_queue;// etcp_sockets -> etcp_channel -> etcp -> output_queue -> получатель
|
||||
|
||||
+88
-19
@@ -1,15 +1,35 @@
|
||||
#include "etcp_connections.h"
|
||||
#include <arpa/inet.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include "debug_config.h"
|
||||
#include "routing.h"
|
||||
#include "utun_instance.h"
|
||||
#include "config_parser.h"
|
||||
#include "crc32.h"
|
||||
#include "etcp.h"
|
||||
#include "packet_pool.h"
|
||||
#include "u_async.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
// Конвертация hex строки в бинарный формат
|
||||
static int hex_to_binary(const char *hex_str, uint8_t *binary, size_t binary_len) {
|
||||
if (!hex_str || !binary || strlen(hex_str) != binary_len * 2) return -1;
|
||||
|
||||
for (size_t i = 0; i < binary_len; i++) {
|
||||
unsigned int byte;
|
||||
if (sscanf(hex_str + i * 2, "%2x", &byte) != 1) return -1;
|
||||
binary[i] = (uint8_t)byte;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Forward declaration
|
||||
int etcp_socket_send(struct ETCP_SOCKET* sock, const uint8_t* data, size_t len, const struct sockaddr* to_addr);
|
||||
|
||||
// Бинарный поиск линка по ip_port_hash
|
||||
static int find_link_index(struct ETCP_CONNECTIONS* conns, uint32_t hash) {
|
||||
if (!conns || conns->num_channels == 0) return -1;
|
||||
@@ -80,13 +100,56 @@ static void remove_link(struct ETCP_CONNECTIONS* conns, uint32_t hash) {
|
||||
conns->num_channels--;
|
||||
}
|
||||
|
||||
struct ETCP_CONNECTIONS* etcp_connections_init(struct ETCP_SOCKET* socket) {
|
||||
if (!socket) return NULL;
|
||||
struct ETCP_CONNECTIONS* etcp_connections_init(struct ETCP_CONN* etcp, const char* bind_addr, uint16_t port) {
|
||||
if (!etcp) return NULL;
|
||||
|
||||
struct ETCP_CONNECTIONS* conns = calloc(1, sizeof(struct ETCP_CONNECTIONS));
|
||||
if (!conns) return NULL;
|
||||
if (!conns) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "Failed to allocate connections");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
conns->etcp = etcp;
|
||||
conns->conns = conns;
|
||||
conns->socket.etcp = etcp;
|
||||
conns->socket.socket_id = (uint32_t)(uintptr_t)&conns->socket;
|
||||
|
||||
conns->socket.fd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (conns->socket.fd < 0) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_CONNECTION, "Failed to create socket: %s", strerror(errno));
|
||||
free(conns);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int flags = fcntl(conns->socket.fd, F_GETFL, 0);
|
||||
fcntl(conns->socket.fd, F_SETFL, flags | O_NONBLOCK);
|
||||
|
||||
struct sockaddr_in* addr = (struct sockaddr_in*)&conns->socket.local_addr;
|
||||
addr->sin_family = AF_INET;
|
||||
addr->sin_port = htons(port);
|
||||
conns->socket.local_addr_len = sizeof(struct sockaddr_in);
|
||||
|
||||
if (bind_addr) {
|
||||
inet_pton(AF_INET, bind_addr, &addr->sin_addr);
|
||||
} else {
|
||||
addr->sin_addr.s_addr = INADDR_ANY;
|
||||
}
|
||||
|
||||
if (bind(conns->socket.fd, (struct sockaddr*)addr, conns->socket.local_addr_len) < 0) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_CONNECTION, "Failed to bind socket to %s:%u: %s",
|
||||
bind_addr ? bind_addr : "ANY", port, strerror(errno));
|
||||
close(conns->socket.fd);
|
||||
free(conns);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (getsockname(conns->socket.fd, (struct sockaddr*)addr, &conns->socket.local_addr_len) < 0) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_CONNECTION, "Failed to get socket name: %s", strerror(errno));
|
||||
close(conns->socket.fd);
|
||||
free(conns);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memcpy(&conns->socket, socket, sizeof(struct ETCP_SOCKET));
|
||||
return conns;
|
||||
}
|
||||
|
||||
@@ -97,12 +160,17 @@ void etcp_connections_destroy(struct ETCP_CONNECTIONS* conns) {
|
||||
etcp_link_close(conns->links[i]);
|
||||
}
|
||||
|
||||
if (conns->socket.fd >= 0) {
|
||||
close(conns->socket.fd);
|
||||
}
|
||||
|
||||
free(conns->links);
|
||||
free(conns);
|
||||
}
|
||||
|
||||
struct ETCP_LINK* etcp_link_new(struct ETCP_CONN* etcp, struct ETCP_SOCKET* socket,
|
||||
const struct sockaddr* remote_addr, socklen_t addr_len) {
|
||||
struct ETCP_CONNECTIONS* conns,
|
||||
const struct sockaddr* remote_addr, socklen_t addr_len) {
|
||||
if (!socket || !remote_addr || addr_len == 0) return NULL;
|
||||
|
||||
struct ETCP_LINK* link = calloc(1, sizeof(struct ETCP_LINK));
|
||||
@@ -110,6 +178,7 @@ struct ETCP_LINK* etcp_link_new(struct ETCP_CONN* etcp, struct ETCP_SOCKET* sock
|
||||
|
||||
link->socket = (struct ETCP_SOCKET*)socket;
|
||||
link->etcp = etcp;
|
||||
link->conns = conns;
|
||||
memcpy(&link->remote_addr, remote_addr, addr_len);
|
||||
link->remote_addr_len = addr_len;
|
||||
link->last_activity = time(NULL);
|
||||
@@ -150,16 +219,16 @@ int etcp_input(struct packet_buffer* pkt, struct ETCP_SOCKET* socket, struct ETC
|
||||
etcp_link_close(link);
|
||||
}
|
||||
|
||||
link = etcp_link_new(NULL, socket, src_addr, addr_len);
|
||||
link = etcp_link_new(NULL, socket, conns, src_addr, addr_len);
|
||||
if (!link) return -1;
|
||||
|
||||
uint8_t* p = &data[1];
|
||||
link->peer_node_id = 0;
|
||||
memcpy(&link->peer_node_id, p, 8);
|
||||
link->etcp->peer_node_id = 0;
|
||||
memcpy(&link->etcp->peer_node_id, p, 8);
|
||||
p += 8;
|
||||
|
||||
memcpy(link->peer_public_key, p, SC_PUBKEY_SIZE);
|
||||
link->has_peer_key = 1;
|
||||
memcpy(link->etcp->peer_public_key, p, SC_PUBKEY_SIZE);
|
||||
link->etcp->has_peer_key = 1;
|
||||
p += SC_PUBKEY_SIZE;
|
||||
|
||||
uint16_t peer_mtu = ntohs(*(uint16_t*)p);
|
||||
@@ -176,7 +245,7 @@ int etcp_input(struct packet_buffer* pkt, struct ETCP_SOCKET* socket, struct ETC
|
||||
|
||||
struct ETCP_LINK* link = etcp_link_find_by_addr(conns, src_addr, addr_len);
|
||||
if (!link) {
|
||||
struct ETCP_LINK* temp_link = etcp_link_new(NULL, socket, src_addr, addr_len);
|
||||
struct ETCP_LINK* temp_link = etcp_link_new(NULL, socket, conns, src_addr, addr_len);
|
||||
if (temp_link) {
|
||||
etcp_link_send_reset(temp_link);
|
||||
etcp_link_close(temp_link);
|
||||
@@ -189,8 +258,8 @@ int etcp_input(struct packet_buffer* pkt, struct ETCP_SOCKET* socket, struct ETC
|
||||
case ETCP_INIT_RESPONSE:
|
||||
if (pkt->metadata.data_len < 1 + 8 + 2 + 2) return -1;
|
||||
|
||||
link->peer_node_id = 0;
|
||||
memcpy(&link->peer_node_id, &data[1], 8);
|
||||
link->etcp->peer_node_id = 0;
|
||||
memcpy(&link->etcp->peer_node_id, &data[1], 8);
|
||||
|
||||
link->mtu = ntohs(*(uint16_t*)&data[1 + 8]);
|
||||
link->keepalive_interval = ntohs(*(uint16_t*)&data[1 + 8 + 2]);
|
||||
@@ -200,8 +269,8 @@ int etcp_input(struct packet_buffer* pkt, struct ETCP_SOCKET* socket, struct ETC
|
||||
case ETCP_CHANNEL_INIT:
|
||||
if (pkt->metadata.data_len < 1 + 8 + 2) return -1;
|
||||
|
||||
link->peer_node_id = 0;
|
||||
memcpy(&link->peer_node_id, &data[1], 8);
|
||||
link->etcp->peer_node_id = 0;
|
||||
memcpy(&link->etcp->peer_node_id, &data[1], 8);
|
||||
link->keepalive_interval = ntohs(*(uint16_t*)&data[1 + 8]);
|
||||
|
||||
return etcp_link_send_channel_response(link);
|
||||
@@ -209,8 +278,8 @@ int etcp_input(struct packet_buffer* pkt, struct ETCP_SOCKET* socket, struct ETC
|
||||
case ETCP_CHANNEL_RESPONSE:
|
||||
if (pkt->metadata.data_len < 1 + 8) return -1;
|
||||
|
||||
link->peer_node_id = 0;
|
||||
memcpy(&link->peer_node_id, &data[1], 8);
|
||||
link->etcp->peer_node_id = 0;
|
||||
memcpy(&link->etcp->peer_node_id, &data[1], 8);
|
||||
link->initialized = 1;
|
||||
break;
|
||||
|
||||
@@ -561,7 +630,7 @@ int init_connections(struct UTUN_INSTANCE* instance) {
|
||||
}
|
||||
|
||||
// Create connections manager
|
||||
struct ETCP_CONNECTIONS* conns = etcp_connections_init(sock);
|
||||
struct ETCP_CONNECTIONS* conns = etcp_connections_init(etcp, bind_ip_str, bind_port);
|
||||
if (!conns) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "Failed to create connections for %s", server->name);
|
||||
etcp_socket_destroy(sock);
|
||||
|
||||
+20
-16
@@ -32,6 +32,13 @@ struct ETCP_CONNECTIONS {
|
||||
// Дополнительные поля для управления соединениями
|
||||
struct ETCP_CONN* etcp; // Родительский ETCP instance
|
||||
struct ETCP_CONNECTIONS* conns;// Указатель на себя (для совместимости)
|
||||
|
||||
// Статистика
|
||||
size_t encrypt_errors;
|
||||
size_t decrypt_errors;
|
||||
size_t send_errors;
|
||||
size_t total_encrypted;
|
||||
size_t total_decrypted;
|
||||
};
|
||||
|
||||
// ETCP Link - одно динамическое соединение (один путь)
|
||||
@@ -41,16 +48,12 @@ struct ETCP_LINK {
|
||||
|
||||
struct ETCP_SOCKET* socket; // Сокет через который идет трафик
|
||||
struct ETCP_CONN* etcp; // Родительский ETCP instance
|
||||
struct ETCP_CONNECTIONS* conns; // Родительский connections (для статистики)
|
||||
|
||||
// Путь соединения
|
||||
struct sockaddr_storage remote_addr; // Удалённый адрес
|
||||
socklen_t remote_addr_len;
|
||||
|
||||
// Информация о пире
|
||||
uint64_t peer_node_id; // Node ID пира
|
||||
uint8_t peer_public_key[SC_PUBKEY_SIZE]; // Публичный ключ пира
|
||||
uint8_t has_peer_key; // Флаг наличия публичного ключа пира
|
||||
|
||||
// Параметры соединения
|
||||
uint16_t mtu; // MTU соединения
|
||||
uint16_t keepalive_interval; // Keepalive интервал
|
||||
@@ -59,19 +62,12 @@ struct ETCP_LINK {
|
||||
uint64_t last_activity; // Время последней активности
|
||||
};
|
||||
|
||||
// SOCKET FUNCTIONS (moved from etcp_sockets)
|
||||
struct ETCP_SOCKET* etcp_socket_create(struct ETCP_CONN* etcp, const char* bind_addr, uint16_t port);
|
||||
void etcp_socket_destroy(struct ETCP_SOCKET* sock);
|
||||
int etcp_socket_send(struct ETCP_SOCKET* sock, const uint8_t* data, size_t len, const struct sockaddr* to_addr);
|
||||
void etcp_socket_set_recv_callback(struct ETCP_SOCKET* sock, void (*callback)(struct ETCP_SOCKET*, struct packet_buffer*, void*), void* user_data);
|
||||
int etcp_socket_get_fd(const struct ETCP_SOCKET* sock);
|
||||
void etcp_socket_get_local_addr(const struct ETCP_SOCKET* sock, struct sockaddr_storage* addr, socklen_t* addr_len);
|
||||
int etcp_socket_set_option(struct ETCP_SOCKET* sock, int level, int optname, const void* optval, socklen_t optlen);
|
||||
|
||||
// CONNECTIONS FUNCTIONS
|
||||
struct ETCP_CONNECTIONS* etcp_connections_init(struct ETCP_SOCKET* socket);
|
||||
struct ETCP_CONNECTIONS* etcp_connections_init(struct ETCP_CONN* etcp, const char* bind_addr, uint16_t port);
|
||||
void etcp_connections_destroy(struct ETCP_CONNECTIONS* conns);
|
||||
struct ETCP_LINK* etcp_link_new(struct ETCP_CONN* etcp, struct ETCP_SOCKET* socket, const struct sockaddr* remote_addr, socklen_t addr_len);
|
||||
struct ETCP_LINK* etcp_link_new(struct ETCP_CONN* etcp, struct ETCP_SOCKET* socket,
|
||||
struct ETCP_CONNECTIONS* conns,
|
||||
const struct sockaddr* remote_addr, socklen_t addr_len);
|
||||
void etcp_link_close(struct ETCP_LINK* link);
|
||||
int etcp_input(struct packet_buffer* pkt, struct ETCP_SOCKET* socket, struct ETCP_CONNECTIONS* conns);
|
||||
int etcp_link_send(struct ETCP_CONN* etcp, struct ETCP_LINK* link, const uint8_t* data, size_t len);
|
||||
@@ -94,4 +90,12 @@ int etcp_link_send_reset(struct ETCP_LINK* link);
|
||||
// Utility functions
|
||||
size_t etcp_connections_get_channel_count(const struct ETCP_CONNECTIONS* conns);
|
||||
|
||||
// Получение статистики шифрования
|
||||
void etcp_connections_get_crypto_stats(const struct ETCP_CONNECTIONS* conns,
|
||||
size_t* encrypt_errors,
|
||||
size_t* decrypt_errors,
|
||||
size_t* send_errors,
|
||||
size_t* total_encrypted,
|
||||
size_t* total_decrypted);
|
||||
|
||||
#endif // ETCP_CONNECTIONS_H
|
||||
+22
-20
@@ -1,4 +1,4 @@
|
||||
Формат кодограммы:
|
||||
Формат кодограммы:
|
||||
------------------
|
||||
Каждая кодограмма состоит из обязательного заголовка и опциональных секций:
|
||||
1. Обязательный заголовок (4 байта):
|
||||
@@ -24,25 +24,27 @@
|
||||
обычно идет последней.
|
||||
|
||||
|
||||
Кодограммы с этими секциями обрабатываются в etcp_connections (в этих кодограммах всегда только одна секция):
|
||||
г) Init запрос - заголовок 0x02: (у инициирующей стороны всегда есть publick key удаленного пира)
|
||||
[0x02] [my_node_id 64bit] [my publick key, binary] [my mtu high] [my mty low] [keepalive high] [keepalive low]
|
||||
- Инициирует первый connection и + etcp instance
|
||||
|
||||
д) Init подтверждение - заголовок 0x03:
|
||||
[0x03] [my_node_id 64bit] [my mtu high] [my mty low] [keepalive high] [keepalive low]
|
||||
|
||||
г) Channel init запрос - добавляем дополнительный канал для подключения
|
||||
[0x04] [my_node_id 64bit] [keepalive high] [keepalive low]
|
||||
- Инициирует новый connection в существующем etcp instance
|
||||
|
||||
д) Channel init подтверждение - заголовок 0x05:
|
||||
[0x05] [my_node_id 64bit]
|
||||
- Подтверждение иниуиализации дополнительного канала
|
||||
|
||||
е) Reset запрос:
|
||||
[0x06]
|
||||
- отправляется в ответ отправителю, если соединение не инициализировано и получен пакет не init (0x02, 0x03)
|
||||
Кодограммы с этими секциями обрабатываются в etcp_connections (в этих кодограммах всегда только одна секция):
|
||||
г) Init запрос - заголовок 0x02:
|
||||
[0x02] [my_node_id 64bit] [my mtu high] [my mty low] [keepalive high] [keepalive low] [my publick key (32 байта, не шифруется)]
|
||||
- Инициирует первый connection и + etcp instance
|
||||
- Публичный ключ отправляется в конце пакета без шифрования, чтобы получатель мог установить его и расшифровать остальную часть пакета
|
||||
|
||||
д) Init подтверждение - заголовок 0x03:
|
||||
[0x03] [my_node_id 64bit] [my mtu high] [my mty low] [keepalive high] [keepalive low]
|
||||
- Подтверждение инициализации
|
||||
|
||||
г) Channel init запрос:
|
||||
[0x04] [my_node_id 64bit] [keepalive high] [keepalive low]
|
||||
- Инициирует новый connection в существующем etcp instance
|
||||
|
||||
д) Channel init подтверждение - заголовок 0x05:
|
||||
[0x05] [my_node_id 64bit] [my publick key (32 байта, не шифруется)]
|
||||
- Подтверждение иниуиализации дополнительного канала
|
||||
|
||||
е) Reset запрос:
|
||||
[0x06]
|
||||
- отправляется в ответ отправителю, если соединение не инициализировано и получен пакет не init (0x02, 0x03)
|
||||
|
||||
При получении init получатель пакета должен:
|
||||
- удалить ETCP_LINK с этим ip_port если оно есть
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// utun_instance.c - Root instance implementation
|
||||
#include "utun_instance.h"
|
||||
#include "config_parser.h"
|
||||
#include "config_updater.h"
|
||||
#include "tun_if.h"
|
||||
#include "routing.h"
|
||||
#include "etcp_connections.h"
|
||||
@@ -32,6 +33,13 @@ struct UTUN_INSTANCE* utun_instance_create(const char *config_file, const char *
|
||||
instance->running = 0;
|
||||
instance->log_fp = NULL;
|
||||
|
||||
// Ensure keys and node_id exist in config
|
||||
if (config_ensure_keys_and_node_id(config_file) < 0) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "Failed to ensure keys and node_id in config: %s", config_file);
|
||||
free(instance);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Load configuration
|
||||
instance->config = parse_config(config_file);
|
||||
if (!instance->config) {
|
||||
@@ -58,6 +66,9 @@ struct UTUN_INSTANCE* utun_instance_create(const char *config_file, const char *
|
||||
|
||||
// uasync has built-in wakeup mechanism, no need for manual pipe
|
||||
|
||||
// Set node_id from config
|
||||
instance->node_id = instance->config->global.my_node_id;
|
||||
|
||||
// Set global instance
|
||||
utun_instance_set(instance);
|
||||
|
||||
|
||||
+1
-1
@@ -27,7 +27,7 @@ struct UTUN_INSTANCE {
|
||||
void *tun_socket_id; // Socket ID from uasync_add_socket
|
||||
|
||||
// Identification
|
||||
uint32_t node_id;
|
||||
uint64_t node_id;
|
||||
|
||||
// Main async context
|
||||
struct uasync_s *ua;
|
||||
|
||||
Reference in new issue
Block a user