net: tcp: Handle case when RST is received in any state
We must check if we receive RST in any of the TCP states. If we do not do this, then the net_context might leak as it would never be released in some of the states. Receiving RST in any TCP state is not described in TCP state diagram but is described in RFC 793 which says in chapter "Reset Processing" that system "...aborts the connection and advises the user and goes to the CLOSED state." We need to also validate the received RST and accept only those TCP reset packets that contain valid sequence number. The validate_state_transitions() function is also changed to accept CLOSED state transition from various other states. Signed-off-by: Jukka Rissanen <jukka.rissanen@linux.intel.com>
This commit is contained in:
parent
8162bb63c4
commit
00b4081da3
3 changed files with 67 additions and 8 deletions
|
@ -816,6 +816,28 @@ NET_CONN_CB(tcp_established)
|
|||
sys_get_be32(NET_TCP_HDR(pkt)->ack));
|
||||
}
|
||||
|
||||
/*
|
||||
* If we receive RST here, we close the socket. See RFC 793 chapter
|
||||
* called "Reset Processing" for details.
|
||||
*/
|
||||
if (tcp_flags & NET_TCP_RST) {
|
||||
/* We only accept RST packet that has valid seq field. */
|
||||
if (!net_tcp_validate_seq(context->tcp, pkt)) {
|
||||
return NET_DROP;
|
||||
}
|
||||
|
||||
net_tcp_print_recv_info("RST", pkt, NET_TCP_HDR(pkt)->src_port);
|
||||
|
||||
if (context->recv_cb) {
|
||||
context->recv_cb(context, NULL, -ECONNRESET,
|
||||
context->tcp->recv_user_data);
|
||||
}
|
||||
|
||||
net_context_unref(context);
|
||||
|
||||
return NET_DROP;
|
||||
}
|
||||
|
||||
if (sys_get_be32(NET_TCP_HDR(pkt)->seq) - context->tcp->send_ack) {
|
||||
/* Don't try to reorder packets. If it doesn't
|
||||
* match the next segment exactly, drop and wait for
|
||||
|
@ -881,6 +903,11 @@ NET_CONN_CB(tcp_synack_received)
|
|||
NET_ASSERT(net_pkt_iface(pkt));
|
||||
|
||||
if (NET_TCP_FLAGS(pkt) & NET_TCP_RST) {
|
||||
/* We only accept RST packet that has valid seq field. */
|
||||
if (!net_tcp_validate_seq(context->tcp, pkt)) {
|
||||
return NET_DROP;
|
||||
}
|
||||
|
||||
if (context->connect_cb) {
|
||||
context->connect_cb(context, -ECONNREFUSED,
|
||||
context->user_data);
|
||||
|
@ -1303,14 +1330,24 @@ NET_CONN_CB(tcp_syn_rcvd)
|
|||
}
|
||||
|
||||
/*
|
||||
* If we receive RST, we go back to LISTEN state.
|
||||
* If we receive RST, we go back to LISTEN state if the previous state
|
||||
* was LISTEN, otherwise we go to CLOSED state.
|
||||
* See RFC 793 chapter 3.4 "Reset Processing" for more details.
|
||||
*/
|
||||
if (NET_TCP_FLAGS(pkt) == NET_TCP_RST) {
|
||||
|
||||
/* We only accept RST packet that has valid seq field. */
|
||||
if (!net_tcp_validate_seq(tcp, pkt)) {
|
||||
return NET_DROP;
|
||||
}
|
||||
|
||||
ack_timer_cancel(tcp);
|
||||
|
||||
net_tcp_print_recv_info("RST", pkt, NET_TCP_HDR(pkt)->src_port);
|
||||
|
||||
net_tcp_change_state(tcp, NET_TCP_LISTEN);
|
||||
if (net_tcp_get_state(tcp) != NET_TCP_LISTEN) {
|
||||
net_tcp_change_state(tcp, NET_TCP_CLOSED);
|
||||
}
|
||||
|
||||
return NET_DROP;
|
||||
}
|
||||
|
|
|
@ -855,16 +855,22 @@ static void validate_state_transition(enum net_tcp_state current,
|
|||
1 << NET_TCP_CLOSED,
|
||||
[NET_TCP_SYN_SENT] = 1 << NET_TCP_CLOSED |
|
||||
1 << NET_TCP_ESTABLISHED |
|
||||
1 << NET_TCP_SYN_RCVD,
|
||||
1 << NET_TCP_SYN_RCVD |
|
||||
1 << NET_TCP_CLOSED,
|
||||
[NET_TCP_ESTABLISHED] = 1 << NET_TCP_CLOSE_WAIT |
|
||||
1 << NET_TCP_FIN_WAIT_1,
|
||||
[NET_TCP_CLOSE_WAIT] = 1 << NET_TCP_LAST_ACK,
|
||||
1 << NET_TCP_FIN_WAIT_1 |
|
||||
1 << NET_TCP_CLOSED,
|
||||
[NET_TCP_CLOSE_WAIT] = 1 << NET_TCP_LAST_ACK |
|
||||
1 << NET_TCP_CLOSED,
|
||||
[NET_TCP_LAST_ACK] = 1 << NET_TCP_CLOSED,
|
||||
[NET_TCP_FIN_WAIT_1] = 1 << NET_TCP_CLOSING |
|
||||
1 << NET_TCP_FIN_WAIT_2 |
|
||||
1 << NET_TCP_TIME_WAIT,
|
||||
[NET_TCP_FIN_WAIT_2] = 1 << NET_TCP_TIME_WAIT,
|
||||
[NET_TCP_CLOSING] = 1 << NET_TCP_TIME_WAIT,
|
||||
1 << NET_TCP_TIME_WAIT |
|
||||
1 << NET_TCP_CLOSED,
|
||||
[NET_TCP_FIN_WAIT_2] = 1 << NET_TCP_TIME_WAIT |
|
||||
1 << NET_TCP_CLOSED,
|
||||
[NET_TCP_CLOSING] = 1 << NET_TCP_TIME_WAIT |
|
||||
1 << NET_TCP_CLOSED,
|
||||
[NET_TCP_TIME_WAIT] = 1 << NET_TCP_CLOSED
|
||||
};
|
||||
|
||||
|
@ -941,3 +947,9 @@ void net_tcp_foreach(net_tcp_cb_t cb, void *user_data)
|
|||
|
||||
irq_unlock(key);
|
||||
}
|
||||
|
||||
bool net_tcp_validate_seq(struct net_tcp *tcp, struct net_pkt *pkt)
|
||||
{
|
||||
return !net_tcp_seq_greater(tcp->send_ack + get_recv_wnd(tcp),
|
||||
sys_get_be32(NET_TCP_HDR(pkt)->seq));
|
||||
}
|
||||
|
|
|
@ -338,6 +338,16 @@ static inline enum net_tcp_state net_tcp_get_state(const struct net_tcp *tcp)
|
|||
return (enum net_tcp_state)tcp->state;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if the sequence number is valid i.e., it is inside the window.
|
||||
*
|
||||
* @param tcp TCP context
|
||||
* @param pkt Network packet
|
||||
*
|
||||
* @return true if network packet sequence number is valid, false otherwise
|
||||
*/
|
||||
bool net_tcp_validate_seq(struct net_tcp *tcp, struct net_pkt *pkt);
|
||||
|
||||
#if defined(CONFIG_NET_TCP)
|
||||
void net_tcp_init(void);
|
||||
#else
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue