svn commit: r339430 - head/sys/netinet

Michael Tuexen tuexen at FreeBSD.org
Thu Oct 18 19:21:20 UTC 2018


Author: tuexen
Date: Thu Oct 18 19:21:18 2018
New Revision: 339430
URL: https://svnweb.freebsd.org/changeset/base/339430

Log:
  The handling of RST segments in the SYN-RCVD state exists in the
  code paths. Both are not consistent and the one on the syn cache code
  does not conform to the relevant specifications (Page 69 of RFC 793
  and Section 4.2 of RFC 5961).
  
  This patch fixes this:
  * The sequence numbers checks are fixed as specified on
    page Page 69 RFC 793.
  * The sysctl variable net.inet.tcp.insecure_rst is now honoured
    and the behaviour as specified in Section 4.2 of RFC 5961.
  
  Approved by:		re (gjb@)
  Reviewed by:		bz@, glebius@, rrs@,
  Differential Revision:	https://reviews.freebsd.org/D17595
  Sponsored by:		Netflix, Inc.

Modified:
  head/sys/netinet/tcp_input.c
  head/sys/netinet/tcp_syncache.c
  head/sys/netinet/tcp_syncache.h

Modified: head/sys/netinet/tcp_input.c
==============================================================================
--- head/sys/netinet/tcp_input.c	Thu Oct 18 19:19:45 2018	(r339429)
+++ head/sys/netinet/tcp_input.c	Thu Oct 18 19:21:18 2018	(r339430)
@@ -1165,7 +1165,7 @@ tfo_socket_result:
 		 * causes.
 		 */
 		if (thflags & TH_RST) {
-			syncache_chkrst(&inc, th);
+			syncache_chkrst(&inc, th, m);
 			goto dropunlock;
 		}
 		/*

Modified: head/sys/netinet/tcp_syncache.c
==============================================================================
--- head/sys/netinet/tcp_syncache.c	Thu Oct 18 19:19:45 2018	(r339429)
+++ head/sys/netinet/tcp_syncache.c	Thu Oct 18 19:21:18 2018	(r339430)
@@ -131,7 +131,7 @@ static void	 syncache_drop(struct syncache *, struct s
 static void	 syncache_free(struct syncache *);
 static void	 syncache_insert(struct syncache *, struct syncache_head *);
 static int	 syncache_respond(struct syncache *, struct syncache_head *,
-		    const struct mbuf *);
+		    const struct mbuf *, int);
 static struct	 socket *syncache_socket(struct syncache *, struct socket *,
 		    struct mbuf *m);
 static void	 syncache_timeout(struct syncache *sc, struct syncache_head *sch,
@@ -489,7 +489,7 @@ syncache_timer(void *xsch)
 			free(s, M_TCPLOG);
 		}
 
-		syncache_respond(sc, sch, NULL);
+		syncache_respond(sc, sch, NULL, TH_SYN|TH_ACK);
 		TCPSTAT_INC(tcps_sc_retransmitted);
 		syncache_timeout(sc, sch, 0);
 	}
@@ -537,9 +537,10 @@ syncache_lookup(struct in_conninfo *inc, struct syncac
  * This function is called when we get a RST for a
  * non-existent connection, so that we can see if the
  * connection is in the syn cache.  If it is, zap it.
+ * If required send a challenge ACK.
  */
 void
