From b8021efed87789a5b7ad1a2c86da72d6b4862084 Mon Sep 17 00:00:00 2001 From: evgeny Date: Fri, 23 Oct 2026 23:41:58 +0200 Subject: [PATCH] Validate UDP handshake MTU and nonzero path IDs before state updates --- src/transport_layer/etcp_connections.c | 13 ++++++++++++- src/transport_layer/etcp_connections.h | 6 ++++-- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/transport_layer/etcp_connections.c b/src/transport_layer/etcp_connections.c index 11e548b5..11252f45 100644 --- a/src/transport_layer/etcp_connections.c +++ b/src/transport_layer/etcp_connections.c @@ -2191,12 +2191,18 @@ static int handle_init_response_client(struct ETCP_SOCKET* e_sock, struct ETCP_D if (server_node_id != sc_derive_node_id_from_pubkey(link->etcp->crypto_ctx.peer_public_key)) { DEBUG_WARN(DEBUG_CATEGORY_ETCP, "INIT_RESPONSE node ID does not match authenticated peer key"); return 46; } + uint16_t remote_mtu = wire_read16(resp->mtu); + if (!resp->link_id || remote_mtu < ETCP_MIN_UDP_MTU(link->remote_addr.ss_family)) { + DEBUG_WARN(DEBUG_CATEGORY_ETCP, "INIT_RESPONSE invalid path: link_id=%u MTU=%u minimum=%u", + resp->link_id, remote_mtu, (unsigned)ETCP_MIN_UDP_MTU(link->remote_addr.ss_family)); + return 46; + } struct ETCP_CONN* conn = link->etcp; int old_state = link->link_state, old_status = etcp_link_record_rx(link, pkt); uint64_t resp_reset_id = wire_read64(resp->reset_id); DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "INIT_RESPONSE rid=%016llx", (unsigned long long)resp_reset_id); etcp_conn_apply_peer_reset_id(link->etcp, resp_reset_id); - link->mtu_remote = wire_read16(resp->mtu); + link->mtu_remote = remote_mtu; if (link->mtu_remote > PACKET_DATA_MAX_MTU) link->mtu_remote = PACKET_DATA_MAX_MTU; link->mtu = link->mtu_local < link->mtu_remote ? link->mtu_local : link->mtu_remote; etcp_update_mtu(link->etcp); @@ -2472,6 +2478,11 @@ static void etcp_process_packet(struct ETCP_SOCKET* e_sock, uint8_t* data, } uint64_t reset_id = wire_read64(req->reset_id); uint16_t mtu = wire_read16(req->mtu); + if (!req->link_id || mtu < ETCP_MIN_UDP_MTU(addr.ss_family)) { + DEBUG_WARN(DEBUG_CATEGORY_ETCP, "INIT_REQUEST invalid path: link_id=%u MTU=%u minimum=%u from=%s", + req->link_id, mtu, (unsigned)ETCP_MIN_UDP_MTU(addr.ss_family), sockaddr_storage_to_str(&addr).str); + errorcode = 7; goto ec_fr; + } uint16_t src_port = wire_read16(req->src_port); DEBUG_INFO(DEBUG_CATEGORY_ETCP, "INIT received: peer=0x%016llx mtu=%u link=%u sock=%u rid=%016llx src=%s", (unsigned long long)peer_id, mtu, req->link_id, req->socket_id, diff --git a/src/transport_layer/etcp_connections.h b/src/transport_layer/etcp_connections.h index cca3f2bb..da230a75 100644 --- a/src/transport_layer/etcp_connections.h +++ b/src/transport_layer/etcp_connections.h @@ -38,6 +38,8 @@ extern "C" { // PACKET_DATA_SIZE (2048) — это внутренний буфер аллокации/приёма, а не wire-MTU. #define PACKET_DATA_MAX_MTU 1500 #define ETCP_PAYLOAD_HEADER_SIZE 7 // type + seq:u32 + attempt_no:u16 (LE, 1..65535, общий номер для всех линков seq) +// Запас normalizer: длина u16 + хотя бы 1 байт кодограммы; меньший MTU даёт нулевой/переполненный frag_size. +#define ETCP_MIN_UDP_MTU(fam) (WIRE_OVERHEAD(fam) + ETCP_PAYLOAD_HEADER_SIZE + ACK_REZERV + 3) #define ETCP_ACK_ENTRY_SIZE 10 // seq:u32 + attempt_no:u16 + receiver_delay_us:u32; все числа LE #define ETCP_MAX_PAYLOAD_SIZE (PACKET_DATA_SIZE - ETCP_ACK_BASE_SIZE - ETCP_PAYLOAD_HEADER_SIZE) #define ETCP_RFC791_MIN_MTU 576 @@ -102,7 +104,7 @@ struct ETCP_INIT_REQUEST_PKT { uint8_t mtu[2]; // 17: client MTU (big-endian) uint8_t keepalive[2]; // 19: keepalive interval (big-endian) uint8_t recovery[2]; // 21: recovery interval/100 (big-endian) - uint8_t link_id; // 23: client's local link id + uint8_t link_id; // 23: client's local link id, 1..255 uint8_t socket_id; // 24: client's socket id uint8_t only_local; // 25: client only_local flag uint8_t type; // 26: client socket type (CFG_SERVER_TYPE_*) @@ -124,7 +126,7 @@ struct ETCP_INIT_RESPONSE_PKT { uint8_t node_id[8]; // 1: server node_id (big-endian) uint8_t reset_id[8]; // 9: локальная эпоха потока сервера (big-endian), не эхо запроса uint8_t mtu[2]; // 17: server MTU (big-endian) - uint8_t link_id; // 19: server's local link id + uint8_t link_id; // 19: server's local link id, 1..255 uint8_t remote_socket_id; // 20: ID серверного сокета, отправляющего ответ uint8_t only_local; // 21: server only_local flag uint8_t type; // 22: server socket type (CFG_SERVER_TYPE_*)