Skip to content

Commit c2818e9

Browse files
committed
when in last_ack state, verify the segment passes the acceptability test
1 parent 88d73b7 commit c2818e9

4 files changed

Lines changed: 73 additions & 0 deletions

File tree

src/test/unit/unit.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -676,6 +676,7 @@ Suite *wolf_suite(void)
676676
tcase_add_test(tc_proto, test_regression_dhcp_nak_restarts_configuration);
677677
tcase_add_test(tc_proto, test_regression_dns_rcode_error_aborts_query);
678678
tcase_add_test(tc_proto, test_regression_udp_checksum_zero_substituted_with_ffff);
679+
tcase_add_test(tc_proto, test_regression_last_ack_rejects_out_of_window_segment);
679680

680681
tcase_add_test(tc_utils, test_transport_checksum);
681682
tcase_add_test(tc_utils, test_iphdr_set_checksum);

src/test/unit/unit_tests_proto.c

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4365,4 +4365,66 @@ START_TEST(test_regression_udp_checksum_zero_substituted_with_ffff)
43654365
END_TEST
43664366

43674367

4368+
/* RFC 9293 s3.10.7.2: segment acceptability applies to all synchronized
4369+
* states including LAST_ACK. The current LAST_ACK handler processes ACKs
4370+
* without checking tcp_segment_acceptable, so an out-of-window ACK could
4371+
* close the connection. */
4372+
START_TEST(test_regression_last_ack_rejects_out_of_window_segment)
4373+
{
4374+
struct wolfIP s;
4375+
struct tsocket *ts;
4376+
struct wolfIP_tcp_seg seg;
4377+
4378+
wolfIP_init(&s);
4379+
mock_link_init(&s);
4380+
wolfIP_ipconfig_set(&s, 0x0A000001U, 0xFFFFFF00U, 0);
4381+
4382+
ts = &s.tcpsockets[0];
4383+
memset(ts, 0, sizeof(*ts));
4384+
ts->proto = WI_IPPROTO_TCP;
4385+
ts->S = &s;
4386+
ts->if_idx = TEST_PRIMARY_IF;
4387+
ts->sock.tcp.state = TCP_LAST_ACK;
4388+
ts->sock.tcp.ack = 100;
4389+
ts->sock.tcp.seq = 1000;
4390+
ts->sock.tcp.snd_una = 1000;
4391+
ts->sock.tcp.last = 999; /* FIN was at seq 999 */
4392+
ts->sock.tcp.cwnd = TCP_MSS;
4393+
ts->sock.tcp.peer_rwnd = TCP_MSS;
4394+
ts->src_port = 1234;
4395+
ts->dst_port = 4321;
4396+
ts->local_ip = 0x0A000001U;
4397+
ts->remote_ip = 0x0A000002U;
4398+
queue_init(&ts->sock.tcp.rxbuf, ts->rxmem, RXBUF_SIZE, ts->sock.tcp.ack);
4399+
fifo_init(&ts->sock.tcp.txbuf, ts->txmem, TXBUF_SIZE);
4400+
4401+
/* Send an ACK with an out-of-window sequence number.
4402+
* rcv_nxt = 100, window = RXBUF_SIZE (20480), so seq = 99999
4403+
* is far outside the window. */
4404+
memset(&seg, 0, sizeof(seg));
4405+
seg.ip.ver_ihl = 0x45;
4406+
seg.ip.ttl = 64;
4407+
seg.ip.proto = WI_IPPROTO_TCP;
4408+
seg.ip.len = ee16(IP_HEADER_LEN + TCP_HEADER_LEN);
4409+
seg.ip.src = ee32(ts->remote_ip);
4410+
seg.ip.dst = ee32(ts->local_ip);
4411+
seg.dst_port = ee16(ts->src_port);
4412+
seg.src_port = ee16(ts->dst_port);
4413+
seg.hlen = TCP_HEADER_LEN << 2;
4414+
seg.flags = TCP_FLAG_ACK;
4415+
seg.seq = ee32(99999);
4416+
seg.ack = ee32(1001); /* ACKs the FIN */
4417+
seg.win = ee16(65535);
4418+
fix_tcp_checksums(&seg);
4419+
4420+
tcp_input(&s, TEST_PRIMARY_IF, &seg,
4421+
(uint32_t)(ETH_HEADER_LEN + IP_HEADER_LEN + TCP_HEADER_LEN));
4422+
4423+
/* The out-of-window segment must be rejected; connection must
4424+
* remain in LAST_ACK, not transition to CLOSED. */
4425+
ck_assert_int_eq(ts->sock.tcp.state, TCP_LAST_ACK);
4426+
}
4427+
END_TEST
4428+
4429+
43684430
/* ----------------------------------------------------------------------- */

src/test/unit/unit_tests_tcp_ack.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3020,6 +3020,8 @@ START_TEST(test_tcp_last_ack_closes_socket)
30203020
ts->remote_ip = remote_ip;
30213021
ts->src_port = local_port;
30223022
ts->dst_port = remote_port;
3023+
ts->sock.tcp.ack = 10;
3024+
queue_init(&ts->sock.tcp.rxbuf, ts->rxmem, RXBUF_SIZE, ts->sock.tcp.ack);
30233025
ts->sock.tcp.ctrl_rto_active = 1;
30243026
memset(&tmr, 0, sizeof(tmr));
30253027
tmr.cb = test_timer_cb;
@@ -3069,6 +3071,8 @@ START_TEST(test_tcp_last_ack_partial_ack_keeps_socket_and_timer)
30693071
ts->remote_ip = remote_ip;
30703072
ts->src_port = local_port;
30713073
ts->dst_port = remote_port;
3074+
ts->sock.tcp.ack = 10;
3075+
queue_init(&ts->sock.tcp.rxbuf, ts->rxmem, RXBUF_SIZE, ts->sock.tcp.ack);
30723076
ts->sock.tcp.ctrl_rto_active = 1;
30733077
memset(&tmr, 0, sizeof(tmr));
30743078
tmr.cb = test_timer_cb;

src/wolfip.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3753,6 +3753,12 @@ static void tcp_input(struct wolfIP *S, unsigned int if_idx,
37533753
}
37543754
}
37553755
} else if (t->sock.tcp.state == TCP_LAST_ACK) {
3756+
/* RFC 9293 s3.10.7.2: segment acceptability applies
3757+
* to all synchronized states including LAST_ACK. */
3758+
if (!tcp_segment_acceptable(t, tcp, tcplen)) {
3759+
tcp_send_ack(t);
3760+
continue;
3761+
}
37563762
/* RFC 9293 §3.10.7.4: if the SYN bit is set on a
37573763
* synchronized connection, send a challenge ACK and
37583764
* drop the segment (RFC 5961). */

0 commit comments

Comments
 (0)