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.

PR:			250499
Reviewed by:		gnn, rrs
MFC after:		1 week
Sponsored by:		Netflix, Inc
Differential Revision:	https://reviews.freebsd.org/D27148
This commit is contained in:
Michael Tuexen 2020-11-09 21:49:40 +00:00
parent db6a0c8f47
commit 283c76c7c3
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=367530
5 changed files with 98 additions and 46 deletions

View file

@ -977,8 +977,8 @@ tcp_input(struct mbuf **mp, int *offp, int proto)
* XXXRW: It may be time to rethink timewait locking.
*/
if (inp->inp_flags & INP_TIMEWAIT) {
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.
*/
@ -1680,20 +1680,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 without 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);
}
}

View file

@ -11430,12 +11430,6 @@ bbr_do_segment_nounlock(struct mbuf *m, struct tcphdr *th, struct socket *so,
#ifdef STATS
stats_voi_update_abs_ulong(tp->t_stats, VOI_TCP_FRWIN, tiwin);
#endif
/*
* Parse options on any incoming segment.
*/
tcp_dooptions(&to, (u_char *)(th + 1),
(th->th_off << 2) - sizeof(struct tcphdr),
(thflags & TH_SYN) ? TO_SYN : 0);
if (m->m_flags & M_TSTMP) {
/* Prefer the hardware timestamp if present */
@ -11459,6 +11453,23 @@ bbr_do_segment_nounlock(struct mbuf *m, struct tcphdr *th, struct socket *so,
*/
bbr->r_ctl.rc_rcvtime = lcts = cts = tcp_get_usecs(&bbr->rc_tv);
}
/*
* Parse options on any incoming segment.
*/
tcp_dooptions(&to, (u_char *)(th + 1),
(th->th_off << 2) - sizeof(struct tcphdr),
(thflags & TH_SYN) ? TO_SYN : 0);
/*
* 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)) {
retval = 0;
goto done_with_input;
}
/*
* If echoed timestamp is later than the current time, fall back to
* non RFC1323 RTT calculation. Normalize timestamp if syncookies

View file

@ -10525,7 +10525,7 @@ rack_handoff_ok(struct tcpcb *tp)
if ((tp->t_state == TCPS_SYN_SENT) ||
(tp->t_state == TCPS_SYN_RECEIVED)) {
/*
* We really don't know if you support sack,
* We really don't know if you support sack,
* you have to get to ESTAB or beyond to tell.
*/
return (EAGAIN);
@ -10868,6 +10868,26 @@ rack_do_segment_nounlock(struct mbuf *m, struct tcphdr *th, struct socket *so,
ctf_do_dropwithreset(m, tp, th, BANDLIM_RST_OPENPORT, tlen);
return(1);
}
/*
* Parse options on any incoming segment.
*/
tcp_dooptions(&to, (u_char *)(th + 1),
(th->th_off << 2) - sizeof(struct tcphdr),
(thflags & TH_SYN) ? TO_SYN : 0);
/*
* 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)) {
way_out = 5;
retval = 0;
goto done_with_input;
}
/*
* Segment received on connection. Reset idle time and keep-alive
* timer. XXX: This should be done after segment validation to
@ -10920,12 +10940,6 @@ rack_do_segment_nounlock(struct mbuf *m, struct tcphdr *th, struct socket *so,
rack_cong_signal(tp, th, CC_ECN);
}
}
/*
* Parse options on any incoming segment.
*/
tcp_dooptions(&to, (u_char *)(th + 1),
(th->th_off << 2) - sizeof(struct tcphdr),
(thflags & TH_SYN) ? TO_SYN : 0);
/*
* If echoed timestamp is later than the current time, fall back to

View file

@ -1211,6 +1211,40 @@ syncache_expand(struct in_conninfo *inc, struct tcpopt *to, struct tcphdr *th,
return (-1); /* Do not send RST */
}
/*
* If timestamps were not negotiated during SYN/ACK and a
* segment without 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.
*
@ -1256,32 +1290,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)

View file

@ -376,7 +376,7 @@ tcp_twstart(struct tcpcb *tp)
* looking for a pcb in the listen state. Returns 0 otherwise.
*/
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;
@ -411,6 +411,16 @@ tcp_twcheck(struct inpcb *inp, struct tcpopt *to __unused, struct tcphdr *th,
if (thflags & TH_RST)
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;
}
#if 0
/* PAWS not needed at the moment */
/*