Re: tcp keep-alives sent without timestamps
On 6 May 2015 at 13:05, Martin Pieuchot m...@openbsd.org wrote: On 20/04/15(Mon) 18:37, Mike Belopuhov wrote: On Tue, Apr 14, 2015 at 22:08 +0300, Lauri Tirkkonen wrote: On Tue, Apr 14 2015 20:40:58 +0200, Mike Belopuhov wrote: According to 3.2 in RFC 7323: Once TSopt has been successfully negotiated, that is both SYN and SYN,ACK contain TSopt, the TSopt MUST be sent in every non-RST segment for the duration of the connection, and SHOULD be sent in an RST segment (see Section 5.2 for details). The TCP SHOULD remember this state by setting a flag, referred to as Snd.TS.OK, to one. If a non-RST segment is received without a TSopt, a TCP SHOULD silently drop the segment. A TCP MUST NOT abort a TCP connection because any segment lacks an expected TSopt. Thank you, I somehow missed the existence of this RFC. Does anyone else want to comment on this? Diff looks good to me. Since you mentioned other *BSD in your previous post, I look at what Linux and Solaris do and they both seem to set timestamps on keep alive packets. Thanks. As for MD5 signatures Linux also include it. Can't fix every problem with one patch... ok mpi@ Committed! Thanks for the review!
Re: tcp keep-alives sent without timestamps
On 14 April 2015 at 21:08, Lauri Tirkkonen loth...@iki.fi wrote: On Tue, Apr 14 2015 20:40:58 +0200, Mike Belopuhov wrote: According to 3.2 in RFC 7323: Once TSopt has been successfully negotiated, that is both SYN and SYN,ACK contain TSopt, the TSopt MUST be sent in every non-RST segment for the duration of the connection, and SHOULD be sent in an RST segment (see Section 5.2 for details). The TCP SHOULD remember this state by setting a flag, referred to as Snd.TS.OK, to one. If a non-RST segment is received without a TSopt, a TCP SHOULD silently drop the segment. A TCP MUST NOT abort a TCP connection because any segment lacks an expected TSopt. Thank you, I somehow missed the existence of this RFC. I had a stab at adding timestamp support to tcp_respond but couldn't test yet. If you feel like giving it a try, please be my guest. With your patch, I confirm that timestamps are present on keep-alive messages. Hi Lauri, I've committed the fix. Thanks a lot for bringing this up and testing.
Re: tcp keep-alives sent without timestamps
On 20/04/15(Mon) 18:37, Mike Belopuhov wrote: On Tue, Apr 14, 2015 at 22:08 +0300, Lauri Tirkkonen wrote: On Tue, Apr 14 2015 20:40:58 +0200, Mike Belopuhov wrote: According to 3.2 in RFC 7323: Once TSopt has been successfully negotiated, that is both SYN and SYN,ACK contain TSopt, the TSopt MUST be sent in every non-RST segment for the duration of the connection, and SHOULD be sent in an RST segment (see Section 5.2 for details). The TCP SHOULD remember this state by setting a flag, referred to as Snd.TS.OK, to one. If a non-RST segment is received without a TSopt, a TCP SHOULD silently drop the segment. A TCP MUST NOT abort a TCP connection because any segment lacks an expected TSopt. Thank you, I somehow missed the existence of this RFC. Does anyone else want to comment on this? Diff looks good to me. Since you mentioned other *BSD in your previous post, I look at what Linux and Solaris do and they both seem to set timestamps on keep alive packets. As for MD5 signatures Linux also include it. ok mpi@ I had a stab at adding timestamp support to tcp_respond but couldn't test yet. If you feel like giving it a try, please be my guest. With your patch, I confirm that timestamps are present on keep-alive messages. The patch needs a small (but crucial) amendment: tcp pcb can be NULL... diff --git sys/netinet/tcp_subr.c sys/netinet/tcp_subr.c index c8c8e77..6f17af0 100644 --- sys/netinet/tcp_subr.c +++ sys/netinet/tcp_subr.c @@ -295,13 +295,10 @@ tcp_template(tp) * attached mbufs. * * In any case the ack and sequence number of the transmitted * segment are as specified by the parameters. */ -#ifdef INET6 -/* This function looks hairy, because it was so IPv4-dependent. */ -#endif /* INET6 */ void tcp_respond(struct tcpcb *tp, caddr_t template, struct tcphdr *th0, tcp_seq ack, tcp_seq seq, int flags, u_int rtableid) { int tlen; @@ -370,14 +367,10 @@ tcp_respond(struct tcpcb *tp, caddr_t template, struct tcphdr *th0, xchg(th-th_dport, th-th_sport, u_int16_t); else flags = TH_ACK; #undef xchg - m-m_len = tlen; - m-m_pkthdr.len = tlen; - m-m_pkthdr.rcvif = (struct ifnet *) 0; th-th_ack = htonl(ack); th-th_x2 = 0; th-th_off = sizeof (struct tcphdr) 2; th-th_flags = flags; @@ -386,10 +379,26 @@ tcp_respond(struct tcpcb *tp, caddr_t template, struct tcphdr *th0, if (win TCP_MAXWIN) win = TCP_MAXWIN; th-th_win = htons((u_int16_t)win); th-th_urp = 0; + if (tp (tp-t_flags (TF_REQ_TSTMP|TF_NOOPT)) == TF_REQ_TSTMP + (flags TH_RST) == 0 (tp-t_flags TF_RCVD_TSTMP)) { + u_int32_t *lp = (u_int32_t *)(th + 1); + /* Form timestamp option as shown in appendix A of RFC 1323. */ + *lp++ = htonl(TCPOPT_TSTAMP_HDR); + *lp++ = htonl(tcp_now + tp-ts_modulate); + *lp = htonl(tp-ts_recent); + tlen += TCPOLEN_TSTAMP_APPA; + th-th_off = (sizeof(struct tcphdr) + TCPOLEN_TSTAMP_APPA) 2; + } + + m-m_len = tlen; + m-m_pkthdr.len = tlen; + m-m_pkthdr.rcvif = (struct ifnet *) 0; + m-m_pkthdr.csum_flags |= M_TCP_CSUM_OUT; + /* force routing table */ if (tp) m-m_pkthdr.ph_rtableid = tp-t_inpcb-inp_rtableid; else m-m_pkthdr.ph_rtableid = rtableid;
Re: tcp keep-alives sent without timestamps
On Tue, Apr 14, 2015 at 22:08 +0300, Lauri Tirkkonen wrote: On Tue, Apr 14 2015 20:40:58 +0200, Mike Belopuhov wrote: According to 3.2 in RFC 7323: Once TSopt has been successfully negotiated, that is both SYN and SYN,ACK contain TSopt, the TSopt MUST be sent in every non-RST segment for the duration of the connection, and SHOULD be sent in an RST segment (see Section 5.2 for details). The TCP SHOULD remember this state by setting a flag, referred to as Snd.TS.OK, to one. If a non-RST segment is received without a TSopt, a TCP SHOULD silently drop the segment. A TCP MUST NOT abort a TCP connection because any segment lacks an expected TSopt. Thank you, I somehow missed the existence of this RFC. Does anyone else want to comment on this? I had a stab at adding timestamp support to tcp_respond but couldn't test yet. If you feel like giving it a try, please be my guest. With your patch, I confirm that timestamps are present on keep-alive messages. The patch needs a small (but crucial) amendment: tcp pcb can be NULL... diff --git sys/netinet/tcp_subr.c sys/netinet/tcp_subr.c index c8c8e77..6f17af0 100644 --- sys/netinet/tcp_subr.c +++ sys/netinet/tcp_subr.c @@ -295,13 +295,10 @@ tcp_template(tp) * attached mbufs. * * In any case the ack and sequence number of the transmitted * segment are as specified by the parameters. */ -#ifdef INET6 -/* This function looks hairy, because it was so IPv4-dependent. */ -#endif /* INET6 */ void tcp_respond(struct tcpcb *tp, caddr_t template, struct tcphdr *th0, tcp_seq ack, tcp_seq seq, int flags, u_int rtableid) { int tlen; @@ -370,14 +367,10 @@ tcp_respond(struct tcpcb *tp, caddr_t template, struct tcphdr *th0, xchg(th-th_dport, th-th_sport, u_int16_t); else flags = TH_ACK; #undef xchg - m-m_len = tlen; - m-m_pkthdr.len = tlen; - m-m_pkthdr.rcvif = (struct ifnet *) 0; - m-m_pkthdr.csum_flags |= M_TCP_CSUM_OUT; th-th_seq = htonl(seq); th-th_ack = htonl(ack); th-th_x2 = 0; th-th_off = sizeof (struct tcphdr) 2; th-th_flags = flags; @@ -386,10 +379,26 @@ tcp_respond(struct tcpcb *tp, caddr_t template, struct tcphdr *th0, if (win TCP_MAXWIN) win = TCP_MAXWIN; th-th_win = htons((u_int16_t)win); th-th_urp = 0; + if (tp (tp-t_flags (TF_REQ_TSTMP|TF_NOOPT)) == TF_REQ_TSTMP + (flags TH_RST) == 0 (tp-t_flags TF_RCVD_TSTMP)) { + u_int32_t *lp = (u_int32_t *)(th + 1); + /* Form timestamp option as shown in appendix A of RFC 1323. */ + *lp++ = htonl(TCPOPT_TSTAMP_HDR); + *lp++ = htonl(tcp_now + tp-ts_modulate); + *lp = htonl(tp-ts_recent); + tlen += TCPOLEN_TSTAMP_APPA; + th-th_off = (sizeof(struct tcphdr) + TCPOLEN_TSTAMP_APPA) 2; + } + + m-m_len = tlen; + m-m_pkthdr.len = tlen; + m-m_pkthdr.rcvif = (struct ifnet *) 0; + m-m_pkthdr.csum_flags |= M_TCP_CSUM_OUT; + /* force routing table */ if (tp) m-m_pkthdr.ph_rtableid = tp-t_inpcb-inp_rtableid; else m-m_pkthdr.ph_rtableid = rtableid;
Re: tcp keep-alives sent without timestamps
On Tue, Apr 14, 2015 at 19:40 +0300, Lauri Tirkkonen wrote: Synopsis:tcp keep-alives sent without timestamps Category:kernel Environment: System : OpenBSD 5.7 Details : OpenBSD 5.7-current (GENERIC) #860: Mon Apr 13 20:58:42 MDT 2015 dera...@amd64.openbsd.org:/usr/src/sys/arch/amd64/compile/GENERIC Architecture: OpenBSD.amd64 Machine : amd64 Description: TCP keep-alive messages sent by OpenBSD do not include timestamp options. When using pf tcp normalisation, this breaks eg. ssh(1) from OpenBSD to illumos after transmission of a keep-alive. On (at least) illumos, receiving an empty ACK like this in a connection which was initiated using timestamps in the SYN, the following data packets sent by the illumos host will not include timestamps either (I'm discussing on their mailing lists [0] whether that makes sense). This is a problem if those data packets are scrubbed with reassemble tcp when received by OpenBSD; they will get dropped, because previous data packets *did* include timestamps [pf_norm.c:1252 onwards]. How-To-Repeat: - set sysctl net.inet.tcp.keepidle to a low value - open a tcp connection with SO_KEEPALIVE to an illumos host, eg. using ssh (TCPKeepAlive=yes is the default) - let the connection idle for half the amount of net.inet.tcp.keepidle - observe that data packets get delivered to the illumos host, but no data packets make it back. With 'pfctl -x notice', observe that pf_norm.c:1283 is reached. Fix: Include timestamp options in TCP keep-alive ACKs when the connection uses them for other packets. [0]: https://www.listbox.com/member/archive/182193/2015/04/sort/time_rev/page/1/entry/0:1/20150414115040:F678B734-E2BD-11E4-A441-A07D3EA1AED1/ -- Lauri Tirkkonen | lotheac @ IRCnet According to 3.2 in RFC 7323: Once TSopt has been successfully negotiated, that is both SYN and SYN,ACK contain TSopt, the TSopt MUST be sent in every non-RST segment for the duration of the connection, and SHOULD be sent in an RST segment (see Section 5.2 for details). The TCP SHOULD remember this state by setting a flag, referred to as Snd.TS.OK, to one. If a non-RST segment is received without a TSopt, a TCP SHOULD silently drop the segment. A TCP MUST NOT abort a TCP connection because any segment lacks an expected TSopt. Indeed, we must set timestamps on keep alive packets, except that keep alive is a bit of a hack and hence specs don't make any mention of it. FreeBSD and NetBSD both should behave the same way. Which seems to contradict RFC IMO. But then it begs the question should other options be also included, e.g. TCP MD5 signatures? Should in fact tcp_timer_keep call syn_cache_respond (with a patched up sequence number)? I had a stab at adding timestamp support to tcp_respond but couldn't test yet. If you feel like giving it a try, please be my guest. diff --git sys/netinet/tcp_subr.c sys/netinet/tcp_subr.c index c8c8e77..9f83bca 100644 --- sys/netinet/tcp_subr.c +++ sys/netinet/tcp_subr.c @@ -370,14 +370,10 @@ tcp_respond(struct tcpcb *tp, caddr_t template, struct tcphdr *th0, xchg(th-th_dport, th-th_sport, u_int16_t); else flags = TH_ACK; #undef xchg - m-m_len = tlen; - m-m_pkthdr.len = tlen; - m-m_pkthdr.rcvif = (struct ifnet *) 0; - m-m_pkthdr.csum_flags |= M_TCP_CSUM_OUT; th-th_seq = htonl(seq); th-th_ack = htonl(ack); th-th_x2 = 0; th-th_off = sizeof (struct tcphdr) 2; th-th_flags = flags; @@ -386,10 +382,26 @@ tcp_respond(struct tcpcb *tp, caddr_t template, struct tcphdr *th0, if (win TCP_MAXWIN) win = TCP_MAXWIN; th-th_win = htons((u_int16_t)win); th-th_urp = 0; + if ((tp-t_flags (TF_REQ_TSTMP|TF_NOOPT)) == TF_REQ_TSTMP + (flags TH_RST) == 0 (tp-t_flags TF_RCVD_TSTMP)) { + u_int32_t *lp = (u_int32_t *)(th + 1); + /* Form timestamp option as shown in appendix A of RFC 1323. */ + *lp++ = htonl(TCPOPT_TSTAMP_HDR); + *lp++ = htonl(tcp_now + tp-ts_modulate); + *lp = htonl(tp-ts_recent); + tlen += TCPOLEN_TSTAMP_APPA; + th-th_off = (sizeof(struct tcphdr) + TCPOLEN_TSTAMP_APPA) 2; + } + + m-m_len = tlen; + m-m_pkthdr.len = tlen; + m-m_pkthdr.rcvif = (struct ifnet *) 0; + m-m_pkthdr.csum_flags |= M_TCP_CSUM_OUT; + /* force routing table */ if (tp) m-m_pkthdr.ph_rtableid = tp-t_inpcb-inp_rtableid; else m-m_pkthdr.ph_rtableid = rtableid;
Re: tcp keep-alives sent without timestamps
On Tue, Apr 14 2015 20:40:58 +0200, Mike Belopuhov wrote: According to 3.2 in RFC 7323: Once TSopt has been successfully negotiated, that is both SYN and SYN,ACK contain TSopt, the TSopt MUST be sent in every non-RST segment for the duration of the connection, and SHOULD be sent in an RST segment (see Section 5.2 for details). The TCP SHOULD remember this state by setting a flag, referred to as Snd.TS.OK, to one. If a non-RST segment is received without a TSopt, a TCP SHOULD silently drop the segment. A TCP MUST NOT abort a TCP connection because any segment lacks an expected TSopt. Thank you, I somehow missed the existence of this RFC. I had a stab at adding timestamp support to tcp_respond but couldn't test yet. If you feel like giving it a try, please be my guest. With your patch, I confirm that timestamps are present on keep-alive messages. -- Lauri Tirkkonen | lotheac @ IRCnet