Browse Source

Refactor: TUN ioctl helpers, routing documentation; prepare for tun_if simplification

nodeinfo-routing-update
Evgeny 2 months ago
parent
commit
2e48f9a111
  1. 3
      AGENTS.md
  2. 21
      src/routing.c
  3. 210
      src/routing.h
  4. 152
      src/tun_if.c
  5. 24
      src/tun_if.h
  6. BIN
      tests/test_crypto
  7. BIN
      tests/test_ecc_encrypt
  8. BIN
      tests/test_etcp_100_packets
  9. BIN
      tests/test_etcp_crypto
  10. BIN
      tests/test_etcp_minimal
  11. BIN
      tests/test_etcp_simple_traffic
  12. BIN
      tests/test_etcp_two_instances
  13. BIN
      tests/test_pkt_normalizer_etcp
  14. BIN
      tests/test_pkt_normalizer_standalone

3
AGENTS.md

@ -245,6 +245,9 @@ Crypto: Fixed CCM nonce size to 13 bytes, all crypto tests passing
- нельзя использовать в одном потоке несколько u_async. один поток = всегда 1 uasync instance
- нельзя использовать sleep/usleep если есть uasync. Нужно использовать uasync_set_timeout.
Конфиги:
- в серверном только собственные ключи и нет секций [client]
- в клиентском есть собственные ключи и pubkey каждого сервера в секции [client]
тех задания для реализации в каталоге /doc.
/doc/etcp_protocol.txt - основной протокол (похож на TCP+QUIC, поддеиживает шифрования, load balancing multi-link, работу а неустойчивых каналах, утилизацию полосы и недопущение перегрузки каналов связи)

21
src/routing.c

