Финальный коммит: полный рефакторинг и улучшения
- Добавлен AGENTS.md - руководство для AI агентов разработки - Рефакторинг etcp: упрощен etcp_connection_create через etcp_conn_reset - Обновлены etcp_connections: улучшена работа с каналами - Обновлен routing: оптимизация таблиц маршрутизации - Обновлен tun_if: улучшена работа с TUN/TAP интерфейсом - Обновлен utun_instance: улучшено управление экземплярами - Обновлен test_routing_full: расширено тестирование - Добавлено больше документации и комментариев - Добавлен шаблон конфигурации src/utun.conf
This commit is contained in:
1 parent
aab0e445f7
commit
50e59bb835
13 files changed
+344
-114
No files matched your search
+3
-74
@@ -26,13 +26,6 @@
|
||||
|
||||
// Forward declarations for missing functions
|
||||
struct ETCP_CONN* etcp_connection_create(struct UTUN_INSTANCE* instance);
|
||||
void etcp_conn_reset(struct ETCP_CONN* etcp);
|
||||
void etcp_conn_input(struct ETCP_CONN* etcp, struct ETCP_DGRAM* pkt);
|
||||
void etcp_destroy(struct ETCP_CONN* etcp);
|
||||
static int etcp_link_send_init_response(struct ETCP_LINK* link, int mtu, uint16_t keepalive_interval);
|
||||
int etcp_input(struct ETCP_DGRAM* pkt);
|
||||
void packet_pool_free(struct memory_pool* pool, void* ptr);
|
||||
int etcp_connections_send(struct ETCP_SOCKET* e_sock, uint8_t* data, size_t len, struct sockaddr* addr, socklen_t addr_len);
|
||||
|
||||
// CONNECTION MANAGEMENT (!!!это всё должно быть static!!!)
|
||||
static void etcp_link_remove_from_connections(struct ETCP_SOCKET* conn, struct ETCP_LINK* link);
|
||||
@@ -40,7 +33,6 @@ static void etcp_link_remove_from_connections(struct ETCP_SOCKET* conn, struct E
|
||||
|
||||
// Отправка кодограмм протокола (!!!это всё должно быть static!!!)
|
||||
static int etcp_link_send_init(struct ETCP_LINK* link, int mtu, uint16_t keepalive_interval);
|
||||
static int etcp_link_send_init_response(struct ETCP_LINK* link, int mtu, uint16_t keepalive_interval);
|
||||
static int etcp_link_send_reset(struct ETCP_LINK* link);
|
||||
|
||||
static uint32_t sockaddr_hash(struct sockaddr_storage* addr) {
|
||||
@@ -280,47 +272,6 @@ int etcp_encrypt_send(struct ETCP_DGRAM* dgram) {
|
||||
if (sent < 0) dgram->link->send_errors++; else dgram->link->total_encrypted += sent;
|
||||
return (int)sent;
|
||||
}
|
||||
/*
|
||||
// надо править
|
||||
int etcp_link_send_init_response(struct ETCP_LINK* link, int mtu, uint16_t keepalive_interval) {
|
||||
uint8_t packet[1 + 8 + 2 + 2] = {0};
|
||||
uint8_t* p = packet;
|
||||
*p++ = ETCP_INIT_RESPONSE;
|
||||
|
||||
uint64_t node_id = link->conns->etcp->utun_i->node_id;
|
||||
memcpy(p, &node_id, 8); p += 8;
|
||||
|
||||
*p++ = (mtu >> 8) & 0xFF;
|
||||
*p++ = mtu & 0xFF;
|
||||
|
||||
*p++ = (keepalive_interval >> 8) & 0xFF;
|
||||
*p++ = keepalive_interval & 0xFF;
|
||||
|
||||
return etcp_encrypt_send(link->conns, packet, sizeof(packet), (struct sockaddr*)&link->remote_addr, link->remote_addr_len);
|
||||
}
|
||||
|
||||
// надо править
|
||||
int etcp_link_send_channel_init(struct ETCP_LINK* link, uint16_t keepalive_interval) {
|
||||
uint8_t packet[1 + 8 + 2] = {0};
|
||||
uint8_t* p = packet;
|
||||
*p++ = ETCP_CHANNEL_INIT;
|
||||
|
||||
uint64_t node_id = link->conns->etcp->utun_i->node_id;
|
||||
memcpy(p, &node_id, 8); p += 8;
|
||||
|
||||
*p++ = (keepalive_interval >> 8) & 0xFF;
|
||||
*p++ = keepalive_interval & 0xFF;
|
||||
|
||||
return etcp_encrypt_send(link->conns, packet, sizeof(packet), (struct sockaddr*)&link->remote_addr, link->remote_addr_len);
|
||||
}
|
||||
|
||||
// надо править
|
||||
int etcp_link_send_reset(struct ETCP_LINK* link) {
|
||||
uint8_t packet[1] = {ETCP_RESET};
|
||||
|
||||
return etcp_connections_send(link->conns, packet, sizeof(packet), (struct sockaddr*)&link->remote_addr, link->remote_addr_len);
|
||||
}
|
||||
*/
|
||||
|
||||
static void etcp_connections_read_callback(int fd, void* arg) {
|
||||
struct ETCP_SOCKET* e_sock = (struct ETCP_SOCKET*)arg;
|
||||
@@ -399,7 +350,7 @@ static void etcp_connections_read_callback(int fd, void* arg) {
|
||||
pkt->noencrypt_len=0;
|
||||
etcp_encrypt_send(pkt);
|
||||
|
||||
packet_pool_free(e_sock->instance->pkt_pool, pkt);
|
||||
memory_pool_free(e_sock->instance->pkt_pool, pkt);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -408,13 +359,13 @@ static void etcp_connections_read_callback(int fd, void* arg) {
|
||||
pkt->noencrypt_len=0;
|
||||
pkt->link=link;
|
||||
|
||||
etcp_conn_input(pkt->link->conn, pkt);
|
||||
etcp_conn_input(pkt);
|
||||
return;
|
||||
|
||||
ec_fr:
|
||||
e_sock->pkt_format_errors++;
|
||||
e_sock->errorcode=errorcode;
|
||||
packet_pool_free(e_sock->instance->pkt_pool, pkt);
|
||||
memory_pool_free(e_sock->instance->pkt_pool, pkt);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -532,25 +483,3 @@ int init_connections(struct UTUN_INSTANCE* instance) {
|
||||
printf("Initialized %d connections\n", instance->connections_count);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Simple implementations for missing functions
|
||||
int etcp_link_send_init_response(struct ETCP_LINK* link, int mtu, uint16_t keepalive_interval) {
|
||||
// TODO: Implement this function
|
||||
return 0;
|
||||
}
|
||||
|
||||
void packet_pool_free(struct memory_pool* pool, void* ptr) {
|
||||
// TODO: Implement this function
|
||||
// For now, just free the memory (this is a simplified version)
|
||||
if (ptr) {
|
||||
// In a real implementation, this would return to the pool
|
||||
// For now, we assume the memory came from the pool
|
||||
}
|
||||
}
|
||||
|
||||
int etcp_connections_send(struct ETCP_SOCKET* e_sock, uint8_t* data, size_t len, struct sockaddr* addr, socklen_t addr_len) {
|
||||
// TODO: Implement this function
|
||||
// For now, just send directly
|
||||
ssize_t sent = sendto(e_sock->fd, data, len, 0, addr, addr_len);
|
||||
return (sent < 0) ? -1 : (int)sent;
|
||||
}
|
||||
@@ -1,6 +1,8 @@
|
||||
#ifndef ETCP_CONNECTIONS_H
|
||||
#define ETCP_CONNECTIONS_H
|
||||
|
||||
// подмодуль ETCP который обслуживает сокеты ETCP для приёма-передачи пакетов и одно ETCP подключение через несколько каналов связи (failover)
|
||||
|
||||
#include "secure_channel.h"
|
||||
#include "utun_instance.h"
|
||||
#include <stdint.h>
|
||||
@@ -83,4 +85,8 @@ int etcp_encrypt_send(struct ETCP_DGRAM* dgram);// зашифровывает и
|
||||
// find link by address
|
||||
struct ETCP_LINK* etcp_link_find_by_addr(struct ETCP_SOCKET* e_sock, struct sockaddr_storage* addr);
|
||||
|
||||
// SEND FUNCTIONS
|
||||
// Отправка данных через сокет
|
||||
int etcp_connections_send(struct ETCP_SOCKET* e_sock, uint8_t* data, size_t len, struct sockaddr* addr, socklen_t addr_len);
|
||||
|
||||
#endif // ETCP_CONNECTIONS_H
|
||||
Executable → Regular
+33
-11
@@ -1,12 +1,11 @@
|
||||
Формат кодограммы:
|
||||
------------------
|
||||
Каждая кодограмма состоит из обязательного заголовка и опциональных секций:
|
||||
1. Обязательный заголовок (4 байта):
|
||||
[ID high][ID low][Timestamp high][Timestamp low]
|
||||
- ID: 16-битный циклический номер (0 = служебный пакет без данных)
|
||||
- Timestamp: время отправки в единицах 0.1 мс (циклическое)
|
||||
1. Обязательный заголовок всего пакета (2 байта) добавляется при передаче, есть во всех пакетах:
|
||||
[Timestamp high][Timestamp low]
|
||||
- Timestamp: время отправки в единицах 0.1 мс (циклическое). при переповторах время обновляется
|
||||
|
||||
2. Опциональные секции (одна или несколько):
|
||||
2. Опциональные секции (одна или несколько) добавляются в etcp.c:
|
||||
а) Подтверждения (ACK) - заголовок 0x01:
|
||||
[0x01][count][(id_hi,id_lo,ts_hi,ts_lo)×count][last_delivered_hi,lo][last_rx_hi,lo]
|
||||
- count: количество пар ID+timestamp (1-32)
|
||||
@@ -16,15 +15,36 @@
|
||||
[0x10+(count-1)][(id_hi,id_lo)×count][last_delivered_hi,lo][last_rx_hi,lo]
|
||||
- count: (заголовок & 0x0F) + 1 (1-32)
|
||||
- last_delivered_id, last_rx_id: для синхронизации состояния
|
||||
в) Полезная нагрузка - заголовок 0x00:
|
||||
[0x00][данные...]
|
||||
- Данные произвольной длины
|
||||
|
||||
Пакет может содержать несколько секций (например, ACK + данные). Секция с данными
|
||||
обычно идет последней.
|
||||
в) channel timestamp (добавляется после выбора канала передачи):
|
||||
[0x0F] [RET_Timestamp high][RET_Timestamp low] [RECV_Timestamp high][RECV_Timestamp low]
|
||||
- RET_Timestamp: это timestamp последнего принятого пакета по этому каналу ETCP_LINK плюс разница времени между принятием этого пакета и текущим временем. т.е. приёмная сторона по этому timestamp (и зная своё время) может просчитать время в пути туда + обратно
|
||||
- RECV_Timestamp: это timestamp времени приёма (т.е. отправляем время "когда мы получили этот пакет по локальном урмени") - по нему другая сторона сможет просчитать относительное время задержки в одну сторону (время туда без обратно).
|
||||
если последний пакет по этому каналу принят сильно давно (прошло более 30000 единиц времени) то channel timestamp не добавляем.
|
||||
|
||||
|
||||
Кодограммы с этими секциями обрабатываются в etcp_connections (в этих кодограммах всегда только одна секция):
|
||||
3. Полезная нагрузка - заголовок 0x00 (одна секция и всегда последняя):
|
||||
[0x00] [ID high][ID low] [данные...] - Данные пакета
|
||||
- ID: 16-битный циклический номер пакета.
|
||||
|
||||
Пакет может содержать несколько опциональных секций (например, ACK + данные).
|
||||
|
||||
|
||||
|
||||
Установка подключения для канала (реализщуется в etcp_connections):
|
||||
|
||||
когда etcp пытается отправить пакет через линк, то
|
||||
если в линке не инициализировано подключение и он клиент то он отбрасывает этот пакет и запускает процесс установки соединения.
|
||||
также процесс установки соединения инициируется при добавлении канала если это client.
|
||||
|
||||
процесс установки соединения:
|
||||
- отправляем init запрос и выставляем таймаут (сохраняем его в struct ETCP_LINK)
|
||||
- по таймауту повторяем init запросы, ведем счетчик запросов init.
|
||||
- когда получаем init подтверждение (отправляется в etcp_connections_read_callback) снимаем таймаут и выставляем флаг struct ETCP_LINK initialized=1
|
||||
|
||||
|
||||
Кодограммы с этими секциями обрабатываются в 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 байта, не шифруется)]
|
||||
- Инициирует новый connection для tcp instance. если tcp instance нет (первое подключение) - создаёт. Между нодами только одно подключение, но можно добавлять каналы.
|
||||
@@ -42,3 +62,5 @@
|
||||
- удалить 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)
|
||||
ETCP_CONN output_queue ->
|
||||
+13
-11
@@ -24,7 +24,7 @@ int parse_subnet(const char *subnet_str, uint32_t *network, uint8_t *prefix_leng
|
||||
if (prefix < 0 || prefix > 32) return -1;
|
||||
struct in_addr addr;
|
||||
if (inet_pton(AF_INET, ip, &addr) != 1) return -1;
|
||||
*network = addr.s_addr;
|
||||
*network = ntohl(addr.s_addr);
|
||||
*prefix_length = (uint8_t)prefix;
|
||||
return 0;
|
||||
}
|
||||
@@ -35,16 +35,16 @@ static int compare_routes(const void *a, const void *b) {
|
||||
const struct route_entry *route_a = (const struct route_entry *)a;
|
||||
const struct route_entry *route_b = (const struct route_entry *)b;
|
||||
|
||||
// First compare by network
|
||||
if (route_a->network != route_b->network) {
|
||||
return route_a->network < route_b->network ? -1 : 1;
|
||||
}
|
||||
|
||||
// Then by prefix length (longest prefix first)
|
||||
// First compare by prefix length (longest prefix first)
|
||||
if (route_b->prefix_length != route_a->prefix_length) {
|
||||
return route_b->prefix_length - route_a->prefix_length;
|
||||
}
|
||||
|
||||
// Then by network
|
||||
if (route_a->network != route_b->network) {
|
||||
return route_a->network < route_b->network ? -1 : 1;
|
||||
}
|
||||
|
||||
// Finally by metrics (best route first)
|
||||
if (route_a->metrics.bandwidth_kbps != route_b->metrics.bandwidth_kbps) {
|
||||
return route_b->metrics.bandwidth_kbps - route_a->metrics.bandwidth_kbps;
|
||||
@@ -137,6 +137,7 @@ bool routing_table_insert(struct routing_table *table, const struct route_entry
|
||||
|
||||
|
||||
// Insert and maintain sorted order
|
||||
table->stats.routes_added++;
|
||||
size_t insert_pos = table->count;
|
||||
for (size_t i = 0; i < table->count; i++) {
|
||||
if (compare_routes(&new_entry, &table->entries[i]) < 0) {
|
||||
@@ -197,14 +198,14 @@ bool routing_table_delete(struct routing_table *table, uint32_t network, uint8_t
|
||||
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 true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -234,6 +235,7 @@ bool routing_table_lookup(struct routing_table *table, uint32_t dest_ip, struct
|
||||
ip_to_string(entry->next_hop_ip, ip_str));
|
||||
|
||||
table->stats.hit_count++;
|
||||
table->stats.routes_lookup_hits++;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -409,7 +411,7 @@ char *ip_to_string(uint32_t ip, char *buffer) {
|
||||
if (!buffer) return NULL;
|
||||
|
||||
struct in_addr addr;
|
||||
addr.s_addr = ip;
|
||||
addr.s_addr = htonl(ip);
|
||||
strncpy(buffer, inet_ntoa(addr), 15);
|
||||
buffer[15] = '\0';
|
||||
return buffer;
|
||||
|
||||
+1
-1
@@ -37,7 +37,7 @@ struct route_entry {
|
||||
uint32_t network;
|
||||
uint8_t prefix_length;
|
||||
uint32_t next_hop_ip;
|
||||
struct ETCP_CONNECTIONS* next_hop;
|
||||
struct ETCP_SOCKET* next_hop;
|
||||
route_type_t type;
|
||||
uint8_t flags;
|
||||
struct route_metrics metrics;
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
internal_routing.c/h:
|
||||
|
||||
это модуль роутинга пакетов.
|
||||
пакеты приходят:
|
||||
1. из очередей ETCP (struct ETCP_CONN output_queue).
|
||||
при добавлении подключения (из конфига)) в вызовы etcp_connection_create/close надо добавить
|
||||
2. из tun интерфейса
|
||||
+16
-7
@@ -2,6 +2,9 @@
|
||||
#define _POSIX_C_SOURCE 200809L
|
||||
#include "tun_if.h"
|
||||
#include "../lib/debug_config.h"
|
||||
#include "routing.h"
|
||||
#include "../lib/u_async.h"
|
||||
#include "etcp_connections.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@@ -262,7 +265,7 @@ static uint32_t get_dest_ip(const uint8_t *packet, size_t len) {
|
||||
return dest_ip;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
// Callback for TUN device read events
|
||||
static void tun_read_callback(int fd, void* user_arg) {
|
||||
struct UTUN_INSTANCE *instance = (struct UTUN_INSTANCE*)user_arg;
|
||||
@@ -284,7 +287,11 @@ static void tun_read_callback(int fd, void* user_arg) {
|
||||
if (routing_table_lookup(instance->routing_table, dest_ip, &route)) {
|
||||
// Found route, send to next hop connection
|
||||
if (route.next_hop) {
|
||||
if (conn_send(route.next_hop, buffer, nread) < 0) {
|
||||
struct sockaddr_in dest_addr;
|
||||
memset(&dest_addr, 0, sizeof(dest_addr));
|
||||
dest_addr.sin_family = AF_INET;
|
||||
dest_addr.sin_addr.s_addr = route.next_hop_ip;
|
||||
if (etcp_connections_send(route.next_hop, buffer, nread, (struct sockaddr*)&dest_addr, sizeof(dest_addr)) < 0) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "Failed to send packet via route");
|
||||
}
|
||||
} else {
|
||||
@@ -308,8 +315,9 @@ int utun_instance_register_sockets(struct UTUN_INSTANCE *instance) {
|
||||
}
|
||||
|
||||
// Register TUN file descriptor
|
||||
if (uasync_add_socket(instance->ua, instance->tun.fd,
|
||||
tun_read_callback, NULL, NULL, instance) < 0) {
|
||||
instance->tun_socket_id = uasync_add_socket(instance->ua, instance->tun.fd,
|
||||
tun_read_callback, NULL, NULL, instance);
|
||||
if (!instance->tun_socket_id) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_TUN, "Failed to register TUN socket");
|
||||
return -1;
|
||||
}
|
||||
@@ -322,9 +330,10 @@ int utun_instance_register_sockets(struct UTUN_INSTANCE *instance) {
|
||||
void utun_instance_unregister_sockets(struct UTUN_INSTANCE *instance) {
|
||||
if (!instance || !instance->ua) return;
|
||||
|
||||
if (instance->tun.fd >= 0) {
|
||||
uasync_remove_socket(instance->ua, instance->tun.fd);
|
||||
if (instance->tun_socket_id) {
|
||||
uasync_remove_socket(instance->ua, instance->tun_socket_id);
|
||||
instance->tun_socket_id = NULL;
|
||||
DEBUG_INFO(DEBUG_CATEGORY_TUN, "Unregistered TUN socket");
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
@@ -6,6 +6,9 @@
|
||||
#include <stddef.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
// Forward declarations
|
||||
struct UTUN_INSTANCE;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
@@ -90,6 +93,10 @@ void tun_close(struct tun_config *config);
|
||||
*/
|
||||
int tun_get_config(const char *ifname, struct tun_config *config);
|
||||
|
||||
int utun_instance_register_sockets(struct UTUN_INSTANCE *instance);
|
||||
void utun_instance_unregister_sockets(struct UTUN_INSTANCE *instance);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
[global]
|
||||
tun_ip=10.0.0.1
|
||||
mtu=1500 # MTU for all connections (0 = use default 1500)
|
||||
control_ip=127.0.0.1
|
||||
control_port=12345
|
||||
net_debug=0
|
||||
|
||||
my_node_id=61be9d4cd3c60c2d
|
||||
my_private_key=1313912e5d34768983b0e06530a48c77816d228a5b5605e1ab3dc443d107a3dc
|
||||
my_public_key=
|
||||
|
||||
|
||||
[routing]
|
||||
allowed_subnet=10.0.0.0/24
|
||||
allowed_subnet=10.22.0.0/16
|
||||
allowed_subnet=10.23.0.0/16
|
||||
my_subnet=10.23.5.0/24
|
||||
my_subnet=10.23.6.0/24
|
||||
|
||||
# мои адреса и каналы
|
||||
[server: lo0_test]
|
||||
addr=127.0.0.1:1330
|
||||
#so_mark=100
|
||||
#netif=eth0
|
||||
type=nat # public / nat / private
|
||||
|
||||
[server: lan1]
|
||||
addr=192.168.29.117:1333
|
||||
so_mark=100
|
||||
netif=eth0
|
||||
type=public # public / nat / private
|
||||
|
||||
[client: client_test1]
|
||||
|
||||
# линки
|
||||
link=lo0_test:192.168.0.20:1234
|
||||
#link=wired1_fast:1.2.3.4:1234
|
||||
link=lan1:192.168.0.20:1234
|
||||
#link=wireless_bkp:1.2.3.4:1234
|
||||
|
||||
keepalive=1
|
||||
peer_public_key=deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbee
|
||||
@@ -54,7 +54,5 @@ void utun_instance_destroy(struct UTUN_INSTANCE* instance);
|
||||
int utun_instance_init(struct UTUN_INSTANCE *instance);
|
||||
void utun_instance_run(struct UTUN_INSTANCE *instance);
|
||||
void utun_instance_stop(struct UTUN_INSTANCE *instance);
|
||||
int utun_instance_register_sockets(struct UTUN_INSTANCE *instance);
|
||||
void utun_instance_unregister_sockets(struct UTUN_INSTANCE *instance);
|
||||
|
||||
#endif // UTUN_INSTANCE_H
|
||||
Reference in new issue
Block a user