aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorHannes Frederic Sowa <hannes@stressinduktion.org>2014-08-14 16:06:12 -0400
committerDavid S. Miller <davem@davemloft.net>2014-08-14 17:38:54 -0400
commita26552afe89438eefbe097512b3187f2c7e929fd (patch)
tree714af26aeea98f9c3faa2d99f4ca979979f1eac2 /net
parent4fab9071950c2021d846e18351e0f46a1cffd67b (diff)
tcp: don't allow syn packets without timestamps to pass tcp_tw_recycle logic
tcp_tw_recycle heavily relies on tcp timestamps to build a per-host ordering of incoming connections and teardowns without the need to hold state on a specific quadruple for TCP_TIMEWAIT_LEN, but only for the last measured RTO. To do so, we keep the last seen timestamp in a per-host indexed data structure and verify if the incoming timestamp in a connection request is strictly greater than the saved one during last connection teardown. Thus we can verify later on that no old data packets will be accepted by the new connection. During moving a socket to time-wait state we already verify if timestamps where seen on a connection. Only if that was the case we let the time-wait socket expire after the RTO, otherwise normal TCP_TIMEWAIT_LEN will be used. But we don't verify this on incoming SYN packets. If a connection teardown was less than TCP_PAWS_MSL seconds in the past we cannot guarantee to not accept data packets from an old connection if no timestamps are present. We should drop this SYN packet. This patch closes this loophole. Please note, this patch does not make tcp_tw_recycle in any way more usable but only adds another safety check: Sporadic drops of SYN packets because of reordering in the network or in the socket backlog queues can happen. Users behing NAT trying to connect to a tcp_tw_recycle enabled server can get caught in blackholes and their connection requests may regullary get dropped because hosts behind an address translator don't have synchronized tcp timestamp clocks. tcp_tw_recycle cannot work if peers don't have tcp timestamps enabled. In general, use of tcp_tw_recycle is disadvised. Cc: Eric Dumazet <eric.dumazet@gmail.com> Cc: Florian Westphal <fw@strlen.de> Signed-off-by: Hannes Frederic Sowa <hannes@stressinduktion.org> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r--net/ipv4/tcp_input.c9
-rw-r--r--net/ipv4/tcp_metrics.c6
2 files changed, 10 insertions, 5 deletions
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index 1a8e89fdd331..4f6cfbc57775 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -5979,12 +5979,14 @@ int tcp_conn_request(struct request_sock_ops *rsk_ops,
5979 * timewait bucket, so that all the necessary checks 5979 * timewait bucket, so that all the necessary checks
5980 * are made in the function processing timewait state. 5980 * are made in the function processing timewait state.
5981 */ 5981 */
5982 if (tmp_opt.saw_tstamp && tcp_death_row.sysctl_tw_recycle) { 5982 if (tcp_death_row.sysctl_tw_recycle) {
5983 bool strict; 5983 bool strict;
5984 5984
5985 dst = af_ops->route_req(sk, &fl, req, &strict); 5985 dst = af_ops->route_req(sk, &fl, req, &strict);
5986
5986 if (dst && strict && 5987 if (dst && strict &&
5987 !tcp_peer_is_proven(req, dst, true)) { 5988 !tcp_peer_is_proven(req, dst, true,
5989 tmp_opt.saw_tstamp)) {
5988 NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_PAWSPASSIVEREJECTED); 5990 NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_PAWSPASSIVEREJECTED);
5989 goto drop_and_release; 5991 goto drop_and_release;
5990 } 5992 }
@@ -5993,7 +5995,8 @@ int tcp_conn_request(struct request_sock_ops *rsk_ops,
5993 else if (!sysctl_tcp_syncookies && 5995 else if (!sysctl_tcp_syncookies &&
5994 (sysctl_max_syn_backlog - inet_csk_reqsk_queue_len(sk) < 5996 (sysctl_max_syn_backlog - inet_csk_reqsk_queue_len(sk) <
5995 (sysctl_max_syn_backlog >> 2)) && 5997 (sysctl_max_syn_backlog >> 2)) &&
5996 !tcp_peer_is_proven(req, dst, false)) { 5998 !tcp_peer_is_proven(req, dst, false,
5999 tmp_opt.saw_tstamp)) {
5997 /* Without syncookies last quarter of 6000 /* Without syncookies last quarter of
5998 * backlog is filled with destinations, 6001 * backlog is filled with destinations,
5999 * proven to be alive. 6002 * proven to be alive.
diff --git a/net/ipv4/tcp_metrics.c b/net/ipv4/tcp_metrics.c
index 0d54e59b9ea8..ed9c9a91851c 100644
--- a/net/ipv4/tcp_metrics.c
+++ b/net/ipv4/tcp_metrics.c
@@ -576,7 +576,8 @@ reset:
576 tp->snd_cwnd_stamp = tcp_time_stamp; 576 tp->snd_cwnd_stamp = tcp_time_stamp;
577} 577}
578 578
579bool tcp_peer_is_proven(struct request_sock *req, struct dst_entry *dst, bool paws_check) 579bool tcp_peer_is_proven(struct request_sock *req, struct dst_entry *dst,
580 bool paws_check, bool timestamps)
580{ 581{
581 struct tcp_metrics_block *tm; 582 struct tcp_metrics_block *tm;
582 bool ret; 583 bool ret;
@@ -589,7 +590,8 @@ bool tcp_peer_is_proven(struct request_sock *req, struct dst_entry *dst, bool pa
589 if (paws_check) { 590 if (paws_check) {
590 if (tm && 591 if (tm &&
591 (u32)get_seconds() - tm->tcpm_ts_stamp < TCP_PAWS_MSL && 592 (u32)get_seconds() - tm->tcpm_ts_stamp < TCP_PAWS_MSL &&
592 (s32)(tm->tcpm_ts - req->ts_recent) > TCP_PAWS_WINDOW) 593 ((s32)(tm->tcpm_ts - req->ts_recent) > TCP_PAWS_WINDOW ||
594 !timestamps))
593 ret = false; 595 ret = false;
594 else 596 else
595 ret = true; 597 ret = true;