-syncache_chkrst(struct in_conninfo *inc, struct tcphdr *th)
+syncache_chkrst(struct in_conninfo *inc, struct tcphdr *th, struct mbuf *m)
 {
 	struct syncache *sc;
 	struct syncache_head *sch;
@@ -590,19 +591,36 @@ syncache_chkrst(struct in_conninfo *inc, struct tcphdr
 	 *   send a reset with the sequence number at the rightmost edge
 	 *   of our receive window, and we have to handle this case.
 	 */
-	if (SEQ_GEQ(th->th_seq, sc->sc_irs) &&
-	    SEQ_LEQ(th->th_seq, sc->sc_irs + sc->sc_wnd)) {
-		syncache_drop(sc, sch);
-		if ((s = tcp_log_addrs(inc, th, NULL, NULL)))
-			log(LOG_DEBUG, "%s; %s: Our SYN|ACK was rejected, "
-			    "connection attempt aborted by remote endpoint\n",
-			    s, __func__);
-		TCPSTAT_INC(tcps_sc_reset);
+	if ((SEQ_GEQ(th->th_seq, sc->sc_irs + 1) &&
+	    SEQ_LT(th->th_seq, sc->sc_irs + 1 + sc->sc_wnd)) ||
+	    (sc->sc_wnd == 0 && th->th_seq == sc->sc_irs + 1)) {
+		if (V_tcp_insecure_rst ||
+		    th->th_seq == sc->sc_irs + 1) {
+			syncache_drop(sc, sch);
+			if ((s = tcp_log_addrs(inc, th, NULL, NULL)))
+				log(LOG_DEBUG,
+				    "%s; %s: Our SYN|ACK was rejected, "
+				    "connection attempt aborted by remote "
+				    "endpoint\n",
+				    s, __func__);
+			TCPSTAT_INC(tcps_sc_reset);
+		} else {
+			TCPSTAT_INC(tcps_badrst);
+			/* Send challenge ACK. */
+			if ((s = tcp_log_addrs(inc, th, NULL, NULL)))
+				log(LOG_DEBUG, "%s; %s: RST with invalid "
+				    " SEQ %u != NXT %u (+WND %u), "
+				    "sending challenge ACK\n",
+				    s, __func__,
+				    th->th_seq, sc->sc_irs + 1, sc->sc_wnd);
+			syncache_respond(sc, sch, m, TH_ACK);
+		}
 	} else {
 		if ((s = tcp_log_addrs(inc, th, NULL, NULL)))
 			log(LOG_DEBUG, "%s; %s: RST with invalid SEQ %u != "
-			    "IRS %u (+WND %u), segment ignored\n",
-			    s, __func__, th->th_seq, sc->sc_irs, sc->sc_wnd);
+			    "NXT %u (+WND %u), segment ignored\n",
+			    s, __func__,
+			    th->th_seq, sc->sc_irs + 1, sc->sc_wnd);
 		TCPSTAT_INC(tcps_badrst);
 	}
 
@@ -1413,7 +1431,7 @@ syncache_add(struct in_conninfo *inc, struct tcpopt *t
 			    s, __func__);
 			free(s, M_TCPLOG);
 		}
-		if (syncache_respond(sc, sch, m) == 0) {
+		if (syncache_respond(sc, sch, m, TH_SYN|TH_ACK) == 0) {
 			sc->sc_rxmits = 0;
 			syncache_timeout(sc, sch, 1);
 			TCPSTAT_INC(tcps_sndacks);
@@ -1577,7 +1595,7 @@ skip_alloc:
 	/*
 	 * Do a standard 3-way handshake.
 	 */
-	if (syncache_respond(sc, sch, m) == 0) {
+	if (syncache_respond(sc, sch, m, TH_SYN|TH_ACK) == 0) {
 		if (V_tcp_syncookies && V_tcp_syncookiesonly && sc != &scs)
 			syncache_free(sc);
 		else if (sc != &scs)
@@ -1618,12 +1636,12 @@ tfo_expanded:
 }
 
 /*
- * Send SYN|ACK to the peer.  Either in response to the peer's SYN,
+ * Send SYN|ACK or ACK to the peer.  Either in response to a peer's segment,
  * i.e. m0 != NULL, or upon 3WHS ACK timeout, i.e. m0 == NULL.
  */
 static int
 syncache_respond(struct syncache *sc, struct syncache_head *sch,
-    const struct mbuf *m0)
+    const struct mbuf *m0, int flags)
 {
 	struct ip *ip = NULL;
 	struct mbuf *m;
@@ -1709,15 +1727,18 @@ syncache_respond(struct syncache *sc, struct syncache_
 	th->th_sport = sc->sc_inc.inc_lport;
 	th->th_dport = sc->sc_inc.inc_fport;
 
-	th->th_seq = htonl(sc->sc_iss);
+	if (flags & TH_SYN)
+		th->th_seq = htonl(sc->sc_iss);
+	else
+		th->th_seq = htonl(sc->sc_iss + 1);
 	th->th_ack = htonl(sc->sc_irs + 1);
 	th->th_off = sizeof(struct tcphdr) >> 2;
 	th->th_x2 = 0;
-	th->th_flags = TH_SYN|TH_ACK;
+	th->th_flags = flags;
 	th->th_win = htons(sc->sc_wnd);
 	th->th_urp = 0;
 
-	if (sc->sc_flags & SCF_ECN) {
+	if ((flags & TH_SYN) && (sc->sc_flags & SCF_ECN)) {
 		th->th_flags |= TH_ECE;
 		TCPSTAT_INC(tcps_ecn_shs);
 	}
@@ -1726,29 +1747,31 @@ syncache_respond(struct syncache *sc, struct syncache_
 	if ((sc->sc_flags & SCF_NOOPT) == 0) {
 		to.to_flags = 0;
 
-		to.to_mss = mssopt;
-		to.to_flags = TOF_MSS;
-		if (sc->sc_flags & SCF_WINSCALE) {
-			to.to_wscale = sc->sc_requested_r_scale;
-			to.to_flags |= TOF_SCALE;
+		if (flags & TH_SYN) {
+			to.to_mss = mssopt;
+			to.to_flags = TOF_MSS;
+			if (sc->sc_flags & SCF_WINSCALE) {
+				to.to_wscale = sc->sc_requested_r_scale;
+				to.to_flags |= TOF_SCALE;
+			}
+			if (sc->sc_flags & SCF_SACK)
+				to.to_flags |= TOF_SACKPERM;
+#if defined(IPSEC_SUPPORT) || defined(TCP_SIGNATURE)
+			if (sc->sc_flags & SCF_SIGNATURE)
+				to.to_flags |= TOF_SIGNATURE;
+#endif
+			if (sc->sc_tfo_cookie) {
+				to.to_flags |= TOF_FASTOPEN;
+				to.to_tfo_len = TCP_FASTOPEN_COOKIE_LEN;
+				to.to_tfo_cookie = sc->sc_tfo_cookie;
+				/* don't send cookie again when retransmitting response */
+				sc->sc_tfo_cookie = NULL;
+			}
 		}
 		if (sc->sc_flags & SCF_TIMESTAMP) {
 			to.to_tsval = sc->sc_tsoff + tcp_ts_getticks();
 			to.to_tsecr = sc->sc_tsreflect;
 			to.to_flags |= TOF_TS;
-		}
-		if (sc->sc_flags & SCF_SACK)
-			to.to_flags |= TOF_SACKPERM;
-#if defined(IPSEC_SUPPORT) || defined(TCP_SIGNATURE)
-		if (sc->sc_flags & SCF_SIGNATURE)
-			to.to_flags |= TOF_SIGNATURE;
-#endif
-		if (sc->sc_tfo_cookie) {
-			to.to_flags |= TOF_FASTOPEN;
-			to.to_tfo_len = TCP_FASTOPEN_COOKIE_LEN;
-			to.to_tfo_cookie = sc->sc_tfo_cookie;
-			/* don't send cookie again when retransmitting response */
-			sc->sc_tfo_cookie = NULL;
 		}
 		optlen = tcp_addoptions(&to, (u_char *)(th + 1));
 

Modified: head/sys/netinet/tcp_syncache.h
==============================================================================
--- head/sys/netinet/tcp_syncache.h	Thu Oct 18 19:19:45 2018	(r339429)
+++ head/sys/netinet/tcp_syncache.h	Thu Oct 18 19:21:18 2018	(r339430)
@@ -46,7 +46,7 @@ int	 syncache_expand(struct in_conninfo *, struct tcpo
 int	 syncache_add(struct in_conninfo *, struct tcpopt *,
 	     struct tcphdr *, struct inpcb *, struct socket **, struct mbuf *,
 	     void *, void *);
-void	 syncache_chkrst(struct in_conninfo *, struct tcphdr *);
+void	 syncache_chkrst(struct in_conninfo *, struct tcphdr *, struct mbuf *);
 void	 syncache_badack(struct in_conninfo *);
 int	 syncache_pcblist(struct sysctl_req *req, int max_pcbs, int *pcbs_exported);
 


More information about the svn-src-head mailing list