From 942736d604fc309da9d3c6398b642f53de5ce874 Mon Sep 17 00:00:00 2001 From: evgeny Date: Fri, 23 Oct 2026 23:42:49 +0200 Subject: [PATCH] Check accepted and rejected MTU boundaries in both UDP handshake directions --- tests/test_etcp_init_liveness.c | 39 +++++++++++++++++++++++++++++---- 1 file changed, 35 insertions(+), 4 deletions(-) diff --git a/tests/test_etcp_init_liveness.c b/tests/test_etcp_init_liveness.c index 16e493de..847e7aa4 100644 --- a/tests/test_etcp_init_liveness.c +++ b/tests/test_etcp_init_liveness.c @@ -252,12 +252,12 @@ static void request_boundaries(unsigned established) { request.code = variant ? ETCP_INIT_REQUEST_NOINIT : ETCP_INIT_REQUEST; for (unsigned invalid = 0; invalid < sizeof(request) + sizeof(request.node_id) + 5; invalid++) { unsigned length = invalid < sizeof(request) ? invalid : sizeof(request); - unsigned fault = invalid - sizeof(request); + unsigned fault = invalid < sizeof(request) ? 0 : invalid - sizeof(request); uint8_t saved_mtu[2]; memcpy(saved_mtu, request.mtu, 2); uint8_t saved_id = request.link_id; if (invalid >= sizeof(request) && fault < 8) request.node_id[fault] ^= 1; if (invalid >= sizeof(request) && fault >= 8 && fault < 12) { - const uint16_t values[] = {0, 1, 100, WIRE_OVERHEAD(AF_INET) + ETCP_PAYLOAD_HEADER_SIZE + ACK_REZERV + 2}; + const uint16_t values[] = {0, 1, 100, ETCP_MIN_UDP_MTU(AF_INET) - 1}; request.mtu[0] = values[fault - 8] >> 8; request.mtu[1] = values[fault - 8]; } if (invalid >= sizeof(request) && fault == 12) request.link_id = 0; @@ -294,6 +294,16 @@ static void request_boundaries(unsigned established) { CHECK(link->initialized && link->remote_keepalive == flag && link->recv_keepalive); accepted++; } + const uint16_t mtus[] = {ETCP_MIN_UDP_MTU(AF_INET), PACKET_DATA_MAX_MTU, UINT16_MAX}; + for (unsigned i = 0; i < 3; i++) { + request.mtu[0] = mtus[i] >> 8; request.mtu[1] = mtus[i]; + size_t errors = ep[1].socket->pkt_format_errors; + send_init_request_body(&request, sizeof(request), 1); + CHECK(ep[1].socket->pkt_format_errors == errors); + CHECK(first_link(1)->mtu_remote == (mtus[i] > PACKET_DATA_MAX_MTU ? PACKET_DATA_MAX_MTU : mtus[i])); + CHECK(ep[1].conn->normalizer->frag_size >= 3 && ep[1].conn->normalizer->frag_size < PACKET_DATA_SIZE); + accepted++; + } } DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "INIT_REQUEST boundaries established=%u: rejected=%u accepted=%u", established, rejected, accepted); teardown(); @@ -318,10 +328,20 @@ static void response_boundaries(void) { unsigned rejected = 0, accepted = 0; for (unsigned variant = 0; variant < 2; variant++) { response.code = variant ? ETCP_INIT_RESPONSE_NOINIT : ETCP_INIT_RESPONSE; - for (unsigned len = 1; len <= sizeof(response) + 1; len++) { + for (unsigned invalid = 1; invalid <= sizeof(response) + 1 + 5; invalid++) { + unsigned len = invalid <= sizeof(response) + 1 ? invalid : sizeof(response); struct ETCP_DGRAM* pkt = memory_pool_alloc(ep[0].inst->pkt_pool); CHECK(pkt); memcpy(pkt->data, &response, sizeof(response)); pkt->data[sizeof(response)] = 0; - if (len >= sizeof(response)) pkt->data[1] ^= 1; /* Полное тело с чужим node_id тоже недопустимо. */ + if (invalid <= sizeof(response) + 1 && len >= sizeof(response)) pkt->data[1] ^= 1; + if (invalid > sizeof(response) + 1) { + unsigned fault = invalid - sizeof(response) - 2; + struct ETCP_INIT_RESPONSE_PKT *bad = (struct ETCP_INIT_RESPONSE_PKT*)pkt->data; + if (fault == 4) bad->link_id = 0; + else { + const uint16_t values[] = {0, 1, 100, ETCP_MIN_UDP_MTU(AF_INET) - 1}; + bad->mtu[0] = values[fault] >> 8; bad->mtu[1] = values[fault]; + } + } pkt->timestamp = 123; pkt->flag_up = 0; struct ETCP_LINK before_link; struct ETCP_CONN before_conn; @@ -346,6 +366,17 @@ static void response_boundaries(void) { CHECK(link->last_recv_timestamp == 456 && !ep[0].conn->callbacks_running); CHECK(ep[0].conn->reset_id == epoch && !ep[0].reinit); accepted++; } + const uint16_t mtus[] = {ETCP_MIN_UDP_MTU(AF_INET), PACKET_DATA_MAX_MTU, UINT16_MAX}; + for (unsigned i = 0; i < 3; i++) { + struct ETCP_DGRAM *pkt = memory_pool_alloc(ep[0].inst->pkt_pool); CHECK(pkt); + memcpy(pkt->data, &response, sizeof(response)); pkt->timestamp = 456; pkt->flag_up = 1; + struct ETCP_INIT_RESPONSE_PKT *valid = (struct ETCP_INIT_RESPONSE_PKT*)pkt->data; + valid->mtu[0] = mtus[i] >> 8; valid->mtu[1] = mtus[i]; + CHECK(etcp_packet_decrypted(ep[0].socket, pkt, link, sizeof(response) + ETCP_ENCRYPTED_HDR_SIZE) == 0); + CHECK(link->mtu_remote == (mtus[i] > PACKET_DATA_MAX_MTU ? PACKET_DATA_MAX_MTU : mtus[i])); + CHECK(ep[0].conn->normalizer->frag_size >= 3 && ep[0].conn->normalizer->frag_size < PACKET_DATA_SIZE); + accepted++; + } } CHECK(ep[0].down == 6 && ep[0].up == 7); DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "INIT_RESPONSE boundaries: rejected=%u accepted=%u (both codes, padding, flag_up=0/1)",