#ifndef ETCP_CONNECTIONS_H #define ETCP_CONNECTIONS_H #ifdef __cplusplus extern "C" { #endif // подмодуль ETCP который обслуживает сокеты ETCP для приёма-передачи пакетов и одно ETCP подключение через несколько каналов связи (failover) #include "secure_channel.h" #include "utun_instance.h" #include "etcp_bbr.h" #include "../lib/socket_compat.h" #include "../lib/ll_queue.h" #include #include #define UDP_HDR_SIZE 28// размер udp header + ethernet заголовков (ipv4) [для ipv6 = 48 байт] #define UDP_SC_HDR_SIZE (13+8+4 + 5)// 13+8+4 - sc_nonce+tag size+crc, 5 - payload hdr #define ACK_REZERV 100// сколько байт резервировать под ack и прочие заголовки #define INFLIGHT_LIM_MIN 8192 // 8K #define INFLIGHT_LIM_MAX 1048576 // 1M #define PACKET_DATA_SIZE 1600//1536 #define PACKET_DATA_MAX_MTU 1600 #define ETCP_MAX_PAYLOAD_SIZE (PACKET_DATA_SIZE - ETCP_ACK_BASE_SIZE - 5) /* 1587 */ #define ETCP_RFC791_MIN_MTU 576 // Типы кодограмм протокола #define ETCP_INIT_REQUEST 0x02 #define ETCP_INIT_RESPONSE 0x03 #define ETCP_INIT_REQUEST_NOINIT 0x04 #define ETCP_INIT_RESPONSE_NOINIT 0x05 #define ETCP_PING 0x06 #define ETCP_PONG 0x07 #define ETCP_KEEPALIVE 0x08 #define ETCP_PING_FLAG_WANT_RTT 0x01 // в PONG: хочу получить RTT от пингера #define ETCP_PING_FLAG_SEND_RTT 0x02 // в PING: несу RTT для получателя /* Адаптивный keepalive */ #define KA_PERIOD_MIN_MS 200 #define KA_PERIOD_MAX_MS 10000 #define KA_TIMEOUT_MULT 10 /* timeout = period * mult */ #pragma pack(push, 1) struct ETCP_DGRAM {// пакет (незашифрованный) struct ETCP_LINK* link;// откуда получена или куда отправялем uint16_t data_len;// общий размер пакета не включая timestamp uint16_t noencrypt_len;// число байт (с конца) которые не надо шифровать. для передачи pubkey uint16_t timestamp;// timestamp отправляющего узла при отправке пакета uint8_t flag_up:1;// bit0 = up/down (recv_keepalive) uint8_t data[];// данные пакета (без timestamp) }; #pragma pack(pop) /* Размер зашифрованного заголовка ETCP_DGRAM (timestamp + flag_up + padding) */ #define ETCP_ENCRYPTED_HDR_SIZE (offsetof(struct ETCP_DGRAM, data) - offsetof(struct ETCP_DGRAM, timestamp)) /* Размер базового ACK: type(1) + count(1) + last_delivered_id(4) + rx_dup_count(2) */ #define ETCP_ACK_BASE_SIZE (2 + 4 + 2) // --- INIT packet wire formats (inside encrypted payload, before padding) --- // INIT REQUEST: client → server struct ETCP_INIT_REQUEST_PKT { uint8_t code; // 0: ETCP_INIT_REQUEST (0x02) или ETCP_INIT_REQUEST_NOINIT (0x04) uint8_t node_id[8]; // 1: sender node_id (big-endian) uint8_t session_id[4]; // 9: session (big-endian) uint8_t mtu[2]; // 13: client MTU (big-endian) uint8_t keepalive[2]; // 15: keepalive interval (big-endian) uint8_t recovery[2]; // 17: recovery interval/100 (big-endian) uint8_t link_id; // 19: client's local link id uint8_t socket_id; // 20: client's socket id uint8_t only_local; // 21: client only_local flag uint8_t type; // 22: client socket type (CFG_SERVER_TYPE_*) // V2 fields (NAT_DIRECT detection): uint8_t src_ipv4[4]; // 23: client interface_addr IPv4 (big-endian, 0 if N/A) uint8_t src_port[2]; // 27: client interface_addr port (big-endian) uint8_t collision; // 29: 1 = cross-connect, remote claims master uint8_t ed25519_pubkey[SC_PUBKEY_SIZE]; // 30: client Ed25519 pubkey (32 bytes) } __attribute__((packed)); #define ETCP_INIT_REQ_SIZE sizeof(struct ETCP_INIT_REQUEST_PKT) // INIT RESPONSE: server → client struct ETCP_INIT_RESPONSE_PKT { uint8_t code; // 0: ETCP_INIT_RESPONSE (0x03) или ETCP_INIT_RESPONSE_NOINIT (0x05) uint8_t node_id[8]; // 1: server node_id (big-endian) uint8_t session_id[4]; // 9: session (big-endian) uint8_t mtu[2]; // 13: server MTU (big-endian) uint8_t link_id; // 15: server's local link id uint8_t remote_socket_id; // 16: echo of client's socket_id uint8_t only_local; // 17: server only_local flag uint8_t type; // 18: server socket type (CFG_SERVER_TYPE_*) // V2 fields: uint8_t peer_ipv4[4]; // 19: client's external NAT address (big-endian) uint8_t peer_port[2]; // 23: client's external NAT port (big-endian) // V3 fields: uint8_t ed25519_pubkey[SC_PUBKEY_SIZE]; // 25: server Ed25519 pubkey (32 bytes) } __attribute__((packed)); #define ETCP_INIT_RESP_SIZE sizeof(struct ETCP_INIT_RESPONSE_PKT) typedef void (*etcp_ping_callback_t)(int success, uint16_t rtt, void* arg, uint64_t nonce, const uint8_t* resp_data, size_t resp_data_len); struct PING_CONTEXT { struct PING_CONTEXT* next; struct UTUN_INSTANCE* instance; etcp_ping_callback_t cb; void* arg; uint64_t nonce; void* timeout_timer; uint64_t send_time; // время отправки пинга в 0.1ms uint8_t peer_pubkey[SC_PUBKEY_SIZE]; uint8_t* user_data; size_t user_data_len; }; #define LINK_ADDR_KEY_SIZE 19 // port(2) + addr(16) + family(1) struct link_queue_entry { uint8_t key[LINK_ADDR_KEY_SIZE]; struct ETCP_LINK* link; }; // список активных подключений которые обслуживает сокет. каждый сокет может обслуживать много подключений struct ETCP_SOCKET { struct ETCP_SOCKET* next; // Linked list для всех соединений struct UTUN_INSTANCE* instance; char name[MAX_CONN_NAME_LEN]; // Socket name from config (e.g., "lan1" from [server: lan1]) socket_t fd; // UDP socket (cross-platform) struct sockaddr_storage local_addr; // Локальный адрес int mtu; // MTU для этого сокета int errorcode; size_t pkt_format_errors; void* socket_id; // Socket ID from uasync_add_socket uint8_t type; // CFG_SERVER_TYPE_PUBLIC/NAT/PRIVATE uint8_t sock_id; // unique socket id (0-255) for NAT matching uint8_t nat_type; // NAT_TYPE_* (detected by server) uint32_t local_defaultroute_ip; // auto-detected IPv4 for public servers (network byte order) uint8_t local_defaultroute_ip6[16]; // auto-detected IPv6 for public servers uint8_t only_local; // 1 = only local connections, no forwarding struct sockaddr_storage interface_addr; // адрес интерфейса: если bind на интерфейс - его IP, если 0.0.0.0 без интерфейса - IP интерфейса через который идет default route, иначе - адрес из конфига struct sockaddr_storage nat_addr; // NAT адрес (network byte order), ss_family=0 = не определён struct ll_queue* links_queue; // хеш-очередь линков, ключ = link_queue_entry.key (19 байт) }; // NAT check status #define NAT_CHECK_NONE 0 #define NAT_CHECK_WAITING 1 #define NAT_CHECK_IN_PROGRESS 2 #define NAT_CHECK_EIM 3 #define NAT_CHECK_STRICT 4 // NAT type (detected by server during NAT check) #define NAT_TYPE_UNKNOWN 0 #define NAT_TYPE_EIM 1 // Endpoint-Independent Mapping #define NAT_TYPE_STRICT 2 // Address/Restricted or Symmetric #define NAT_TYPE_DIRECT 3 // real public IP, no NAT (detected during INIT handshake) // Verified NAT types (published in nodeinfo after server-side NAT detection) // Values above CFG_SERVER_TYPE_PRIVATE to avoid collision with config types #define NAT_VERIFIED_UNKNOWN 4 // detection failed or inconclusive #define NAT_VERIFIED_EIM 5 // EIM NAT #define NAT_VERIFIED_STRICT 6 // strict NAT #define NAT_VERIFIED_DIRECT 7 // real public IP, no NAT // Тип функции-перехватчика отправки UDP. // Если link->send_hook != NULL, etcp_udp_send вызывает её вместо socket_sendto. struct ETCP_LINK; typedef ssize_t (*etcp_udp_send_fn_t)(socket_t fd, const void* buf, size_t len, const struct sockaddr* addr, socklen_t addr_len, struct ETCP_LINK* link, void* context); // ETCP Link - одно динамическое соединение (один путь) struct ETCP_LINK { struct ll_entry* link_queue_entry; // элемент в socket->links_queue struct ETCP_LINK* next; // Linked list подключений для ETCP_CONN (каждое подключение это child для ETCP_CONN) struct ETCP_CONN* etcp; // подключение (parent) struct ETCP_SOCKET* conn; // сокет через который работаем // Путь соединения struct sockaddr_storage remote_addr; // Удалённый адрес // Параметры соединения uint16_t mtu; // MTU общий uint16_t mtu_local; // MTU моего зла uint16_t mtu_remote; // MTU удаленного узла uint16_t keepalive_interval; // Keepalive интервал (x1ms) uint32_t recovery_interval; // recovery интервал (x0.1ms) uint8_t is_server; // инициирует подключение клиент uint8_t initialized; // Флаг инициализации (1=подтверждено или получен request) uint8_t local_link_id; // id моего линка uint8_t remote_link_id; // id этого линка на peer (устанавливается в момент initialized) uint8_t remote_socket_id; // socket id peer uint8_t remote_only_local; // only_local flag from peer uint8_t remote_type; // CFG_SERVER_TYPE_* (type of peer's socket) uint8_t nat_type; // NAT_TYPE_* (detected for this client link) uint8_t remote_ed25519_pubkey[SC_PUBKEY_SIZE]; // Ed25519 pubkey пира (из INIT handshake) uint8_t recv_keepalive; // 1 - up, 0 - down (принимаются ли пакеты) uint8_t remote_keepalive; // 1 - up, 0 - down (удаленная сторона сообщает - принимаются ли у нее пакеты) uint8_t link_status; // 1 - up, 0 - down (итоговый статус - если есть проблемы на любой стороне - линк down) uint8_t link_state; // 0 - just init, 1 - handshake, 2 - try reconnect, 3 - connected // Состояние установки соединения (только для клиентов) void* init_timer; // Таймер для повторов INIT (NULL=не подключается) uint16_t init_timeout; // Текущий таймаут в мс uint16_t init_retry_count; // Счетчик попыток // uint64_t last_activity; // Время последней активности uint64_t last_recv_local_time; // x0.1 ms uint16_t last_recv_timestamp; uint8_t last_recv_updated; // =1 при обновлении timestamp, =0 при отправке (чтобы не дублировать отправки при отсутствии обновлений) uint64_t shaper_load_time_tb; // основной в 0.1 мс units uint64_t shaper_sub_nanotime; // sub 0-999999 для 0.1 нс - 0.1 мс uint8_t shaper_state; void* shaper_timer; uint32_t inflight_bytes; uint32_t inflight_packets; uint32_t inflight_lim_bytes; // statistics size_t encrypt_errors; size_t decrypt_errors; size_t send_errors; size_t recv_errors; size_t total_encrypted; size_t total_decrypted; uint32_t total_retransmissions; uint64_t acked_bytes; // подтверждённых байт на этом линке uint64_t acked_packets; // подтверждённых пакетов на этом линке uint16_t rtt_last; // round trip (время отправки + приёма) uint32_t jitter; // Current jitter [>>16] x0.1 ms // rtt_avg10 удалён — заменён BBR (bbr->min_rtt_us/100) uint32_t recv_dt_avg_tx; // дельта времени для отправленных пакетов (относительное время отправки) x256 uint32_t recv_dt_avg_rx; // дельта времени для принятых пакетов (относительное время отправки) x256 uint16_t tt_last; // transmit time (время доставки отправленных пакетов) uint16_t rt_last; // recv time (время доставки принятых пакетов) uint32_t bandwidth; // Link bandwidth in Kbits/sec // NAT address tracking (from INIT_RESPONSE) uint32_t nat_ip; // NAT IPv4 address (network byte order), 0 = not set uint16_t nat_port; // NAT port (host byte order) uint32_t nat_changes_count; // Counter of NAT address changes uint32_t nat_hits_count; // Counter of NAT address matches (new init response with same IP:port) uint8_t nat_check_status; // NAT_CHECK_* // Keepalive state void* keepalive_timer; // Таймер для отправки keepalive пакетов uint32_t keepalive_timeout; // таймаут (ms) uint16_t ka_period_ms; // адаптивный период отправки keepalive (200→10000->200) uint8_t pkt_sent_since_keepalive; // Флаг: был ли отправлен пакет с последнего keepalive тика uint32_t keepalive_sent_count; // Счётчик отправленных keepalive uint32_t keepalive_recv_count; // Счётчик полученных keepalive uint16_t handshake_minsize; // минимальный размер udp при handshake uint16_t handshake_maxsize; // мax размер udp при handshake (выбирает рандом) // === Burst-измерение bandwidth === // Sender-сторона uint16_t burst_id; // монотонно возрастающий ID burst uint8_t burst_active; // 1 = burst в процессе отправки uint8_t burst_seq; // текущий номер пакета в burst (0..burst_count-1) uint8_t burst_count; // общее число пакетов в burst uint64_t burst_last_time_tb; // время последнего burst (0.1ms), для MIN_BURST_INTERVAL void* burst_resp_timer; // таймер ожидания ответа на burst uint32_t burst_target_bdp; // BDP из последнего успешного burst (байты) uint16_t burst_pkt_size; // сохранённый размер пакета для вычисления BW // Receiver-сторона uint16_t burst_recv_id; // ID отслеживаемого burst uint8_t burst_recv_count; // ожидаемое число пакетов в burst uint8_t burst_recv_next_seq; // следующий ожидаемый seq uint8_t burst_recv_valid; // 1 = порядок пакетов не нарушен uint8_t burst_recv_received; // сколько пакетов уже принято uint64_t burst_recv_times[16]; // время прихода каждого пакета (µs) uint16_t burst_recv_pkt_size; // размер пакета из MEAS_TS (для ответа) uint8_t burst_resp_pending; // 1 = есть готовый ответ для piggyback uint32_t burst_resp_gap_avg; // средний inter-packet gap (µs) uint32_t burst_resp_gap_min; // минимальный inter-packet gap (µs) uint8_t burst_resp_pkt_count; // число пакетов в измерении uint8_t burst_resp_valid; // валидность измерения // === BBR congestion control === struct bbr* bbr; // BBR state (per-link, создаётся в etcp_link_new) uint64_t delivered_bytes; // кумулятивно delivered bytes на линке (для round detection) uint64_t last_ack_time_tb; // 0.1ms timestamp последнего ACK (для interval_us) uint32_t bbr_pacing_rate; // bytes/sec output BBR → shaper uint32_t bbr_loss_since_ack; // счётчик потерь на линке с последнего ACK (для rs->lost) etcp_udp_send_fn_t send_hook; // NULL = socket_sendto напрямую void* send_hook_ctx; }; // Единая точка отправки всех ETCP-пакетов. 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); // INITIALIZATION // Создаёт только listen-сокеты из конфига (серверы для incoming connections) int init_sockets(struct UTUN_INSTANCE* instance); // Создаёт listen-сокеты и client connections из конфига int init_connections(struct UTUN_INSTANCE* instance); // SOCKET FUNCTIONS // добавляет новый версер (сокет для приёма и отправки кодограмм. обслуживает много подключений) struct ETCP_SOCKET* etcp_socket_add(struct UTUN_INSTANCE* instance, struct CFG_SERVER* server); // удаляет сокет и освобождает ресурсы (грохает все его подключения и сокет) void etcp_socket_remove(struct ETCP_SOCKET* conn); // connection functions // создает новый канал связи для etcp подключения (ETCP_CONN) struct ETCP_LINK* etcp_link_new(struct ETCP_CONN* etcp, struct ETCP_SOCKET* conn, struct sockaddr_storage* remote_addr, uint8_t is_server); void etcp_link_update_inflight_lim(struct ETCP_LINK* link, uint32_t new_lim); void etcp_link_close(struct ETCP_LINK* link); //int etcp_input_cbk(struct packet_buffer* pkt, struct ETCP_SOCKET* conn);// получает расшифрованный пакет 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); // find free local_link_id for connection // scans all links in connection, marks used ids in bit array // returns first free id (0-255) or -1 if all occupied int etcp_find_free_local_link_id(struct ETCP_CONN* etcp); // Burst measurement functions void etcp_link_burst_start(struct ETCP_LINK* link); void etcp_link_burst_check(struct ETCP_LINK* link); void etcp_link_burst_finish(struct ETCP_LINK* link); 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, const uint8_t* user_data, size_t user_data_len); // шлёт пинг на addr используя pubkey. в пакет помещает user_data[user_len]. при получении ответа или таймауте вызывает callback. // flags: ETCP_PING_FLAG_SEND_RTT — user_data содержит RTT для peer 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, const uint8_t* user_data, size_t user_data_len, uint8_t flags); void etcp_connections_read_callback_socket(socket_t sock, void* arg); #ifdef __cplusplus } #endif #endif // ETCP_CONNECTIONS_H