aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Tuexen <tuexen@FreeBSD.org>2020-11-30 10:58:06 +0000
committerMichael Tuexen <tuexen@FreeBSD.org>2020-11-30 10:58:06 +0000
commit46ecd24a0d72ece375e91fad7a672497ba9da41b (patch)
treecb7edcb62a8c3c2273ed2276573253860ed33fc1
parent00da35beb0e5840a3aab77bf6e719fa86769eee0 (diff)
downloadsrc-46ecd24a0d72ece375e91fad7a672497ba9da41b.tar.gz
src-46ecd24a0d72ece375e91fad7a672497ba9da41b.zip
MFC r367530:
RFC 7323 specifies that: * TCP segments without timestamps should be dropped when support for the timestamp option has been negotiated. * TCP segments with timestamps should be processed normally if support for the timestamp option has not been negotiated. This patch enforces the above. Manually resolved merge conflicts. MFC 367891: Fix an issue I introuced in r367530: tcp_twcheck() can be called with to == NULL for SYN segments. So don't assume tp != NULL. Thanks to jhb@ for reporting and suggesting a fix. MFC r367946: Fix two occurences of a typo in a comment introduced in r367530. Thanks to lstewart@ for reporting them. PR: 250499 Reviewed by: gnn, rrs Sponsored by: Netflix, Inc. Differential Revision: https://reviews.freebsd.org/D27148
Notes
Notes: svn path=/stable/11/; revision=368183
-rw-r--r--sys/netinet/tcp_input.c21
-rw-r--r--sys/netinet/tcp_syncache.c60
-rw-r--r--sys/netinet/tcp_timewait.c15
3 files changed, 63 insertions, 33 deletions
diff --git a/sys/netinet/tcp_input.c b/sys/netinet/tcp_input.c
index 4d48cdd7a685..87bee467de28 100644
--- a/sys/netinet/tcp_input.c
+++ b/sys/netinet/tcp_input.c
@@ -992,8 +992,8 @@ relocked:
}
INP_INFO_RLOCK_ASSERT(&V_tcbinfo);
- if (thflags & TH_SYN)
- tcp_dooptions(&to, optp, optlen, TO_SYN);
+ tcp_dooptions(&to, optp, optlen,
+ (thflags & TH_SYN) ? TO_SYN : 0);
/*
* NB: tcp_twcheck unlocks the INP and frees the mbuf.
*/
@@ -1729,20 +1729,29 @@ tcp_do_segment(struct mbuf *m, struct tcphdr *th, struct socket *so,
}
/*
- * If timestamps were negotiated during SYN/ACK they should
- * appear on every segment during this session and vice versa.
+ * If timestamps were negotiated during SYN/ACK and a
+ * segment without a timestamp is received, silently drop
+ * the segment.
+ * See section 3.2 of RFC 7323.
*/
if ((tp->t_flags & TF_RCVD_TSTMP) && !(to.to_flags & TOF_TS)) {
if ((s = tcp_log_addrs(inc, th, NULL, NULL))) {
log(LOG_DEBUG, "%s; %s: Timestamp missing, "
- "no action\n", s, __func__);
+ "segment silently dropped\n", s, __func__);
free(s, M_TCPLOG);
}
+ goto drop;
}
+ /*
+ * If timestamps were not negotiated during SYN/ACK and a
+ * segment with a timestamp is received, ignore the
+ * timestamp and process the packet normally.
+ * See section 3.2 of RFC 7323.
+ */
if (!(tp->t_flags & TF_RCVD_TSTMP) && (to.to_flags & TOF_TS)) {
if ((s = tcp_log_addrs(inc, th, NULL, NULL))) {
log(LOG_DEBUG, "%s; %s: Timestamp not expected, "
- "no action\n", s, __func__);
+ "segment processed normally\n", s, __func__);
free(s, M_TCPLOG);
}
}
diff --git a/sys/netinet/tcp_syncache.c b/sys/netinet/tcp_syncache.c
index d0a74c8b66fd..16bd1ee0a074 100644
--- a/sys/netinet/tcp_syncache.c
+++ b/sys/netinet/tcp_syncache.c
@@ -1111,6 +1111,40 @@ syncache_expand(struct in_conninfo *inc, struct tcpopt *to, struct tcphdr *th,
}
/*
+ * If timestamps were not negotiated during SYN/ACK and a
+ * segment with a timestamp is received, ignore the
+ * timestamp and process the packet normally.
+ * See section 3.2 of RFC 7323.
+ */
+ if (!(sc->sc_flags & SCF_TIMESTAMP) &&
+ (to->to_flags & TOF_TS)) {
+ if ((s = tcp_log_addrs(inc, th, NULL, NULL))) {
+ log(LOG_DEBUG, "%s; %s: Timestamp not "
+ "expected, segment processed normally\n",
+ s, __func__);
+ free(s, M_TCPLOG);
+ s = NULL;
+ }
+ }
+
+ /*
+ * If timestamps were negotiated during SYN/ACK and a
+ * segment without a timestamp is received, silently drop
+ * the segment.
+ * See section 3.2 of RFC 7323.
+ */
+ if ((sc->sc_flags & SCF_TIMESTAMP) &&
+ !(to->to_flags & TOF_TS)) {
+ SCH_UNLOCK(sch);
+ if ((s = tcp_log_addrs(inc, th, NULL, NULL))) {
+ log(LOG_DEBUG, "%s; %s: Timestamp missing, "
+ "segment silently dropped\n", s, __func__);
+ free(s, M_TCPLOG);
+ }
+ return (-1); /* Do not send RST */
+ }
+
+ /*
* Pull out the entry to unlock the bucket row.
*
* NOTE: We must decrease TCPS_SYN_RECEIVED count here, not
@@ -1155,32 +1189,6 @@ syncache_expand(struct in_conninfo *inc, struct tcpopt *to, struct tcphdr *th,
goto failed;
}
- /*
- * If timestamps were not negotiated during SYN/ACK they
- * must not appear on any segment during this session.
- */
- if (!(sc->sc_flags & SCF_TIMESTAMP) && (to->to_flags & TOF_TS)) {
- if ((s = tcp_log_addrs(inc, th, NULL, NULL)))
- log(LOG_DEBUG, "%s; %s: Timestamp not expected, "
- "segment rejected\n", s, __func__);
- goto failed;
- }
-
- /*
- * If timestamps were negotiated during SYN/ACK they should
- * appear on every segment during this session.
- * XXXAO: This is only informal as there have been unverified
- * reports of non-compliants stacks.
- */
- if ((sc->sc_flags & SCF_TIMESTAMP) && !(to->to_flags & TOF_TS)) {
- if ((s = tcp_log_addrs(inc, th, NULL, NULL))) {
- log(LOG_DEBUG, "%s; %s: Timestamp missing, "
- "no action\n", s, __func__);
- free(s, M_TCPLOG);
- s = NULL;
- }
- }
-
*lsop = syncache_socket(sc, *lsop, m);
if (*lsop == NULL)
diff --git a/sys/netinet/tcp_timewait.c b/sys/netinet/tcp_timewait.c
index b7a346249296..35d7075538e8 100644
--- a/sys/netinet/tcp_timewait.c
+++ b/sys/netinet/tcp_timewait.c
@@ -373,9 +373,10 @@ tcp_twstart(struct tcpcb *tp)
/*
* Returns 1 if the TIME_WAIT state was killed and we should start over,
* looking for a pcb in the listen state. Returns 0 otherwise.
+ * It be called with to == NULL only for pure SYN-segments.
*/
int
-tcp_twcheck(struct inpcb *inp, struct tcpopt *to __unused, struct tcphdr *th,
+tcp_twcheck(struct inpcb *inp, struct tcpopt *to, struct tcphdr *th,
struct mbuf *m, int tlen)
{
struct tcptw *tw;
@@ -396,6 +397,8 @@ tcp_twcheck(struct inpcb *inp, struct tcpopt *to __unused, struct tcphdr *th,
goto drop;
thflags = th->th_flags;
+ KASSERT(to != NULL || (thflags & (TH_SYN | TH_ACK)) == TH_SYN,
+ ("tcp_twcheck: called without options on a non-SYN segment"));
/*
* NOTE: for FIN_WAIT_2 (to be added later),
@@ -445,6 +448,16 @@ tcp_twcheck(struct inpcb *inp, struct tcpopt *to __unused, struct tcphdr *th,
goto drop;
/*
+ * If timestamps were negotiated during SYN/ACK and a
+ * segment without a timestamp is received, silently drop
+ * the segment.
+ * See section 3.2 of RFC 7323.
+ */
+ if (((to->to_flags & TOF_TS) == 0) && (tw->t_recent != 0)) {
+ goto drop;
+ }
+
+ /*
* Reset the 2MSL timer if this is a duplicate FIN.
*/
if (thflags & TH_FIN) {