|
|
|
|
@ -32,20 +32,29 @@
|
|
|
|
|
#include "../lib/mem.h" |
|
|
|
|
#include "etcp.h" |
|
|
|
|
|
|
|
|
|
// Читаемое имя типа сокета (CFG_SERVER_TYPE_*) для логов.
|
|
|
|
|
static const char* server_type_str(uint8_t type) { |
|
|
|
|
static const char* names[] = {"UNKNOWN", "PUBLIC", "NAT", "PRIVATE", "LOCAL"}; |
|
|
|
|
return type < 5 ? names[type] : "?"; |
|
|
|
|
} |
|
|
|
|
// Читаемое имя NAT-типа (NAT_TYPE_*/NAT_VERIFIED_*) для логов.
|
|
|
|
|
static const char* nat_type_str(uint8_t nat_type) { |
|
|
|
|
if (nat_type >= 4 && nat_type <= 7) nat_type -= 4; |
|
|
|
|
static const char* names[] = {"UNKNOWN", "EIM", "STRICT", "DIRECT"}; |
|
|
|
|
return nat_type < 4 ? names[nat_type] : "?"; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* ── Forward declarations ────────────────────────────────────────────
|
|
|
|
|
* Только static-функции, используемые раньше своего определения. |
|
|
|
|
* Не-static функции уже объявлены в etcp_connections.h. */ |
|
|
|
|
static void tcp_link_close_cb(struct stcp_link *sl, int err, void *arg); |
|
|
|
|
void etcp_link_enter_ready_tcp(struct ETCP_LINK *link); |
|
|
|
|
static void etcp_link_send_init(struct ETCP_LINK* link, uint8_t reset, uint8_t collision); |
|
|
|
|
static void etcp_link_init_timer_cbk(void* arg); |
|
|
|
|
static void burst_resp_timeout_cb(void* arg); |
|
|
|
|
static int etcp_tcp_send(struct ETCP_DGRAM* dgram); |
|
|
|
|
|
|
|
|
|
// TCP server: on new incoming connection → create ETCP_LINK + enter ready
|
|
|
|
|
// STCP-сервер: новое входящее TCP-соединение → найти/создать ETCP_CONN по node_id
|
|
|
|
|
// pubkey пира, создать TCP-линк и поднять его (ready).
|
|
|
|
|
void tcp_server_on_link(struct stcp_link *link, struct ETCP_SOCKET *tcp_sock) { |
|
|
|
|
struct UTUN_INSTANCE *inst = tcp_sock->instance; |
|
|
|
|
DEBUG_DEBUG(DEBUG_CATEGORY_DEBUG, "tcp_server_on_link: link=%p tcp_sock=%p inst=%p inst->ua=%p", |
|
|
|
|
@ -90,19 +99,9 @@ void tcp_server_on_link(struct stcp_link *link, struct ETCP_SOCKET *tcp_sock) {
|
|
|
|
|
etcp_link_enter_ready_tcp(tlink); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Forward declaration
|
|
|
|
|
void etcp_connections_read_callback_socket(socket_t sock, void* arg); |
|
|
|
|
static void etcp_link_remove_from_connections(struct ETCP_SOCKET* conn, struct ETCP_LINK* link); |
|
|
|
|
|
|
|
|
|
static void etcp_link_send_init(struct ETCP_LINK* link, uint8_t reset, uint8_t collision); |
|
|
|
|
//static int etcp_link_send_reset(struct ETCP_LINK* link);
|
|
|
|
|
static void etcp_link_init_timer_cbk(void* arg); |
|
|
|
|
static void link_stats_timer_cb(void* arg); |
|
|
|
|
static void burst_resp_timeout_cb(void* arg); |
|
|
|
|
static int etcp_tcp_send(struct ETCP_DGRAM* dgram); |
|
|
|
|
|
|
|
|
|
// === Burst sender functions ===
|
|
|
|
|
// === Burst sender: замер пропускной способности линка ===
|
|
|
|
|
|
|
|
|
|
// Старт burst: отправка пачки пакетов подряд для измерения bandwidth.
|
|
|
|
|
void etcp_link_burst_start(struct ETCP_LINK* link) { |
|
|
|
|
if (!link || !link->etcp || !link->etcp->instance) return; |
|
|
|
|
link->burst_active = 1; |
|
|
|
|
@ -116,6 +115,7 @@ void etcp_link_burst_start(struct ETCP_LINK* link) {
|
|
|
|
|
if (link->etcp->link_ready_for_send_fn) link->etcp->link_ready_for_send_fn(link->etcp); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Возможность стартовать burst: линк насыщен (inflight достиг лимита) и прошёл интервал.
|
|
|
|
|
void etcp_link_burst_check(struct ETCP_LINK* link) { |
|
|
|
|
if (!link || !link->etcp) return; |
|
|
|
|
if (link->burst_active) return; |
|
|
|
|
@ -126,6 +126,7 @@ void etcp_link_burst_check(struct ETCP_LINK* link) {
|
|
|
|
|
etcp_link_burst_start(link); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Завершение burst: сброс флага, запуск таймера ожидания ответа с замерами пира.
|
|
|
|
|
void etcp_link_burst_finish(struct ETCP_LINK* link) { |
|
|
|
|
if (!link || !link->etcp || !link->etcp->instance) return; |
|
|
|
|
link->burst_active = 0; |
|
|
|
|
@ -134,6 +135,7 @@ void etcp_link_burst_finish(struct ETCP_LINK* link) {
|
|
|
|
|
if (link->etcp->link_ready_for_send_fn) link->etcp->link_ready_for_send_fn(link->etcp); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Таймаут ожидания ответа на burst — просто сбрасываем таймер.
|
|
|
|
|
static void burst_resp_timeout_cb(void* arg) { |
|
|
|
|
struct ETCP_LINK* link = (struct ETCP_LINK*)arg; |
|
|
|
|
if (!link) return; |
|
|
|
|
@ -144,6 +146,8 @@ static void burst_resp_timeout_cb(void* arg) {
|
|
|
|
|
#define INIT_TIMEOUT_INITIAL 500 |
|
|
|
|
#define INIT_TIMEOUT_MAX 50000 |
|
|
|
|
|
|
|
|
|
// Клиент: собрать и отправить INIT_REQUEST (handshake) — заголовок, padding для обфускации
|
|
|
|
|
// размера и обфусцированный pubkey. reset=1 → запрос сброса эпохи, collision=1 → ответ на коллизию.
|
|
|
|
|
static void etcp_link_send_init(struct ETCP_LINK* link, uint8_t reset, uint8_t collision) { |
|
|
|
|
DEBUG_TRACE(DEBUG_CATEGORY_ETCP, ""); |
|
|
|
|
DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "link=%p, is_server=%d, reset=%d, collision=%d", link, link ? link->is_server : -1, reset, collision); |
|
|
|
|
@ -247,6 +251,7 @@ static void etcp_link_send_init(struct ETCP_LINK* link, uint8_t reset, uint8_t c
|
|
|
|
|
link->init_retry_count++; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Периодический повтор INIT до установления связи (с экспоненциальным backoff до INIT_TIMEOUT_MAX).
|
|
|
|
|
static void etcp_link_init_timer_cbk(void* arg) { |
|
|
|
|
DEBUG_TRACE(DEBUG_CATEGORY_ETCP, ""); |
|
|
|
|
struct ETCP_LINK* link = (struct ETCP_LINK*)arg; |
|
|
|
|
@ -266,6 +271,7 @@ static void etcp_link_init_timer_cbk(void* arg) {
|
|
|
|
|
else etcp_link_send_init(link,0,0); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Сброс таймера INIT на начальный таймаут (используется при каждом новом handshake).
|
|
|
|
|
void etcp_link_restart_init_timer(struct ETCP_LINK* link) { |
|
|
|
|
DEBUG_TRACE(DEBUG_CATEGORY_ETCP, ""); |
|
|
|
|
if (link->init_timer) uasync_cancel_timeout(link->etcp->instance->ua, link->init_timer); |
|
|
|
|
@ -273,7 +279,8 @@ void etcp_link_restart_init_timer(struct ETCP_LINK* link) {
|
|
|
|
|
link->init_timer = uasync_set_timeout(link->etcp->instance->ua, link->init_timeout, link, etcp_link_init_timer_cbk, "link_init"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void etcp_link_enter_init(struct ETCP_LINK* link) {//
|
|
|
|
|
// Клиент: переход в handshake — отправить INIT и запустить таймер повторов.
|
|
|
|
|
void etcp_link_enter_init(struct ETCP_LINK* link) { |
|
|
|
|
DEBUG_TRACE(DEBUG_CATEGORY_ETCP, ""); |
|
|
|
|
if (!link) return; |
|
|
|
|
int old_state = link->link_state; |
|
|
|
|
@ -285,6 +292,7 @@ void etcp_link_enter_init(struct ETCP_LINK* link) {//
|
|
|
|
|
etcp_link_restart_init_timer(link); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Клиент: повторный handshake после разрыва — уведомить о падении, отправить INIT, снять keepalive.
|
|
|
|
|
void etcp_link_enter_reinit(struct ETCP_LINK* link) { |
|
|
|
|
DEBUG_TRACE(DEBUG_CATEGORY_ETCP, ""); |
|
|
|
|
if (!link) return; |
|
|
|
|
@ -305,6 +313,7 @@ void etcp_link_enter_reinit(struct ETCP_LINK* link) {
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Собирает 19-байтовый ключ из sockaddr (port+addr+family) для hash-индекса links_queue.
|
|
|
|
|
static void sockaddr_to_key(struct sockaddr_storage* addr, uint8_t key[LINK_ADDR_KEY_SIZE], int is_tcp) { |
|
|
|
|
memset(key, 0, LINK_ADDR_KEY_SIZE); |
|
|
|
|
if (!addr) return; |
|
|
|
|
@ -323,6 +332,7 @@ static void sockaddr_to_key(struct sockaddr_storage* addr, uint8_t key[LINK_ADDR
|
|
|
|
|
|
|
|
|
|
// find_link_index, realloc_links, insert_link, remove_link — УДАЛЕНЫ. Заменены на ll_queue с хеш-индексом.
|
|
|
|
|
|
|
|
|
|
// Вставка линка в links_queue сокета по hash-ключу адреса; при дубле адреса другого коннекта — коллизия.
|
|
|
|
|
static int insert_link_queue(struct ETCP_SOCKET* e_sock, struct ETCP_LINK* link) { |
|
|
|
|
DEBUG_TRACE(DEBUG_CATEGORY_ETCP, ""); |
|
|
|
|
if (!e_sock || !link || !e_sock->links_queue) return -1; |
|
|
|
|
@ -368,6 +378,7 @@ static int insert_link_queue(struct ETCP_SOCKET* e_sock, struct ETCP_LINK* link)
|
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Удаление линка из links_queue сокета (освобождение hash-записи).
|
|
|
|
|
static void remove_link_from_queue(struct ETCP_LINK* link) { |
|
|
|
|
DEBUG_TRACE(DEBUG_CATEGORY_ETCP, ""); |
|
|
|
|
if (!link || !link->link_queue_entry) return; |
|
|
|
|
@ -377,6 +388,7 @@ static void remove_link_from_queue(struct ETCP_LINK* link) {
|
|
|
|
|
link->link_queue_entry = NULL; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Сравнение двух sockaddr_storage (family + addr + port) без учёта прочих полей.
|
|
|
|
|
static int sockaddr_equal(const struct sockaddr_storage* a, const struct sockaddr_storage* b) { |
|
|
|
|
if (!a || !b || a->ss_family != b->ss_family) return 0; |
|
|
|
|
if (a->ss_family == AF_INET) { |
|
|
|
|
@ -392,6 +404,7 @@ static int sockaddr_equal(const struct sockaddr_storage* a, const struct sockadd
|
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Поиск линка в сокете по remote-адресу (через hash-индекс links_queue).
|
|
|
|
|
struct ETCP_LINK* etcp_link_find_by_addr(struct ETCP_SOCKET* e_sock, struct sockaddr_storage* addr, int is_tcp) { |
|
|
|
|
DEBUG_TRACE(DEBUG_CATEGORY_ETCP, ""); |
|
|
|
|
if (!e_sock || !addr || !e_sock->links_queue) return NULL; |
|
|
|
|
@ -437,6 +450,7 @@ struct ETCP_LINK* etcp_select_collision_link(struct ETCP_CONN* conn, const struc
|
|
|
|
|
return NULL; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Поиск линка по remote_link_id (id, под которым линк известен пиру).
|
|
|
|
|
struct ETCP_LINK* etcp_link_find_by_remote_id(struct ETCP_CONN* conn, uint8_t remote_link_id) { |
|
|
|
|
DEBUG_TRACE(DEBUG_CATEGORY_ETCP, ""); |
|
|
|
|
if (!conn || remote_link_id == 0) return NULL; |
|
|
|
|
@ -448,6 +462,7 @@ struct ETCP_LINK* etcp_link_find_by_remote_id(struct ETCP_CONN* conn, uint8_t re
|
|
|
|
|
return NULL; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Выделение свободного local_link_id (0-255): битовая маска занятых id + циклический поиск.
|
|
|
|
|
int etcp_find_free_local_link_id(struct ETCP_CONN* etcp) { |
|
|
|
|
DEBUG_TRACE(DEBUG_CATEGORY_ETCP, ""); |
|
|
|
|
if (!etcp) return -1; |
|
|
|
|
@ -477,8 +492,8 @@ int etcp_find_free_local_link_id(struct ETCP_CONN* etcp) {
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// ===============================
|
|
|
|
|
|
|
|
|
|
// Создание UDP-сокета приёма/отправки кодограмм: bind к interface_addr, настройка буферов,
|
|
|
|
|
// регистрация в uasync и добавление в instance->etcp_sockets.
|
|
|
|
|
struct ETCP_SOCKET* etcp_socket_add(struct UTUN_INSTANCE* instance, struct CFG_SERVER* server) { |
|
|
|
|
DEBUG_TRACE(DEBUG_CATEGORY_ETCP, ""); |
|
|
|
|
if (!instance || !server) return NULL; |
|
|
|
|
@ -726,6 +741,7 @@ struct ETCP_SOCKET* etcp_socket_add(struct UTUN_INSTANCE* instance, struct CFG_S
|
|
|
|
|
return e_sock; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Удаление UDP-сокета: снятие с uasync, закрытие fd, закрытие всех линков и освобождение.
|
|
|
|
|
void etcp_socket_remove(struct ETCP_SOCKET* conn) { |
|
|
|
|
DEBUG_TRACE(DEBUG_CATEGORY_ETCP, ""); |
|
|
|
|
if (!conn) return; |
|
|
|
|
@ -767,6 +783,8 @@ void etcp_socket_remove(struct ETCP_SOCKET* conn) {
|
|
|
|
|
|
|
|
|
|
/* ── TCP socket management ── */ |
|
|
|
|
|
|
|
|
|
// TCP-сокет (запись ETCP_SOCKET с is_tcp=1): определение bind-адреса по конфигу.
|
|
|
|
|
// Сам listen/accept выполняет stcp_server — здесь только модель сокета.
|
|
|
|
|
struct ETCP_SOCKET* tcp_socket_add(struct UTUN_INSTANCE* instance, struct CFG_SERVER* server) { |
|
|
|
|
if (!instance || !server) return NULL; |
|
|
|
|
|
|
|
|
|
@ -855,6 +873,7 @@ struct ETCP_SOCKET* tcp_socket_add(struct UTUN_INSTANCE* instance, struct CFG_SE
|
|
|
|
|
return ts; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Удаление TCP-сокета из списка instance->etcp_sockets.
|
|
|
|
|
void tcp_socket_remove(struct ETCP_SOCKET* sock) { |
|
|
|
|
if (!sock || !sock->instance) return; |
|
|
|
|
struct UTUN_INSTANCE* inst = sock->instance; |
|
|
|
|
@ -865,6 +884,8 @@ void tcp_socket_remove(struct ETCP_SOCKET* sock) {
|
|
|
|
|
u_free(sock); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Создание нового ETCP_LINK: аллокация, выделение local_link_id, инициализация BBR/keepalive,
|
|
|
|
|
// вставка в список коннекта и links_queue сокета. Для outbound UDP сразу запускает handshake.
|
|
|
|
|
struct ETCP_LINK* etcp_link_new(struct ETCP_CONN* etcp, struct ETCP_SOCKET* conn, struct sockaddr_storage* remote_addr, uint8_t is_server) { |
|
|
|
|
DEBUG_TRACE(DEBUG_CATEGORY_ETCP, ""); |
|
|
|
|
if (!etcp) { DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "null etcp"); return NULL; } |
|
|
|
|
@ -970,6 +991,7 @@ struct ETCP_LINK* etcp_link_new(struct ETCP_CONN* etcp, struct ETCP_SOCKET* conn
|
|
|
|
|
return link; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Установка нового лимита inflight с клампингом в [INFLIGHT_LIM_MIN, max_inflight] и уведомлением коннекта.
|
|
|
|
|
void etcp_link_update_inflight_lim(struct ETCP_LINK* link, uint32_t new_lim) { |
|
|
|
|
if (!link || !link->etcp) return; |
|
|
|
|
if (new_lim < INFLIGHT_LIM_MIN) new_lim = INFLIGHT_LIM_MIN; |
|
|
|
|
@ -991,6 +1013,8 @@ static void etcp_inflight_nullify_link(struct ll_queue* q, struct ETCP_LINK* dea
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Закрытие линка: отмена таймеров (init/shaper/keepalive/tcp), удаление из списков и очереди,
|
|
|
|
|
// зануление ссылок inflight (защита от use-after-free) и освобождение памяти.
|
|
|
|
|
void etcp_link_close(struct ETCP_LINK* link) { |
|
|
|
|
DEBUG_TRACE(DEBUG_CATEGORY_ETCP, ""); |
|
|
|
|
if (!link) return; |
|
|
|
|
@ -1065,6 +1089,8 @@ void etcp_link_close(struct ETCP_LINK* link) {
|
|
|
|
|
|
|
|
|
|
// ====== TCP link helpers ======
|
|
|
|
|
|
|
|
|
|
// Поднять TCP-линк в ready: синхронизация reset-эпохи (gop/rid), keepalive, ed25519,
|
|
|
|
|
// mark initialized + link_status=1, уведомить коннект и loadbalancer.
|
|
|
|
|
void etcp_link_enter_ready_tcp(struct ETCP_LINK *link) { |
|
|
|
|
if (!link || !link->etcp) return; |
|
|
|
|
struct ETCP_CONN *etcp = link->etcp; |
|
|
|
|
@ -1108,6 +1134,7 @@ void etcp_link_enter_ready_tcp(struct ETCP_LINK *link) {
|
|
|
|
|
etcp->initialized, etcp->links_up, etcp->tcp_link_count); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Повторная попытка STCP-подключения с экспоненциальным backoff (до 30 с).
|
|
|
|
|
static void tcp_link_reconnect_cb(void *arg) { |
|
|
|
|
struct ETCP_LINK *link = (struct ETCP_LINK *)arg; |
|
|
|
|
if (!link || !link->etcp || !link->etcp->instance) return; |
|
|
|
|
@ -1122,6 +1149,7 @@ static void tcp_link_reconnect_cb(void *arg) {
|
|
|
|
|
stcp_link_set_on_close(sl, tcp_link_close_cb, link); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Исходящее TCP-подключение линка: stcp_link_connect + установка close-callback.
|
|
|
|
|
void etcp_tcp_link_start_connect(struct ETCP_LINK *link, struct sockaddr_storage *addr, uint16_t port) { |
|
|
|
|
if (!link || !link->etcp || !addr) return; |
|
|
|
|
/* link->conn опционален: NULL = без локального bind (ОС выбирает source IP/интерфейс).
|
|
|
|
|
@ -1136,6 +1164,7 @@ void etcp_tcp_link_start_connect(struct ETCP_LINK *link, struct sockaddr_storage
|
|
|
|
|
link->conn ? sockaddr_storage_to_str(&link->conn->interface_addr).str : "auto"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Запланировать реконнект TCP-линка после обрыва (через tcp_reconnect_timer).
|
|
|
|
|
void etcp_tcp_link_start_reconnect(struct ETCP_LINK *link) { |
|
|
|
|
if (!link || !link->etcp || !link->etcp->instance || link->is_server) return; |
|
|
|
|
if (link->etcp->state == 2) return; |
|
|
|
|
@ -1146,6 +1175,7 @@ void etcp_tcp_link_start_reconnect(struct ETCP_LINK *link) {
|
|
|
|
|
link->tcp_reconnect_timer = uasync_set_timeout(link->etcp->instance->ua, (int)(link->tcp_reconnect_delay_ms * 10), link, tcp_link_reconnect_cb, "tcp_rct"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Callback закрытия STCP-линка: серверный линк закрываем, клиентский — отправляем на реконнект.
|
|
|
|
|
static void tcp_link_close_cb(struct stcp_link *sl, int err, void *arg) { |
|
|
|
|
struct ETCP_LINK *link = (struct ETCP_LINK *)arg; |
|
|
|
|
if (!link || !link->etcp) return; |
|
|
|
|
@ -1173,6 +1203,7 @@ static void tcp_link_close_cb(struct stcp_link *sl, int err, void *arg) {
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Отправка ETCP_DGRAM по TCP: сборка буфера (timestamp+flag_up+data) и передача в stcp_link_send.
|
|
|
|
|
static int etcp_tcp_send(struct ETCP_DGRAM* dgram) { |
|
|
|
|
struct ETCP_LINK *link = dgram->link; |
|
|
|
|
if (!link->tcp_link || !stcp_link_is_ready(link->tcp_link)) return -1; |
|
|
|
|
@ -1198,6 +1229,7 @@ static int etcp_tcp_send(struct ETCP_DGRAM* dgram) {
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Единая точка отправки UDP: через send_hook (если задан) или socket_sendto напрямую.
|
|
|
|
|
ssize_t etcp_udp_send(struct ETCP_LINK* link, socket_t fd, const void* buf, size_t len, |
|
|
|
|
const struct sockaddr* addr, socklen_t addr_len) { |
|
|
|
|
if (link && link->send_hook) |
|
|
|
|
@ -1205,6 +1237,7 @@ ssize_t etcp_udp_send(struct ETCP_LINK* link, socket_t fd, const void* buf, size
|
|
|
|
|
return socket_sendto(fd, buf, len, addr, addr_len); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Зашифровать и отправить пакет: TCP → etcp_tcp_send, UDP → AES-CCM + socket_sendto.
|
|
|
|
|
int etcp_encrypt_send(struct ETCP_DGRAM* dgram) { |
|
|
|
|
if (!dgram || !dgram->link) { DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "Null pointer"); return -1; } |
|
|
|
|
if (dgram->link->is_tcp) return etcp_tcp_send(dgram); |
|
|
|
|
@ -1255,6 +1288,7 @@ es_err:
|
|
|
|
|
return -1; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Шифрует и отправляет готовый PING/PONG-датаграмм без линка (сырой sendto по fd).
|
|
|
|
|
static int etcp_send_ping_raw(struct ETCP_DGRAM* dgram, socket_t fd, sc_context_t* sc, const struct sockaddr_storage* addr) { |
|
|
|
|
if (!dgram || !sc || !addr) { |
|
|
|
|
DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "Null pointer in ping send"); |
|
|
|
|
@ -1292,6 +1326,7 @@ static int etcp_send_ping_raw(struct ETCP_DGRAM* dgram, socket_t fd, sc_context_
|
|
|
|
|
return (int)sent; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Копирует пользовательские данные запроса в ответ (эхо) с ограничением буфера.
|
|
|
|
|
static size_t etcp_build_ping_response_data(const uint8_t* req_data, size_t req_data_len, |
|
|
|
|
uint8_t* resp_buf, size_t resp_buf_len) { |
|
|
|
|
if (req_data_len > resp_buf_len) req_data_len = resp_buf_len; |
|
|
|
|
@ -1299,6 +1334,7 @@ static size_t etcp_build_ping_response_data(const uint8_t* req_data, size_t req_
|
|
|
|
|
return req_data_len; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Таймаут пинга: снять из pending_pings и вызвать callback с success=0.
|
|
|
|
|
static void ping_timeout_cbk(void* arg) { |
|
|
|
|
struct PING_CONTEXT* ctx = (struct PING_CONTEXT*)arg; |
|
|
|
|
if (!ctx || !ctx->cb) return; |
|
|
|
|
@ -1318,6 +1354,8 @@ static void ping_timeout_cbk(void* arg) {
|
|
|
|
|
u_free(ctx); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Отправка UDP-пинга через конкретный сокет: сборка PING-кодограммы (nonce, user_data,
|
|
|
|
|
// обфусцированный pubkey), регистрация в pending_pings с таймаутом.
|
|
|
|
|
int etcp_send_ping_to_socket(struct UTUN_INSTANCE* instance, struct ETCP_SOCKET* e_sock, |
|
|
|
|
const uint8_t* peer_pubkey_bin, const struct sockaddr_storage* addr, |
|
|
|
|
int timeout_ms, etcp_ping_callback_t cb, void* user_arg, |
|
|
|
|
@ -1420,6 +1458,7 @@ int etcp_send_ping_to_socket(struct UTUN_INSTANCE* instance, struct ETCP_SOCKET*
|
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Отправка UDP-пинга: подбор сокета по family адреса, делегирование в etcp_send_ping_to_socket.
|
|
|
|
|
int etcp_send_ping(struct UTUN_INSTANCE* instance, const uint8_t* peer_pubkey_bin, |
|
|
|
|
const struct sockaddr_storage* addr, int timeout_ms, |
|
|
|
|
etcp_ping_callback_t cb, void* user_arg, |
|
|
|
|
@ -1446,12 +1485,14 @@ struct tcp_ping_adapter {
|
|
|
|
|
void* arg; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
// Адаптер: приводит callback STCP-пинга к типу etcp_ping_callback_t.
|
|
|
|
|
static void tcp_ping_cb_adapter(int success, uint16_t rtt, void* arg) { |
|
|
|
|
struct tcp_ping_adapter* a = (struct tcp_ping_adapter*)arg; |
|
|
|
|
a->cb(success, rtt, a->arg, 0, NULL, 0); |
|
|
|
|
u_free(a); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// TCP-пинг: STCP-хендшейк с пиром и замер RTT по handshake (через stcp_ping_send).
|
|
|
|
|
int etcp_send_tcp_ping(struct UTUN_INSTANCE* instance, const uint8_t* peer_pubkey_bin, |
|
|
|
|
const struct sockaddr_storage* addr, int timeout_ms, |
|
|
|
|
etcp_ping_callback_t cb, void* user_arg) { |
|
|
|
|
@ -1487,6 +1528,7 @@ int etcp_send_tcp_ping(struct UTUN_INSTANCE* instance, const uint8_t* peer_pubke
|
|
|
|
|
|
|
|
|
|
// === Helpers extracted from etcp_connections_read_callback_socket ===
|
|
|
|
|
|
|
|
|
|
// Обработка входящего PING: обновление RTT (если флаг SEND_RTT), ответ PONG с эхо-данными.
|
|
|
|
|
static int handle_ping(struct ETCP_SOCKET* e_sock, struct ETCP_DGRAM* pkt, const struct sockaddr_storage* addr, const uint8_t* decrypted_pubkey, size_t pkt_len) { |
|
|
|
|
if (pkt_len < 23) { |
|
|
|
|
DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "PING too short: pkt_len=%zu from %s", pkt_len, sockaddr_storage_to_str(addr).str); |
|
|
|
|
@ -1543,11 +1585,13 @@ static int handle_ping(struct ETCP_SOCKET* e_sock, struct ETCP_DGRAM* pkt, const
|
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Пустой callback для RTT-ответа (получателю RTT-пинга ответ не важен).
|
|
|
|
|
static void rtt_send_ping_cb(int success, uint16_t rtt, void* arg, uint64_t nonce, |
|
|
|
|
const uint8_t* resp_data, size_t resp_data_len) { |
|
|
|
|
(void)success; (void)rtt; (void)arg; (void)nonce; (void)resp_data; (void)resp_data_len; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Обработка входящего PONG: поиск pending_pings по nonce, вызов callback с RTT и данными.
|
|
|
|
|
static int handle_pong(struct ETCP_SOCKET* e_sock, struct ETCP_DGRAM* pkt, const struct sockaddr_storage* addr, size_t pkt_len) { |
|
|
|
|
if (pkt_len < 23) { |
|
|
|
|
DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "PONG too short: pkt_len=%zu from %s", pkt_len, sockaddr_storage_to_str(addr).str); |
|
|
|
|
@ -1610,6 +1654,8 @@ static int handle_pong(struct ETCP_SOCKET* e_sock, struct ETCP_DGRAM* pkt, const
|
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Сервер: собрать и отправить INIT_RESPONSE (mtu, link_id, NAT-адрес клиента, ed25519),
|
|
|
|
|
// провести NAT-детекцию, поднять линк и запустить keepalive.
|
|
|
|
|
static void send_init_response(struct ETCP_SOCKET* e_sock, struct ETCP_DGRAM* pkt, struct ETCP_LINK* link, struct ETCP_CONN* conn, const struct ETCP_INIT_REQUEST_PKT* req, const struct sockaddr_storage* addr, uint8_t send_reset, uint32_t req_src_ip, uint16_t req_src_port, size_t pkt_len) { |
|
|
|
|
struct ETCP_INIT_RESPONSE_PKT* resp = (struct ETCP_INIT_RESPONSE_PKT*)pkt->data; |
|
|
|
|
|
|
|
|
|
@ -1747,6 +1793,7 @@ static void send_init_response(struct ETCP_SOCKET* e_sock, struct ETCP_DGRAM* pk
|
|
|
|
|
if (link->etcp->instance->nat_det) nat_detection_link_ready(link->etcp->instance->nat_det, link); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Клиент: обработка INIT_RESPONSE — MTU, link_id, NAT-адрес, ed25519, keepalive, подъём линка.
|
|
|
|
|
static int handle_init_response_client(struct ETCP_SOCKET* e_sock, struct ETCP_DGRAM* pkt, struct ETCP_LINK* link, uint8_t pkt_code, size_t pkt_len) { |
|
|
|
|
if (!e_sock) return -1; |
|
|
|
|
if (pkt_len < ETCP_INIT_RESP_SIZE) { |
|
|
|
|
@ -1860,6 +1907,8 @@ static int handle_init_response_client(struct ETCP_SOCKET* e_sock, struct ETCP_D
|
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Главный приёмник UDP-кодограмм: normal/init decrypt, диспетчеризация PING/PONG/INIT,
|
|
|
|
|
// создание/переиспользование линков и коннектов, обработка коллизий.
|
|
|
|
|
void etcp_connections_read_callback_socket(socket_t sock, void* arg) { |
|
|
|
|
DEBUG_TRACE(DEBUG_CATEGORY_ETCP, ""); |
|
|
|
|
// DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "etcp_connections_read_callback fd=%d, socket=%p", fd, arg);
|
|
|
|
|
@ -2298,6 +2347,8 @@ ec_fr:
|
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Обработка пакета, расшифрованного на установленном линке: keepalive-статус, INIT_RESPONSE,
|
|
|
|
|
// обычные данные → etcp_conn_input.
|
|
|
|
|
int etcp_packet_decrypted(struct ETCP_SOCKET* e_sock, struct ETCP_DGRAM* pkt, |
|
|
|
|
struct ETCP_LINK* link, size_t pkt_len) { |
|
|
|
|
DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "Decrypt ok - normal pkt"); |
|
|
|
|
@ -2362,9 +2413,6 @@ int etcp_packet_decrypted(struct ETCP_SOCKET* e_sock, struct ETCP_DGRAM* pkt,
|
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Initialize only sockets (servers for incoming connections)
|
|
|
|
|
// Called before topo_group_init() to populate etcp_sockets for nodeinfo
|
|
|
|
|
// Returns: 0 = all OK, 1 = partial success (some sockets failed), -1 = fatal error (no sockets)
|
|
|
|
|
/* Создаёт один серверный сокет из CFG_SERVER: UDP (etcp_socket_add) или TCP
|
|
|
|
|
* (tcp_socket_add + stcp_server_listen + stcp_server_list_add). |
|
|
|
|
* Линки к соединениям не добавляет — это забота вызывающего. |
|
|
|
|
@ -2401,6 +2449,9 @@ int etcp_create_server_socket(struct UTUN_INSTANCE* instance, struct CFG_SERVER*
|
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Создание всех listen-сокетов из конфига ([server] секции); автосокеты пропускаются.
|
|
|
|
|
// Вызывается до topo_group_init() чтобы заполнить etcp_sockets для nodeinfo.
|
|
|
|
|
// Возврат: 0 = OK, 1 = частичный успех (часть сокетов не создана), -1 = фатально (нет сокетов).
|
|
|
|
|
int init_sockets(struct UTUN_INSTANCE* instance) { |
|
|
|
|
DEBUG_TRACE(DEBUG_CATEGORY_ETCP, ""); |
|
|
|
|
if (!instance || !instance->config) return -1; |
|
|
|
|
@ -2547,6 +2598,7 @@ struct NODE_CONN_DIRECT* etcp_config_client_reality(struct UTUN_INSTANCE* instan
|
|
|
|
|
return handle; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Инициализация сети: listen-сокеты (если ещё нет) + client-соединения через NCD из конфига.
|
|
|
|
|
int init_connections(struct UTUN_INSTANCE* instance) { |
|
|
|
|
DEBUG_TRACE(DEBUG_CATEGORY_ETCP, ""); |
|
|
|
|
if (!instance || !instance->config) return -1; |
|
|
|
|
|