You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
359 lines
20 KiB
359 lines
20 KiB
#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 <stdint.h> |
|
#include <stddef.h> |
|
|
|
#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
|
|
|