diff --git a/sys/netinet/tcp_input.c b/sys/netinet/tcp_input.c --- a/sys/netinet/tcp_input.c +++ b/sys/netinet/tcp_input.c @@ -1961,8 +1961,22 @@ /* * If the state is SYN_RECEIVED: * if seg contains an ACK, but not for our SYN/ACK, send a RST. + * for RST segments, follow RFC9293 */ case TCPS_SYN_RECEIVED: + if (thflags & TH_RST) { + if (SEQ_LT(th->th_seq, tp->rcv_nxt) || + SEQ_GT(th->th_seq, tp->rcv_adv)) + goto drop; + if (th->th_seq == tp->rcv_nxt) { + TCP_PROBE5(connect__refused, NULL, tp, + m, tp, th); + tcp_log_end_status(tp, TCP_EI_STATUS_RST_IN_FRONT); + tp = tcp_drop(tp, ECONNREFUSED); + goto drop; + } + goto dropafterack; + } if ((thflags & TH_ACK) && (SEQ_LEQ(th->th_ack, tp->snd_una) || SEQ_GT(th->th_ack, tp->snd_max))) { @@ -2161,9 +2175,6 @@ TCPSTAT_INC(tcps_drops); /* Drop the connection. */ switch (tp->t_state) { - case TCPS_SYN_RECEIVED: - so->so_error = ECONNREFUSED; - goto close; case TCPS_ESTABLISHED: case TCPS_FIN_WAIT_1: case TCPS_FIN_WAIT_2: @@ -2171,7 +2182,6 @@ case TCPS_CLOSING: case TCPS_LAST_ACK: so->so_error = ECONNRESET; - close: /* FALLTHROUGH */ default: tcp_log_end_status(tp, TCP_EI_STATUS_CLIENT_RST); diff --git a/sys/netinet/tcp_syncache.c b/sys/netinet/tcp_syncache.c --- a/sys/netinet/tcp_syncache.c +++ b/sys/netinet/tcp_syncache.c @@ -624,12 +624,13 @@ SCH_LOCK_ASSERT(sch); /* - * Any RST to our SYN|ACK must not carry ACK, SYN or FIN flags. - * See RFC 793 page 65, section SEGMENT ARRIVES. + * Any RST to our SYN|ACK must not carry SYN or FIN flags. + * See RFC 9293 section 3.10.7.4, check the RST bit after + * acceptability tests. */ - if (tcp_get_flags(th) & (TH_ACK|TH_SYN|TH_FIN)) { + if (tcp_get_flags(th) & (TH_SYN|TH_FIN)) { if ((s = tcp_log_addrs(inc, th, NULL, NULL))) - log(LOG_DEBUG, "%s; %s: Spurious RST with ACK, SYN or " + log(LOG_DEBUG, "%s; %s: Spurious RST with SYN or " "FIN flag set, segment ignored\n", s, __func__); TCPSTAT_INC(tcps_badrst); goto done;