From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S966758AbcKLSOS (ORCPT ); Sat, 12 Nov 2016 13:14:18 -0500 Received: from mail-it0-f48.google.com ([209.85.214.48]:38328 "EHLO mail-it0-f48.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S966533AbcKLSOQ (ORCPT ); Sat, 12 Nov 2016 13:14:16 -0500 Subject: Re: Source address fib invalidation on IPv6 To: "Jason A. Donenfeld" References: <31e050e2-0499-a77e-f698-86e58ad2fa6b@cumulusnetworks.com> Cc: Netdev , WireGuard mailing list , LKML , YOSHIFUJI Hideaki , Hannes Frederic Sowa From: David Ahern Message-ID: <0dbf5deb-bffb-4878-a268-1adb17c47676@cumulusnetworks.com> Date: Sat, 12 Nov 2016 11:14:01 -0700 User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.11; rv:45.0) Gecko/20100101 Thunderbird/45.4.0 MIME-Version: 1.0 In-Reply-To: Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 7bit Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org On 11/12/16 8:40 AM, Jason A. Donenfeld wrote: > Hi again, > > I've done some pretty in depth debugging now to determine exactly what > the behavior of ipv6_stub->ipv6_dst_lookup is. First I'll start with > ip_route_output_flow, which I believe to be well behaved, and then > I'll show ipv6_stub->ipv6_dst_lookup, which seems ill-behaved: > > Userspace: > ip addr add 192.168.1.2/24 dev eth0 > Kernelspace: > struct flowi4 fl = { > .saddr = 192.168.1.2, > .daddr = 192.168.1.99, > }; > rt = ip_route_output_flow(sock_net(sock), &fl, sock); > // rt returns valid rt for routing to 192.168.1.99 from > 192.168.1.2 using eth0 > Userspace: > ip addr add 192.168.1.3/24 dev eth0 > ip addr del 192.168.1.2/24 dev eth0 > Kernelspace: > struct flowi4 fl = { > .saddr = 192.168.1.2, > .daddr = 192.168.1.99, > }; > rt = ip_route_output_flow(sock_net(sock), &fl, sock); > // PTR_ERR(rt) == -EINVAL I believe that is coming from __ip_route_output_key_hash(), line 2232 with __ip_dev_find not finding a device with that address. Not applicable for your use case, but __ip_dev_find does not have any checks on which L3 domain the device belongs to so the check does not handle VRF for example. I'll take a look at fixing this next week. > > This seems correct behavior to me, since no interface has 192.168.1.2 > as a source address. > > Now for the incorrect IPv6 behavior: > > Userspace: > ip -6 addr add abcd::2/96 dev eth0 > Kernelspace: > struct flowi6 fl = { > .saddr = abcd::2, > .daddr = abcd::99, > }; > ret = ipv6_stub->ipv6_dst_lookup(sock_net(sock), sock, &dst, &fl); > // ret is 0, and dst is a non-null dst routing to abcd::99 from > abcd::2 using eth0 > Userspace: > ip -6 addr add abcd::3/96 dev eth0 > ip -6 addr del abcd::2/96 dev eth0 > Kernelspace: > struct flowi6 fl = { > .saddr = abcd::2, > .daddr = abcd::99, > }; > ret = ipv6_stub->ipv6_dst_lookup(sock_net(sock), sock, &dst, &fl); > // ret is 0, and dst is a non-null dst routing to abcd::99 from > abcd::2 using eth0 **INCORRECT BEHAVIOR!** > > This seems *INCORRECT* behavior to me, since no interface has abcd::2 > as a source address. Gotcha. I don't see any checks that the saddr is valid similar to what IPv4 does. I think the right place to add a check is in ip6_dst_lookup_tail(): if (!ipv6_addr_any(&fl6->saddr)) { // saddr is valid for L3 domain } From mboxrd@z Thu Jan 1 00:00:00 1970 From: David Ahern Subject: Re: Source address fib invalidation on IPv6 Date: Sat, 12 Nov 2016 11:14:01 -0700 Message-ID: <0dbf5deb-bffb-4878-a268-1adb17c47676@cumulusnetworks.com> References: <31e050e2-0499-a77e-f698-86e58ad2fa6b@cumulusnetworks.com> Mime-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Cc: Netdev , Hannes Frederic Sowa , LKML , WireGuard mailing list , YOSHIFUJI Hideaki To: "Jason A. Donenfeld" Return-path: In-Reply-To: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: wireguard-bounces@lists.zx2c4.com Sender: "WireGuard" List-Id: netdev.vger.kernel.org On 11/12/16 8:40 AM, Jason A. Donenfeld wrote: > Hi again, > > I've done some pretty in depth debugging now to determine exactly what > the behavior of ipv6_stub->ipv6_dst_lookup is. First I'll start with > ip_route_output_flow, which I believe to be well behaved, and then > I'll show ipv6_stub->ipv6_dst_lookup, which seems ill-behaved: > > Userspace: > ip addr add 192.168.1.2/24 dev eth0 > Kernelspace: > struct flowi4 fl = { > .saddr = 192.168.1.2, > .daddr = 192.168.1.99, > }; > rt = ip_route_output_flow(sock_net(sock), &fl, sock); > // rt returns valid rt for routing to 192.168.1.99 from > 192.168.1.2 using eth0 > Userspace: > ip addr add 192.168.1.3/24 dev eth0 > ip addr del 192.168.1.2/24 dev eth0 > Kernelspace: > struct flowi4 fl = { > .saddr = 192.168.1.2, > .daddr = 192.168.1.99, > }; > rt = ip_route_output_flow(sock_net(sock), &fl, sock); > // PTR_ERR(rt) == -EINVAL I believe that is coming from __ip_route_output_key_hash(), line 2232 with __ip_dev_find not finding a device with that address. Not applicable for your use case, but __ip_dev_find does not have any checks on which L3 domain the device belongs to so the check does not handle VRF for example. I'll take a look at fixing this next week. > > This seems correct behavior to me, since no interface has 192.168.1.2 > as a source address. > > Now for the incorrect IPv6 behavior: > > Userspace: > ip -6 addr add abcd::2/96 dev eth0 > Kernelspace: > struct flowi6 fl = { > .saddr = abcd::2, > .daddr = abcd::99, > }; > ret = ipv6_stub->ipv6_dst_lookup(sock_net(sock), sock, &dst, &fl); > // ret is 0, and dst is a non-null dst routing to abcd::99 from > abcd::2 using eth0 > Userspace: > ip -6 addr add abcd::3/96 dev eth0 > ip -6 addr del abcd::2/96 dev eth0 > Kernelspace: > struct flowi6 fl = { > .saddr = abcd::2, > .daddr = abcd::99, > }; > ret = ipv6_stub->ipv6_dst_lookup(sock_net(sock), sock, &dst, &fl); > // ret is 0, and dst is a non-null dst routing to abcd::99 from > abcd::2 using eth0 **INCORRECT BEHAVIOR!** > > This seems *INCORRECT* behavior to me, since no interface has abcd::2 > as a source address. Gotcha. I don't see any checks that the saddr is valid similar to what IPv4 does. I think the right place to add a check is in ip6_dst_lookup_tail(): if (!ipv6_addr_any(&fl6->saddr)) { // saddr is valid for L3 domain } From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: dsa@cumulusnetworks.com Received: from mail-it0-f50.google.com (mail-it0-f50.google.com [209.85.214.50]) by krantz.zx2c4.com (ZX2C4 Mail Server) with ESMTP id 26e62cf8 for ; Sat, 12 Nov 2016 18:11:53 +0000 (UTC) Received: by mail-it0-f50.google.com with SMTP id q124so36383109itd.1 for ; Sat, 12 Nov 2016 10:14:15 -0800 (PST) Return-Path: To: "Jason A. Donenfeld" References: <31e050e2-0499-a77e-f698-86e58ad2fa6b@cumulusnetworks.com> From: David Ahern Message-ID: <0dbf5deb-bffb-4878-a268-1adb17c47676@cumulusnetworks.com> Date: Sat, 12 Nov 2016 11:14:01 -0700 MIME-Version: 1.0 In-Reply-To: Content-Type: text/plain; charset=utf-8 Cc: Netdev , Hannes Frederic Sowa , LKML , WireGuard mailing list , YOSHIFUJI Hideaki Subject: Re: [WireGuard] Source address fib invalidation on IPv6 List-Id: Development discussion of WireGuard List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , On 11/12/16 8:40 AM, Jason A. Donenfeld wrote: > Hi again, > > I've done some pretty in depth debugging now to determine exactly what > the behavior of ipv6_stub->ipv6_dst_lookup is. First I'll start with > ip_route_output_flow, which I believe to be well behaved, and then > I'll show ipv6_stub->ipv6_dst_lookup, which seems ill-behaved: > > Userspace: > ip addr add 192.168.1.2/24 dev eth0 > Kernelspace: > struct flowi4 fl = { > .saddr = 192.168.1.2, > .daddr = 192.168.1.99, > }; > rt = ip_route_output_flow(sock_net(sock), &fl, sock); > // rt returns valid rt for routing to 192.168.1.99 from > 192.168.1.2 using eth0 > Userspace: > ip addr add 192.168.1.3/24 dev eth0 > ip addr del 192.168.1.2/24 dev eth0 > Kernelspace: > struct flowi4 fl = { > .saddr = 192.168.1.2, > .daddr = 192.168.1.99, > }; > rt = ip_route_output_flow(sock_net(sock), &fl, sock); > // PTR_ERR(rt) == -EINVAL I believe that is coming from __ip_route_output_key_hash(), line 2232 with __ip_dev_find not finding a device with that address. Not applicable for your use case, but __ip_dev_find does not have any checks on which L3 domain the device belongs to so the check does not handle VRF for example. I'll take a look at fixing this next week. > > This seems correct behavior to me, since no interface has 192.168.1.2 > as a source address. > > Now for the incorrect IPv6 behavior: > > Userspace: > ip -6 addr add abcd::2/96 dev eth0 > Kernelspace: > struct flowi6 fl = { > .saddr = abcd::2, > .daddr = abcd::99, > }; > ret = ipv6_stub->ipv6_dst_lookup(sock_net(sock), sock, &dst, &fl); > // ret is 0, and dst is a non-null dst routing to abcd::99 from > abcd::2 using eth0 > Userspace: > ip -6 addr add abcd::3/96 dev eth0 > ip -6 addr del abcd::2/96 dev eth0 > Kernelspace: > struct flowi6 fl = { > .saddr = abcd::2, > .daddr = abcd::99, > }; > ret = ipv6_stub->ipv6_dst_lookup(sock_net(sock), sock, &dst, &fl); > // ret is 0, and dst is a non-null dst routing to abcd::99 from > abcd::2 using eth0 **INCORRECT BEHAVIOR!** > > This seems *INCORRECT* behavior to me, since no interface has abcd::2 > as a source address. Gotcha. I don't see any checks that the saddr is valid similar to what IPv4 does. I think the right place to add a check is in ip6_dst_lookup_tail(): if (!ipv6_addr_any(&fl6->saddr)) { // saddr is valid for L3 domain }