Skip to content

Commit 20489a1

Browse files
shrek-wangkartben
authored andcommitted
net: tcp: Fix TCP reset issue
According to RFC793 chapter3.5 with the 'Reset Processing' part, "In the SYN-SENT state (a RST received in response to an initial SYN), the RST is acceptable if the ACK field acknowledges the SYN." So, in the net_tcp_reply_rst() we should use 'ack++' if no ACK flag but have SYN flag. And, all the RST packet should use net_tcp_reply_rst() instead of tcp_out(). Signed-off-by: Shrek Wang <[email protected]>
1 parent 2c10b2f commit 20489a1

File tree

2 files changed

+21
-10
lines changed

2 files changed

+21
-10
lines changed

subsys/net/ip/tcp.c

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1514,6 +1514,10 @@ void net_tcp_reply_rst(struct net_pkt *pkt)
15141514
} else {
15151515
uint32_t ack = ntohl(th_pkt->th_seq) + tcp_data_len(pkt);
15161516

1517+
if (th_flags(th_pkt) & SYN) {
1518+
ack++;
1519+
}
1520+
15171521
UNALIGNED_PUT(RST | ACK, &th_rst->th_flags);
15181522
UNALIGNED_PUT(htonl(ack), &th_rst->th_ack);
15191523
}
@@ -2846,7 +2850,7 @@ static enum net_verdict tcp_in(struct tcp *conn, struct net_pkt *pkt)
28462850
NET_DBG("%s", tcp_conn_state(conn, pkt));
28472851

28482852
if (th_off(th) < 5) {
2849-
tcp_out(conn, RST);
2853+
net_tcp_reply_rst(pkt);
28502854
do_close = true;
28512855
close_status = -ECONNRESET;
28522856
goto out;
@@ -2874,6 +2878,13 @@ static enum net_verdict tcp_in(struct tcp *conn, struct net_pkt *pkt)
28742878
if (conn->in_connect) {
28752879
fl = th_flags(th);
28762880
if (FL(&fl, ==, RST | ACK)) {
2881+
if (th_ack(th) != conn->seq) {
2882+
/* Invalid ACKnum - drop it */
2883+
net_stats_update_tcp_seg_rsterr(net_pkt_iface(pkt));
2884+
k_mutex_unlock(&conn->lock);
2885+
return NET_DROP;
2886+
}
2887+
28772888
close_status = -ECONNREFUSED;
28782889
}
28792890
}
@@ -2884,7 +2895,7 @@ static enum net_verdict tcp_in(struct tcp *conn, struct net_pkt *pkt)
28842895
if (tcp_options_len && !tcp_options_check(&conn->recv_options, pkt,
28852896
tcp_options_len)) {
28862897
NET_DBG("DROP: Invalid TCP option list");
2887-
tcp_out(conn, RST);
2898+
net_tcp_reply_rst(pkt);
28882899
do_close = true;
28892900
close_status = -ECONNRESET;
28902901
goto out;
@@ -2899,7 +2910,7 @@ static enum net_verdict tcp_in(struct tcp *conn, struct net_pkt *pkt)
28992910
NET_DBG("conn: %p, SYN received in %s state, dropping connection",
29002911
conn, tcp_state_to_str(conn->state, false));
29012912
net_stats_update_tcp_seg_drop(conn->iface);
2902-
tcp_out(conn, RST);
2913+
net_tcp_reply_rst(pkt);
29032914
do_close = true;
29042915
close_status = -ECONNRESET;
29052916
goto out;
@@ -3173,7 +3184,7 @@ static enum net_verdict tcp_in(struct tcp *conn, struct net_pkt *pkt)
31733184
"(total=%zu)", conn, len_acked,
31743185
conn->send_data_total);
31753186
net_stats_update_tcp_seg_drop(conn->iface);
3176-
tcp_out(conn, RST);
3187+
net_tcp_reply_rst(pkt);
31773188
do_close = true;
31783189
close_status = -ECONNRESET;
31793190
break;
@@ -3236,7 +3247,7 @@ static enum net_verdict tcp_in(struct tcp *conn, struct net_pkt *pkt)
32363247

32373248
ret = tcp_send_queued_data(conn);
32383249
if (ret < 0 && ret != -ENOBUFS) {
3239-
tcp_out(conn, RST);
3250+
net_tcp_reply_rst(pkt);
32403251
do_close = true;
32413252
close_status = ret;
32423253
verdict = NET_OK;
@@ -3334,7 +3345,7 @@ static enum net_verdict tcp_in(struct tcp *conn, struct net_pkt *pkt)
33343345

33353346
next = tcp_enter_time_wait(conn);
33363347

3337-
tcp_out(conn, RST);
3348+
net_tcp_reply_rst(pkt);
33383349
break;
33393350
}
33403351
if (FL(&fl, &, ACK, th_ack(th) == conn->seq)) {
@@ -3414,7 +3425,7 @@ static enum net_verdict tcp_in(struct tcp *conn, struct net_pkt *pkt)
34143425

34153426
next = tcp_enter_time_wait(conn);
34163427

3417-
tcp_out(conn, RST);
3428+
net_tcp_reply_rst(pkt);
34183429
break;
34193430
}
34203431
/*
@@ -3459,7 +3470,7 @@ static enum net_verdict tcp_in(struct tcp *conn, struct net_pkt *pkt)
34593470

34603471
next = tcp_enter_time_wait(conn);
34613472

3462-
tcp_out(conn, RST);
3473+
net_tcp_reply_rst(pkt);
34633474
break;
34643475
}
34653476

@@ -3513,7 +3524,7 @@ static enum net_verdict tcp_in(struct tcp *conn, struct net_pkt *pkt)
35133524
conn, new_len);
35143525
net_stats_update_tcp_seg_drop(conn->iface);
35153526

3516-
tcp_out(conn, RST);
3527+
net_tcp_reply_rst(pkt);
35173528
} else {
35183529
/* Acknowledge any FIN attempts, in case retransmission took
35193530
* place.

tests/net/tcp/src/main.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2202,7 +2202,7 @@ static void handle_server_rst_on_closed_port(sa_family_t af, struct tcphdr *th)
22022202
/* Port was closed so expect RST instead of SYN */
22032203
test_verify_flags(th, RST | ACK);
22042204
zassert_equal(ntohl(th->th_seq), 0, "Invalid SEQ value");
2205-
zassert_equal(ntohl(th->th_ack), seq, "Invalid ACK value");
2205+
zassert_equal(ntohl(th->th_ack), seq + 1, "Invalid ACK value");
22062206
t_state = T_CLOSING;
22072207
test_sem_give();
22082208
break;

0 commit comments

Comments
 (0)