@ -126,7 +126,7 @@ bool routing_table_insert(struct routing_table *table, const struct route_entry
struct route_entry *new_entries = realloc(table->entries, new_capacity * sizeof(struct route_entry));
if (!new_entries) {
DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "routing_table_insert: failed to expand routing table to %zu entries", new_capacity);
return false;
return false;
}
table->entries = new_entries;
@ -313,13 +313,13 @@ bool routing_get_all_routes(const struct routing_table *table, uint32_t network,
void routing_table_print(const struct routing_table *table) {
if (!table) return;
printf("\n=== Routing Table ===\n");
printf("Total routes: %zu\n", table->count);
printf("Dynamic subnets: %zu, Local subnets: %zu\n",
DEBUG_INFO(DEBUG_CATEGORY_ROUTING, "=== Routing Table ===");
DEBUG_INFO(DEBUG_CATEGORY_ROUTING, "Total routes: %zu", table->count);
DEBUG_INFO(DEBUG_CATEGORY_ROUTING, "Dynamic subnets: %zu, Local subnets: %zu",
table->dynamic_subnet_count / 2, table->local_subnet_count / 2);
if (table->count > 0) {
printf("\nRoutes:\n");
DEBUG_INFO(DEBUG_CATEGORY_ROUTING, "Routes:");
for (size_t i = 0; i < table->count; i++) {
const struct route_entry *entry = &table->entries[i];
char network_str[16], next_hop_str[16];
@ -327,27 +327,24 @@ void routing_table_print(const struct routing_table *table) {
ip_to_string(entry->network, network_str);
ip_to_string(entry->next_hop_ip, next_hop_str);
printf(" %zu: %s/%d -> %s [%s]\n",
DEBUG_INFO(DEBUG_CATEGORY_ROUTING, " %zu: %s/%d -> %s [%s]",
i + 1, network_str, entry->prefix_length, next_hop_str,
route_type_to_string(entry->type));
printf(" Bandwidth: %uK, Loss: %.2f%%, Latency: %ums, Hops: %d\n",
DEBUG_INFO(DEBUG_CATEGORY_ROUTING, " Bandwidth: %uK, Loss: %.2f%%, Latency: %ums, Hops: %d",
entry->metrics.bandwidth_kbps,
entry->metrics.packet_loss_rate / 100.0,
entry->metrics.latency_ms,
entry->metrics.hop_count);
printf(" Flags: %s%s%s%s\n",
DEBUG_INFO(DEBUG_CATEGORY_ROUTING, " Flags: %s%s%s%s",
(entry->flags & ROUTE_FLAG_ACTIVE) ? "ACTIVE " : "",
(entry->flags & ROUTE_FLAG_VALIDATED) ? "VALIDATED " : "",
(entry->flags & ROUTE_FLAG_ADVERTISED) ? "ADVERTISED " : "",
(entry->flags & ROUTE_FLAG_LEARNED) ? "LEARNED" : "");
printf("\n");
}
} else {
printf("\nNo routes configured.\n");
DEBUG_INFO(DEBUG_CATEGORY_ROUTING, "No routes configured.");
}
}

210
src/routing.h

@ -7,81 +7,195 @@
// Forward declarations
struct ETCP_CONNECTIONS;
// Типы маршрутов
/**
* @brief Типы маршрутов
*/
typedef enum {
ROUTE_TYPE_STATIC = 0,
ROUTE_TYPE_DYNAMIC = 1,
ROUTE_TYPE_LOCAL = 2,
ROUTE_TYPE_LEARNED = 3
ROUTE_TYPE_STATIC = 0, /**< Статический маршрут */
ROUTE_TYPE_DYNAMIC = 1, /**< Динамический маршрут */
ROUTE_TYPE_LOCAL = 2, /**< Локальный маршрут */
ROUTE_TYPE_LEARNED = 3 /**< Изученный маршрут */
} route_type_t;
// Флаги маршрута
/**
* @brief Флаги маршрута
*/
typedef enum {
ROUTE_FLAG_ACTIVE = (1 << 0),
ROUTE_FLAG_VALIDATED = (1 << 1),
ROUTE_FLAG_ADVERTISED = (1 << 2),
ROUTE_FLAG_LEARNED = (1 << 3)
ROUTE_FLAG_ACTIVE = (1 << 0), /**< Маршрут активен */
ROUTE_FLAG_VALIDATED = (1 << 1), /**< Маршрут валидирован */
ROUTE_FLAG_ADVERTISED = (1 << 2), /**< Маршрут анонсирован */
ROUTE_FLAG_LEARNED = (1 << 3) /**< Маршрут изучен */
} route_flags_t;
// Расширенные метрики маршрута
/**
* @brief Расширенные метрики маршрута
*
* Структура содержит дополнительные метрики для оценки качества маршрута.
*/
struct route_metrics {
uint32_t bandwidth_kbps;
uint16_t packet_loss_rate;
uint16_t latency_ms;
uint8_t hop_count;
uint64_t last_updated;
uint32_t bandwidth_kbps; /**< Пропускная способность в Кбит/с */
uint16_t packet_loss_rate; /**< Уровень потери пакетов (в промилле) */
uint16_t latency_ms; /**< Задержка в миллисекундах */
uint8_t hop_count; /**< Количество прыжков */
uint64_t last_updated; /**< Время последнего обновления (в микросекундах) */
};
// Расширенная запись маршрута
/**
* @brief Расширенная запись маршрута
*
* Структура представляет собой отдельную запись в таблице маршрутизации с детальной информацией о маршруте.
*/
struct route_entry {
uint32_t network;
uint8_t prefix_length;
uint32_t next_hop_ip;
struct ETCP_SOCKET* next_hop;
route_type_t type;
uint8_t flags;
struct route_metrics metrics;
uint64_t created_time;
uint64_t last_update;
uint64_t last_used;
uint32_t network; /**< Сетевой адрес */
uint8_t prefix_length; /**< Длина префикса подсети */
uint32_t next_hop_ip; /**< IP-адрес следующего хопа */
struct ETCP_SOCKET* next_hop; /**< Указатель на сокет следующего хопа */
route_type_t type; /**< Тип маршрута */
uint8_t flags; /**< Флаги маршрута */
struct route_metrics metrics; /**< Метрики маршрута */
uint64_t created_time; /**< Время создания (в микросекундах) */
uint64_t last_update; /**< Время последнего обновления (в микросекундах) */
uint64_t last_used; /**< Время последнего использования (в микросекундах) */
};
// Таблица маршрутизации
/**
* @brief Таблица маршрутизации
*
* Структура представляет собой таблицу маршрутизации, содержащую записи маршрутов, подсети и статистику.
*/
struct routing_table {
struct route_entry *entries;
size_t count;
size_t capacity;
uint32_t *dynamic_subnets;
size_t dynamic_subnet_count;
uint32_t *local_subnets;
size_t local_subnet_count;
struct route_entry *entries; /**< Массив записей маршрутов */
size_t count; /**< Текущее количество записей */
size_t capacity; /**< Максимальная емкость таблицы */
uint32_t *dynamic_subnets; /**< Динамические подсети (массив пар: сеть, префикс) */
size_t dynamic_subnet_count; /**< Количество динамических подсетей */
uint32_t *local_subnets; /**< Локальные подсети (массив пар: сеть, префикс) */
size_t local_subnet_count; /**< Количество локальных подсетей */
struct {
uint64_t total_routes;
uint64_t static_routes;
uint64_t dynamic_routes;
uint64_t local_routes;
uint64_t learned_routes;
uint64_t routes_added;
uint64_t routes_deleted;
uint64_t lookup_count;
uint64_t hit_count;
uint64_t routes_lookup_hits;
uint64_t routes_lookup_misses;
uint64_t validation_failures;
} stats;
uint64_t total_routes; /**< Общее количество маршрутов */
uint64_t static_routes; /**< Количество статических маршрутов */
uint64_t dynamic_routes; /**< Количество динамических маршрутов */
uint64_t local_routes; /**< Количество локальных маршрутов */
uint64_t learned_routes; /**< Количество изученных маршрутов */
uint64_t routes_added; /**< Количество добавленных маршрутов */
uint64_t routes_deleted; /**< Количество удаленных маршрутов */
uint64_t lookup_count; /**< Количество запросов поиска */
uint64_t hit_count; /**< Количество успешных поисков */
uint64_t routes_lookup_hits; /**< Количество попаданий в поиск маршрутов */
uint64_t routes_lookup_misses; /**< Количество промахов в поиск маршрутов */
uint64_t validation_failures; /**< Количество неудачных валидаций */
} stats; /**< Статистика таблицы маршрутизации */
};
/**
* @brief Создает новую таблицу маршрутизации
*
* @return Указатель на созданную таблицу или NULL в случае ошибки
*/
struct routing_table *routing_table_create(void);
/**
* @brief Уничтожает таблицу маршрутизации и освобождает ресурсы
*
* @param table Указатель на таблицу маршрутизации
*/
void routing_table_destroy(struct routing_table *table);
/**
* @brief Вставляет новую запись в таблицу маршрутизации
*
* @param table Указатель на таблицу маршрутизации
* @param entry Указатель на вставляемую запись маршрута
* @return true если вставка успешна, false иначе
*/
bool routing_table_insert(struct routing_table *table, const struct route_entry *entry);
/**
* @brief Удаляет запись из таблицы маршрутизации
*
* @param table Указатель на таблицу маршрутизации
* @param network Сетевой адрес
* @param prefix_length Длина префикса
* @param source_node_id Идентификатор источника узла
* @return true если удаление успешно, false иначе
*/
bool routing_table_delete(struct routing_table *table, uint32_t network, uint8_t prefix_length, uint32_t source_node_id);
/**
* @brief Выполняет поиск лучшего маршрута для заданного IP-адреса
*
* @param table Указатель на таблицу маршрутизации
* @param dest_ip Целевой IP-адрес
* @param best_route Указатель на структуру для хранения лучшего маршрута
* @return true если маршрут найден, false иначе
*/
bool routing_table_lookup(struct routing_table *table, uint32_t dest_ip, struct route_entry *best_route);
/**
* @brief Валидирует маршрут на основе типа и подсетей
*
* @param table Указатель на таблицу маршрутизации
* @param network Сетевой адрес
* @param prefix_length Длина префикса
* @param route_type Тип маршрута
* @return true если маршрут валиден, false иначе
*/
bool routing_validate_route(struct routing_table *table, uint32_t network, uint8_t prefix_length, route_type_t route_type);
/**
* @brief Добавляет динамическую подсеть в таблицу
*
* @param table Указатель на таблицу маршрутизации
* @param network Сетевой адрес
* @param prefix_length Длина префикса
* @return true если добавление успешно, false иначе
*/
bool routing_add_dynamic_subnet(struct routing_table *table, uint32_t network, uint8_t prefix_length);
/**
* @brief Добавляет локальную подсеть в таблицу
*
* @param table Указатель на таблицу маршрутизации
* @param network Сетевой адрес
* @param prefix_length Длина префикса
* @return true если добавление успешно, false иначе
*/
bool routing_add_local_subnet(struct routing_table *table, uint32_t network, uint8_t prefix_length);
/**
* @brief Получает все маршруты для заданной сети и префикса
*
* @param table Указатель на таблицу маршрутизации
* @param network Сетевой адрес
* @param prefix_length Длина префикса
* @param routes Указатель на массив маршрутов (будет выделен)
* @param count Указатель на количество найденных маршрутов
* @return true если операция успешна, false иначе
*/
bool routing_get_all_routes(const struct routing_table *table, uint32_t network, uint8_t prefix_length, struct route_entry **routes, size_t *count);
/**
* @brief Печатает содержимое таблицы маршрутизации
*
* @param table Указатель на таблицу маршрутизации
*/
void routing_table_print(const struct routing_table *table);
/**
* @brief Преобразует тип маршрута в строковое представление
*
* @param type Тип маршрута
* @return Строковое представление типа
*/
const char* route_type_to_string(route_type_t type);
/**
* @brief Преобразует IP-адрес в строковое представление
*
* @param ip IP-адрес в сетевом формате
* @param buffer Буфер для хранения строки (минимум 16 байт)
* @return Указатель на буфер с строкой
*/
char* ip_to_string(uint32_t ip, char *buffer);
#endif // ROUTING_H

152
src/tun_if.c

@ -4,7 +4,6 @@
#include "../lib/debug_config.h"
#include "../lib/u_async.h"
#include "etcp_connections.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@ -21,6 +20,51 @@
#include <linux/if_tun.h>
#include <errno.h>
// Helper for interface ioctl operations
static int if_ioctl(const char *ifname, unsigned long request, struct ifreq *ifr) {
int sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock < 0) {
DEBUG_ERROR(DEBUG_CATEGORY_TUN, "Failed to create ioctl socket: %s", strerror(errno));
return -1;
}
strncpy(ifr->ifr_name, ifname, IFNAMSIZ - 1);
ifr->ifr_name[IFNAMSIZ - 1] = '\0';
int ret = ioctl(sock, request, ifr);
if (ret < 0) {
DEBUG_ERROR(DEBUG_CATEGORY_TUN, "ioctl failed for %s (request=0x%lx): %s", ifname, request, strerror(errno));
}
close(sock);
return ret;
}
// Parse IP address and CIDR mask
static int parse_ip_mask(const char *ip_addr, struct in_addr *ip, struct in_addr *netmask) {
if (!ip_addr || !ip || !netmask) return -1;
char ip_str[INET_ADDRSTRLEN];
char *slash = strchr(ip_addr, '/');
if (!slash) return -1; // Require /mask
size_t ip_len = slash - ip_addr;
if (ip_len >= sizeof(ip_str)) return -1;
strncpy(ip_str, ip_addr, ip_len);
ip_str[ip_len] = '\0';
if (inet_pton(AF_INET, ip_str, ip) <= 0) return -1;
char *endptr;
long cidr = strtol(slash + 1, &endptr, 10);
if (*endptr != '\0' || cidr < 0 || cidr > 32) return -1;
uint32_t mask = (cidr == 0) ? 0 : ~((1U << (32 - cidr)) - 1);
netmask->s_addr = htonl(mask);
return 0;
}
// Create TUN device
static int create_tun_device(char *ifname, size_t ifname_len) {
struct ifreq ifr;
@ -53,45 +97,6 @@ static int create_tun_device(char *ifname, size_t ifname_len) {
return fd;
}
// Run system command
static int run_command(const char *cmd) {
int ret = system(cmd);
if (ret == -1) {
perror("system");
return -1;
}
if (WIFEXITED(ret) && WEXITSTATUS(ret) != 0) {
DEBUG_ERROR(DEBUG_CATEGORY_TUN, "Command failed: %s", cmd);
return -1;
}
return 0;
}
// Parse IP address and mask
static int parse_ip_mask(const char *ip_addr, char *ip, size_t ip_len, int *mask) {
if (!ip_addr || !ip || !mask) return -1;
char *slash = strchr(ip_addr, '/');
if (!slash) {
// Default mask /32
*mask = 32;
strncpy(ip, ip_addr, ip_len - 1);
ip[ip_len - 1] = '\0';
} else {
size_t ip_size = slash - ip_addr;
if (ip_size >= ip_len) return -1;
strncpy(ip, ip_addr, ip_size);
ip[ip_size] = '\0';
char *endptr;
long mask_val = strtol(slash + 1, &endptr, 10);
if (*endptr != '\0' || mask_val < 0 || mask_val > 32) return -1;
*mask = (int)mask_val;
}
return 0;
}
int tun_create(struct tun_config *config) {
if (!config) {
errno = EINVAL;
@ -137,19 +142,27 @@ int tun_set_ip(const char *ifname, const char *ip_addr) {
return -1;
}
char ip[64];
int mask;
if (parse_ip_mask(ip_addr, ip, sizeof(ip), &mask) < 0) {
struct in_addr ip, netmask;
if (parse_ip_mask(ip_addr, &ip, &netmask) < 0) {
DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "Invalid IP address format: %s", ip_addr);
errno = EINVAL;
return -1;
}
char cmd[256];
snprintf(cmd, sizeof(cmd), "ip addr add %s dev %s", ip_addr, ifname);
if (run_command(cmd) < 0) {
return -1;
}
struct ifreq ifr;
memset(&ifr, 0, sizeof(ifr));
// Set IP address
struct sockaddr_in *addr = (struct sockaddr_in *)&ifr.ifr_addr;
addr->sin_family = AF_INET;
addr->sin_addr = ip;
if (if_ioctl(ifname, SIOCSIFADDR, &ifr) < 0) return -1;
// Set netmask
addr = (struct sockaddr_in *)&ifr.ifr_netmask;
addr->sin_family = AF_INET;
addr->sin_addr = netmask;
if (if_ioctl(ifname, SIOCSIFNETMASK, &ifr) < 0) return -1;
return 0;
}
@ -160,11 +173,15 @@ int tun_set_up(const char *ifname) {
return -1;
}
char cmd[256];
snprintf(cmd, sizeof(cmd), "ip link set %s up", ifname);
if (run_command(cmd) < 0) {
return -1;
}
struct ifreq ifr;
memset(&ifr, 0, sizeof(ifr));
// Get current flags
if (if_ioctl(ifname, SIOCGIFFLAGS, &ifr) < 0) return -1;
// Set UP and RUNNING
ifr.ifr_flags |= IFF_UP | IFF_RUNNING;
if (if_ioctl(ifname, SIOCSIFFLAGS, &ifr) < 0) return -1;
return 0;
}
@ -175,11 +192,11 @@ int tun_set_mtu(const char *ifname, int mtu) {
return -1;
}
char cmd[256];
snprintf(cmd, sizeof(cmd), "ip link set %s mtu %d", ifname, mtu);
if (run_command(cmd) < 0) {
return -1;
}
struct ifreq ifr;
memset(&ifr, 0, sizeof(ifr));
ifr.ifr_mtu = mtu;
if (if_ioctl(ifname, SIOCSIFMTU, &ifr) < 0) return -1;
return 0;
}
@ -230,7 +247,7 @@ int tun_get_config(const char *ifname, struct tun_config *config) {
}
// TODO: Implement reading current interface configuration
// This would require parsing ip addr show output
// This would require ioctl SIOCGIFADDR, SIOCGIFNETMASK, etc.
memset(config, 0, sizeof(*config));
strncpy(config->ifname, ifname, sizeof(config->ifname) - 1);
@ -239,18 +256,6 @@ int tun_get_config(const char *ifname, struct tun_config *config) {
return 0;
}
// Extract destination IPv4 address from packet
static uint32_t tun_get_dest_ip(const uint8_t *packet, size_t len) {
if (len < 20) return 0; // Minimum IPv4 header size
// Check IP version (first nibble)
uint8_t version = (packet[0] >> 4) & 0x0F;
if (version != 4) return 0;
// Destination IP is at offset 16
uint32_t dest_ip;
memcpy(&dest_ip, packet + 16, 4);
return dest_ip;
}
// Extract destination IPv4 address from packet
static uint32_t get_dest_ip(const uint8_t *packet, size_t len) {
if (len < 20) return 0; // Minimum IPv4 header size
@ -263,7 +268,6 @@ static uint32_t get_dest_ip(const uint8_t *packet, size_t len) {
return dest_ip;
}
// Callback for TUN device read events
void tun_read_callback(int fd, void* user_arg) {
struct UTUN_INSTANCE *instance = (struct UTUN_INSTANCE*)user_arg;
@ -280,8 +284,7 @@ void tun_read_callback(int fd, void* user_arg) {
if (nread > 0) {
// Route packet based on destination IP
uint32_t dest_ip = get_dest_ip(buffer, nread);
//...
// ... (rest of the routing logic)
}
}
@ -314,4 +317,3 @@ void utun_instance_unregister_sockets(struct UTUN_INSTANCE *instance) {
DEBUG_INFO(DEBUG_CATEGORY_TUN, "Unregistered TUN socket: %s", instance->tun.ifname);
}
}

24
src/tun_if.h

@ -1,7 +1,6 @@
// tun_if.h - TUN interface management for utun
#ifndef TUN_IF_H
#define TUN_IF_H
#include <stdint.h>
#include <stddef.h>
#include <sys/types.h>
@ -17,18 +16,18 @@ extern "C" {
// TUN interface configuration
struct tun_config {
char ifname[16]; // Interface name (e.g., "tun12")
char ip_addr[64]; // IP address with mask (e.g., "10.0.0.1/24")
int mtu; // MTU size
int fd; // File descriptor
uint8_t is_up; // 1 if interface is up
char ifname[16]; // Interface name (e.g., "tun12")
char ip_addr[64]; // IP address with mask (e.g., "10.0.0.1/24")
int mtu; // MTU size
int fd; // File descriptor
uint8_t is_up; // 1 if interface is up
// Statistics
uint64_t bytes_read; // Bytes read from TUN
uint64_t bytes_written; // Bytes written to TUN
uint32_t packets_read; // Packets read from TUN
uint32_t packets_written; // Packets written to TUN
uint32_t read_errors; // Read errors
uint32_t write_errors; // Write errors
uint64_t bytes_read; // Bytes read from TUN
uint64_t bytes_written; // Bytes written to TUN
uint32_t packets_read; // Packets read from TUN
uint32_t packets_written; // Packets written to TUN
uint32_t read_errors; // Read errors
uint32_t write_errors; // Write errors
};
/**
@ -99,7 +98,6 @@ void utun_instance_unregister_sockets(struct UTUN_INSTANCE *instance);
// TUN callback function
void tun_read_callback(int fd, void* user_arg);
#ifdef __cplusplus
}
#endif

BIN
tests/test_crypto

Binary file not shown.

BIN
tests/test_ecc_encrypt

Binary file not shown.

BIN
tests/test_etcp_100_packets

Binary file not shown.

BIN
tests/test_etcp_crypto

Binary file not shown.

BIN
tests/test_etcp_minimal

Binary file not shown.

BIN
tests/test_etcp_simple_traffic

Binary file not shown.

BIN
tests/test_etcp_two_instances

Binary file not shown.

BIN
tests/test_pkt_normalizer_etcp

Binary file not shown.

BIN
tests/test_pkt_normalizer_standalone

Binary file not shown.
Loading…
Cancel
Save