* [PATCH -next] net: tcp: move to timewait when receiving data post active-close @ 2015-11-18 15:03 Florian Westphal 2015-11-18 15:28 ` Eric Dumazet 0 siblings, 1 reply; 10+ messages in thread From: Florian Westphal @ 2015-11-18 15:03 UTC (permalink / raw) To: netdev; +Cc: marcelo.leitner, eric.dumazet, Florian Westphal RFC 1122, 4.2.2.13: [..] if new data is received after CLOSE is called, its TCP SHOULD send a RST to show that data was lost. When a connection is closed actively, it MUST linger in TIME-WAIT state [..]. We reset a connection, but destroy state immediately. After discussing this with Hannes, we decided it was preferable to also move to TW state to avoid immediate port reuse. packetdrill testcase: 0.000 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3 0.000 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0 0.000 bind(3, ..., ...) = 0 0.000 listen(3, 1) = 0 0.100 < S 0:0(0) win 29200 <mss 1460> 0.100 > S. 0:0(0) ack 1 <mss 1460> 0.200 < . 1:1(0) ack 1 win 257 0.200 accept(3, ..., ...) = 4 // close our side. 0.210 close(4) = 0 // we should expect to see FIN now, sk moves to FIN_WAIT_1 0.210 > F. 1:1(0) ack 1 win 29200 // receive data, but sk already closed -> Reset 0.300 < P. 1:1001(1000) ack 1 win 46 0.300 > R 1:1(0) win 0 Acked-by: Hannes Frederic Sowa <hannes@stressinduktion.org> Signed-off-by: Florian Westphal <fw@strlen.de> --- We got complaint from customer that CLOSED state transition is RFC violation. The advantage of current behaviour is that further packets will also result in RST. I'm interested if others think its worth changing this now. Thanks. diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index fdd88c3..3bcdad1 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -5904,11 +5904,16 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb) break; } - if (tp->linger2 < 0 || - (TCP_SKB_CB(skb)->end_seq != TCP_SKB_CB(skb)->seq && - after(TCP_SKB_CB(skb)->end_seq - th->fin, tp->rcv_nxt))) { + if (tp->linger2 < 0) { + NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPABORTONDATA); tcp_done(sk); + return 1; + } + + if (TCP_SKB_CB(skb)->end_seq != TCP_SKB_CB(skb)->seq && + after(TCP_SKB_CB(skb)->end_seq - th->fin, tp->rcv_nxt)) { NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPABORTONDATA); + tcp_time_wait(sk, TCP_TIME_WAIT, 0); return 1; } @@ -5966,7 +5971,13 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb) if (TCP_SKB_CB(skb)->end_seq != TCP_SKB_CB(skb)->seq && after(TCP_SKB_CB(skb)->end_seq - th->fin, tp->rcv_nxt)) { NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPABORTONDATA); - tcp_reset(sk); + + if (sk->sk_state == TCP_CLOSE_WAIT || + sk->sk_state == TCP_LAST_ACK) + tcp_reset(sk); + else + tcp_time_wait(sk, TCP_TIME_WAIT, 0); + return 1; } } -- 2.4.10 ^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [PATCH -next] net: tcp: move to timewait when receiving data post active-close 2015-11-18 15:03 [PATCH -next] net: tcp: move to timewait when receiving data post active-close Florian Westphal @ 2015-11-18 15:28 ` Eric Dumazet 2015-11-18 15:36 ` Florian Westphal 0 siblings, 1 reply; 10+ messages in thread From: Eric Dumazet @ 2015-11-18 15:28 UTC (permalink / raw) To: Florian Westphal; +Cc: netdev, marcelo.leitner On Wed, 2015-11-18 at 16:03 +0100, Florian Westphal wrote: > RFC 1122, 4.2.2.13: > [..] if new data is received after CLOSE is called, its TCP > SHOULD send a RST to show that data was lost. > > When a connection is closed actively, it MUST linger in > TIME-WAIT state [..]. > > We reset a connection, but destroy state immediately. > > After discussing this with Hannes, we decided it was preferable > to also move to TW state to avoid immediate port reuse. > > packetdrill testcase: > > 0.000 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3 > 0.000 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0 > 0.000 bind(3, ..., ...) = 0 > 0.000 listen(3, 1) = 0 > 0.100 < S 0:0(0) win 29200 <mss 1460> > 0.100 > S. 0:0(0) ack 1 <mss 1460> > 0.200 < . 1:1(0) ack 1 win 257 > 0.200 accept(3, ..., ...) = 4 > // close our side. > 0.210 close(4) = 0 > // we should expect to see FIN now, sk moves to FIN_WAIT_1 > 0.210 > F. 1:1(0) ack 1 win 29200 > // receive data, but sk already closed -> Reset > 0.300 < P. 1:1001(1000) ack 1 win 46 > 0.300 > R 1:1(0) win 0 Thanks for using packetdrill ;) This packetdrill test shows nothing special regarding your patch, it should work right now with current kernels ??? lpk51:~# tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on any, link-type LINUX_SLL (Linux cooked), capture size 262144 bytes lpk51:~# ./packetdrill Florian.pkt 07:26:49.656548 IP 192.0.2.1.59883 > 192.168.155.177.8080: Flags [S], seq 0, win 29200, options [mss 1460], length 0 07:26:49.656611 IP 192.168.155.177.8080 > 192.0.2.1.59883: Flags [S.], seq 1433468786, ack 1, win 29200, options [mss 1460], length 0 07:26:49.756530 IP 192.0.2.1.59883 > 192.168.155.177.8080: Flags [.], ack 1, win 257, length 0 07:26:49.766529 IP 192.168.155.177.8080 > 192.0.2.1.59883: Flags [F.], seq 1, ack 1, win 29200, length 0 07:26:49.856529 IP 192.0.2.1.59883 > 192.168.155.177.8080: Flags [P.], seq 1:1001, ack 1, win 46, length 1000: HTTP 07:26:49.856560 IP 192.168.155.177.8080 > 192.0.2.1.59883: Flags [R], seq 1433468787, win 0, length 0 07:26:49.856806 IP 192.0.2.1.59883 > 192.168.155.177.8080: Flags [R.], seq 1001, ack 1, win 46, length 0 ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH -next] net: tcp: move to timewait when receiving data post active-close 2015-11-18 15:28 ` Eric Dumazet @ 2015-11-18 15:36 ` Florian Westphal 2015-11-18 15:46 ` Eric Dumazet 0 siblings, 1 reply; 10+ messages in thread From: Florian Westphal @ 2015-11-18 15:36 UTC (permalink / raw) To: Eric Dumazet; +Cc: Florian Westphal, netdev, marcelo.leitner Eric Dumazet <eric.dumazet@gmail.com> wrote: > On Wed, 2015-11-18 at 16:03 +0100, Florian Westphal wrote: > > RFC 1122, 4.2.2.13: > > [..] if new data is received after CLOSE is called, its TCP > > SHOULD send a RST to show that data was lost. > > > > When a connection is closed actively, it MUST linger in > > TIME-WAIT state [..]. > > > > We reset a connection, but destroy state immediately. > > > > After discussing this with Hannes, we decided it was preferable > > to also move to TW state to avoid immediate port reuse. > > > > packetdrill testcase: > > > > 0.000 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3 > > 0.000 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0 > > 0.000 bind(3, ..., ...) = 0 > > 0.000 listen(3, 1) = 0 > > 0.100 < S 0:0(0) win 29200 <mss 1460> > > 0.100 > S. 0:0(0) ack 1 <mss 1460> > > 0.200 < . 1:1(0) ack 1 win 257 > > 0.200 accept(3, ..., ...) = 4 > > // close our side. > > 0.210 close(4) = 0 > > // we should expect to see FIN now, sk moves to FIN_WAIT_1 > > 0.210 > F. 1:1(0) ack 1 win 29200 > > // receive data, but sk already closed -> Reset > > 0.300 < P. 1:1001(1000) ack 1 win 46 > > 0.300 > R 1:1(0) win 0 > This packetdrill test shows nothing special regarding your patch, it > should work right now with current kernels ??? Yes, but we kill the socket. I should have added 0.400 `ss -nito state time-wait` as last line... Before patch: no output after patch: tw socket shown. The on-wire behavior doesn't change unless further packets arrive. Old behaviour: more RST New behaviour: acks+tw timer restart Sorry for the confusion. ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH -next] net: tcp: move to timewait when receiving data post active-close 2015-11-18 15:36 ` Florian Westphal @ 2015-11-18 15:46 ` Eric Dumazet 2015-11-18 15:54 ` Hannes Frederic Sowa 2015-11-19 17:11 ` David Miller 0 siblings, 2 replies; 10+ messages in thread From: Eric Dumazet @ 2015-11-18 15:46 UTC (permalink / raw) To: Florian Westphal; +Cc: netdev, marcelo.leitner On Wed, 2015-11-18 at 16:36 +0100, Florian Westphal wrote: > Yes, but we kill the socket. > > I should have added > > 0.400 `ss -nito state time-wait` > > as last line... > > Before patch: no output > after patch: tw socket shown. > > The on-wire behavior doesn't change unless further packets arrive. > Old behaviour: more RST > New behaviour: acks+tw timer restart Just add few more incoming packets to the packetdrill test then ? Also, is your customer really _not_ using TCP timestamps ? This is kind of a requirement for port reuse anyway. Anyway, having a TIMEWAIT setup after sending a RST makes little sense to me. When a RST packet is sent, the remote peer will forget everything about this previous connection, and another connect() might reuse the tuple and I do not think we should forbid this. Normal PAWS checks were invented for a good reason. RFC 1122, 4.2.2.13 can be interpreted in very different ways. Please show us real issue your customer has. ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH -next] net: tcp: move to timewait when receiving data post active-close 2015-11-18 15:46 ` Eric Dumazet @ 2015-11-18 15:54 ` Hannes Frederic Sowa 2015-11-18 17:28 ` Eric Dumazet 2015-11-19 17:11 ` David Miller 1 sibling, 1 reply; 10+ messages in thread From: Hannes Frederic Sowa @ 2015-11-18 15:54 UTC (permalink / raw) To: Eric Dumazet, Florian Westphal; +Cc: netdev, marcelo.leitner On Wed, Nov 18, 2015, at 16:46, Eric Dumazet wrote: > On Wed, 2015-11-18 at 16:36 +0100, Florian Westphal wrote: > > > Yes, but we kill the socket. > > > > I should have added > > > > 0.400 `ss -nito state time-wait` > > > > as last line... > > > > Before patch: no output > > after patch: tw socket shown. > > > > The on-wire behavior doesn't change unless further packets arrive. > > Old behaviour: more RST > > New behaviour: acks+tw timer restart > > Just add few more incoming packets to the packetdrill test then ? > > Also, is your customer really _not_ using TCP timestamps ? Windows mostly does not use TCP timestamps. Also we have cases were security folks tell customers to turn off timestamps as they enable attackers to guess uptime. :( > This is kind of a requirement for port reuse anyway. > > Anyway, having a TIMEWAIT setup after sending a RST makes little sense > to me. > > When a RST packet is sent, the remote peer will forget everything about > this previous connection, and another connect() might reuse the tuple > and I do not think we should forbid this. Normal PAWS checks were > invented for a good reason. Still, the RST packet can be dropped along the way. So the teardown of the socket on the other side might not happen. Bye, Hannes ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH -next] net: tcp: move to timewait when receiving data post active-close 2015-11-18 15:54 ` Hannes Frederic Sowa @ 2015-11-18 17:28 ` Eric Dumazet 2015-11-18 17:32 ` Florian Westphal 2015-11-18 17:35 ` Hannes Frederic Sowa 0 siblings, 2 replies; 10+ messages in thread From: Eric Dumazet @ 2015-11-18 17:28 UTC (permalink / raw) To: Hannes Frederic Sowa; +Cc: Florian Westphal, netdev, marcelo.leitner On Wed, 2015-11-18 at 16:54 +0100, Hannes Frederic Sowa wrote: > Still, the RST packet can be dropped along the way. So the teardown of > the socket on the other side might not happen. This is why it is better to send RST for every incoming in-excess packet Try following packetdrill test, before and after your patch : 0.000 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3 0.000 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0 0.000 bind(3, ..., ...) = 0 0.000 listen(3, 1) = 0 0.100 < S 0:0(0) win 29200 <mss 1460> 0.100 > S. 0:0(0) ack 1 <mss 1460> 0.200 < . 1:1(0) ack 1 win 257 0.200 accept(3, ..., ...) = 4 // close our side. 0.210 close(4) = 0 // we should expect to see FIN now, sk moves to FIN_WAIT_1 0.210 > F. 1:1(0) ack 1 win 29200 // receive data, but sk already closed -> Reset +.010 < P. 1:1001(1000) ack 1 win 46 +0 > R 1:1(0) win 0 // Are we properly sending a RST like prior packet did ? +.010 < P. 1001:2001(1000) ack 1 win 46 +0 > R 1:1(0) win 0 ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH -next] net: tcp: move to timewait when receiving data post active-close 2015-11-18 17:28 ` Eric Dumazet @ 2015-11-18 17:32 ` Florian Westphal 2015-11-18 17:35 ` Hannes Frederic Sowa 1 sibling, 0 replies; 10+ messages in thread From: Florian Westphal @ 2015-11-18 17:32 UTC (permalink / raw) To: Eric Dumazet Cc: Hannes Frederic Sowa, Florian Westphal, netdev, marcelo.leitner Eric Dumazet <eric.dumazet@gmail.com> wrote: > On Wed, 2015-11-18 at 16:54 +0100, Hannes Frederic Sowa wrote: > > > Still, the RST packet can be dropped along the way. So the teardown of > > the socket on the other side might not happen. > > This is why it is better to send RST for every incoming in-excess packet I'm convinced and marked patch as rejected in patchwork. Thanks Eric! ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH -next] net: tcp: move to timewait when receiving data post active-close 2015-11-18 17:28 ` Eric Dumazet 2015-11-18 17:32 ` Florian Westphal @ 2015-11-18 17:35 ` Hannes Frederic Sowa 2015-11-18 18:35 ` Eric Dumazet 1 sibling, 1 reply; 10+ messages in thread From: Hannes Frederic Sowa @ 2015-11-18 17:35 UTC (permalink / raw) To: Eric Dumazet; +Cc: Florian Westphal, netdev, marcelo.leitner On Wed, Nov 18, 2015, at 18:28, Eric Dumazet wrote: > On Wed, 2015-11-18 at 16:54 +0100, Hannes Frederic Sowa wrote: > > > Still, the RST packet can be dropped along the way. So the teardown of > > the socket on the other side might not happen. > > This is why it is better to send RST for every incoming in-excess packet I agree it would be better to send a RST than ACK incoming data. Just thinking out loud, would it make sense to add a sub-state to timewait so we RST all other packets for TIMEWAIT_LEN duration? > Try following packetdrill test, before and after your patch : > > 0.000 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3 > 0.000 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0 > 0.000 bind(3, ..., ...) = 0 > 0.000 listen(3, 1) = 0 > 0.100 < S 0:0(0) win 29200 <mss 1460> > 0.100 > S. 0:0(0) ack 1 <mss 1460> > 0.200 < . 1:1(0) ack 1 win 257 > 0.200 accept(3, ..., ...) = 4 > // close our side. > 0.210 close(4) = 0 > // we should expect to see FIN now, sk moves to FIN_WAIT_1 > 0.210 > F. 1:1(0) ack 1 win 29200 > > // receive data, but sk already closed -> Reset > +.010 < P. 1:1001(1000) ack 1 win 46 > +0 > R 1:1(0) win 0 > > // Are we properly sending a RST like prior packet did ? > +.010 < P. 1001:2001(1000) ack 1 win 46 > +0 > R 1:1(0) win 0 Thanks, Hannes ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH -next] net: tcp: move to timewait when receiving data post active-close 2015-11-18 17:35 ` Hannes Frederic Sowa @ 2015-11-18 18:35 ` Eric Dumazet 0 siblings, 0 replies; 10+ messages in thread From: Eric Dumazet @ 2015-11-18 18:35 UTC (permalink / raw) To: Hannes Frederic Sowa; +Cc: Florian Westphal, netdev, marcelo.leitner On Wed, 2015-11-18 at 18:35 +0100, Hannes Frederic Sowa wrote: > On Wed, Nov 18, 2015, at 18:28, Eric Dumazet wrote: > > On Wed, 2015-11-18 at 16:54 +0100, Hannes Frederic Sowa wrote: > > > > > Still, the RST packet can be dropped along the way. So the teardown of > > > the socket on the other side might not happen. > > > > This is why it is better to send RST for every incoming in-excess packet > > I agree it would be better to send a RST than ACK incoming data. Just > thinking out loud, would it make sense to add a sub-state to timewait so > we RST all other packets for TIMEWAIT_LEN duration? Intuitively this timewait creation looks dangerous to me, maybe from an attack surface perspective. An out of sequence packet sends an advisory RST packet, which is already a hint for building some kinds of attacks. Now if we also create a timewait socket, and its associated timer, we also add quite a risk of memory and cpu consumption. So I am fine you create a timewait, only if you can prove there is no change in security. Thanks ! ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH -next] net: tcp: move to timewait when receiving data post active-close 2015-11-18 15:46 ` Eric Dumazet 2015-11-18 15:54 ` Hannes Frederic Sowa @ 2015-11-19 17:11 ` David Miller 1 sibling, 0 replies; 10+ messages in thread From: David Miller @ 2015-11-19 17:11 UTC (permalink / raw) To: eric.dumazet; +Cc: fw, netdev, marcelo.leitner From: Eric Dumazet <eric.dumazet@gmail.com> Date: Wed, 18 Nov 2015 07:46:31 -0800 > Anyway, having a TIMEWAIT setup after sending a RST makes little > sense to me. > > When a RST packet is sent, the remote peer will forget everything about > this previous connection, and another connect() might reuse the tuple > and I do not think we should forbid this. Normal PAWS checks were > invented for a good reason. > > RFC 1122, 4.2.2.13 can be interpreted in very different ways. I think it is clear that once RST is emitted, that connection ID no longer exists, on both ends. Sender of RST must not have that matching state, and receiver of RST must tear things down. ^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2015-11-19 17:11 UTC | newest] Thread overview: 10+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2015-11-18 15:03 [PATCH -next] net: tcp: move to timewait when receiving data post active-close Florian Westphal 2015-11-18 15:28 ` Eric Dumazet 2015-11-18 15:36 ` Florian Westphal 2015-11-18 15:46 ` Eric Dumazet 2015-11-18 15:54 ` Hannes Frederic Sowa 2015-11-18 17:28 ` Eric Dumazet 2015-11-18 17:32 ` Florian Westphal 2015-11-18 17:35 ` Hannes Frederic Sowa 2015-11-18 18:35 ` Eric Dumazet 2015-11-19 17:11 ` David Miller
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).