From patchwork Fri Oct 12 14:34:17 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexey Kuznetsov X-Patchwork-Id: 191145 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 6674D2C008B for ; Sat, 13 Oct 2012 02:14:32 +1100 (EST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1759695Ab2JLPOY (ORCPT ); Fri, 12 Oct 2012 11:14:24 -0400 Received: from minus.inr.ac.ru ([194.67.69.97]:42071 "HELO ms2.inr.ac.ru" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with SMTP id S1755474Ab2JLPOX (ORCPT ); Fri, 12 Oct 2012 11:14:23 -0400 X-Greylist: delayed 2369 seconds by postgrey-1.27 at vger.kernel.org; Fri, 12 Oct 2012 11:14:12 EDT DomainKey-Signature: a=rsa-sha1; q=dns; c=nofws; s=s1024; d=ms2.inr.ac.ru; b=XuJqvmBfHtk6KYUAfN98fcpboc90IPmMBwgJdm8mdDH16Aa9CkyghT3NEOleh0YtHl8JRgLuMMj2qLBIM+9aasA3jGlIPQF0MsL/ukkeyhtQYsuJ7aU+sySPrsN1qvLQkGU4KnMhDBZZYKDnDlZyUkO475fALPHh+LeH6vtQiGY=; Received: (from kuznet@localhost) envelope-from=kuznet by ms2.inr.ac.ru (8.6.13/ANK) id SAA08860; Fri, 12 Oct 2012 18:34:17 +0400 Date: Fri, 12 Oct 2012 18:34:17 +0400 From: Alexey Kuznetsov To: netdev@vger.kernel.org, davem@davemloft.net, shawn.lu@ericsson.com, eric.dumazet@gmail.com, sol@eqv.ru Subject: [PATCH] tcp resets are misrouted Message-ID: <20121012143417.GA8481@ms2.inr.ac.ru> Mime-Version: 1.0 Content-Disposition: inline User-Agent: Mutt/1.5.6i Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org After commit e2446eaa.. tcp resets are always lost, when routing is asymmetric. Yes, backing out that patch will result in misrouting of resets for dead connections which used interface binding when were alive, but we actually cannot do anything here. What's died that's died and correct handling normal unbound connections is obviously a priority. Comment to comment: > This has few benefits: > 1. tcp_v6_send_reset already did that. It was done to route resets for IPv6 link local addresses. It was a mistake to do so for global addresses. The patch fixes this as well. Actually, the problem appears to be even more serious than guaranteed loss of resets. As reported by Sergey Soloviev , those misrouted resets create a lot of arp traffic and huge amount of unresolved arp entires putting down to knees NAT firewalls which use asymmetric routing. Signed-off-by: Alexey Kuznetsov --- net/ipv4/tcp_ipv4.c | 7 ++++--- net/ipv6/tcp_ipv6.c | 3 ++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 75735c9..ef998b0 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -708,10 +708,11 @@ static void tcp_v4_send_reset(struct sock *sk, struct sk_buff *skb) arg.csumoffset = offsetof(struct tcphdr, check) / 2; arg.flags = (sk && inet_sk(sk)->transparent) ? IP_REPLY_ARG_NOSRCCHECK : 0; /* When socket is gone, all binding information is lost. - * routing might fail in this case. using iif for oif to - * make sure we can deliver it + * routing might fail in this case. No choice here, if we choose to force + * input interface, we will misroute in case of asymmetric route. */ - arg.bound_dev_if = sk ? sk->sk_bound_dev_if : inet_iif(skb); + if (sk) + arg.bound_dev_if = sk->sk_bound_dev_if; net = dev_net(skb_dst(skb)->dev); arg.tos = ip_hdr(skb)->tos; diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 49c8903..26175bf 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -877,7 +877,8 @@ static void tcp_v6_send_response(struct sk_buff *skb, u32 seq, u32 ack, u32 win, __tcp_v6_send_check(buff, &fl6.saddr, &fl6.daddr); fl6.flowi6_proto = IPPROTO_TCP; - fl6.flowi6_oif = inet6_iif(skb); + if (ipv6_addr_type(&fl6.daddr) & IPV6_ADDR_LINKLOCAL) + fl6.flowi6_oif = inet6_iif(skb); fl6.fl6_dport = t1->dest; fl6.fl6_sport = t1->source; security_skb_classify_flow(skb, flowi6_to_flowi(&fl6));