From 51fdefb522cd41583689558b474db680ae95e94b Mon Sep 17 00:00:00 2001 From: "Jason A. Donenfeld" Date: Tue, 15 Nov 2016 02:42:40 +0100 Subject: socket: ensure that saddr routing can deal with interface removal --- src/socket.c | 11 +++++++++++ src/tests/netns.sh | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/src/socket.c b/src/socket.c index 20e82fd..970e0d6 100644 --- a/src/socket.c +++ b/src/socket.c @@ -43,6 +43,12 @@ static inline int send4(struct wireguard_device *wg, struct sk_buff *skb, struct if (!rt) { security_sk_classify_flow(sock, flowi4_to_flowi(&fl)); rt = ip_route_output_flow(sock_net(sock), &fl, sock); + if (unlikely(IS_ERR(rt) && PTR_ERR(rt) == -EINVAL && fl.saddr)) { + endpoint->src4.s_addr = fl.saddr = 0; + if (cache) + dst_cache_reset(cache); + rt = ip_route_output_flow(sock_net(sock), &fl, sock); + } if (unlikely(IS_ERR(rt))) { ret = PTR_ERR(rt); net_dbg_ratelimited("No route to %pISpfsc, error %d\n", &endpoint->addr_storage, ret); @@ -103,6 +109,11 @@ static inline int send6(struct wireguard_device *wg, struct sk_buff *skb, struct if (!dst) { security_sk_classify_flow(sock, flowi6_to_flowi(&fl)); + if (unlikely(!ipv6_addr_any(&fl.saddr) && !ipv6_chk_addr(sock_net(sock), &fl.saddr, NULL, 0))) { + endpoint->src6 = fl.saddr = in6addr_any; + if (cache) + dst_cache_reset(cache); + } ret = ipv6_stub->ipv6_dst_lookup(sock_net(sock), sock, &dst, &fl); if (unlikely(ret)) { net_dbg_ratelimited("No route to %pISpfsc, error %d\n", &endpoint->addr_storage, ret); diff --git a/src/tests/netns.sh b/src/tests/netns.sh index 1c638d4..4ee8cd1 100755 --- a/src/tests/netns.sh +++ b/src/tests/netns.sh @@ -247,3 +247,35 @@ n2 wg # Demonstrate n2 can still send packets to n1, since persistent-keepalive will prevent connection tracking entry from expiring (to see entries: `n0 conntrack -L`). pp sleep 3 n2 ping -W 1 -c 1 192.168.241.1 + +n0 iptables -t nat -F +ip0 link del vethrc +ip0 link del vethrs +ip1 link del wg0 +ip2 link del wg0 + +# Test that saddr routing isn't overly sticky +ip1 link add dev wg0 type wireguard +ip2 link add dev wg0 type wireguard +configure_peers +ip1 link add veth1 type veth peer name veth2 +ip1 link set veth2 netns $netns2 +n1 bash -c 'echo 0 > /proc/sys/net/ipv6/conf/veth1/accept_dad' +n2 bash -c 'echo 0 > /proc/sys/net/ipv6/conf/veth2/accept_dad' +n1 bash -c 'echo 1 > /proc/sys/net/ipv4/conf/veth1/promote_secondaries' +ip1 addr add 10.0.0.1/24 dev veth1 +ip1 addr add dead::1/96 dev veth1 +ip2 addr add 10.0.0.2/24 dev veth2 +ip2 addr add dead::2/96 dev veth2 +ip1 link set veth1 up +ip2 link set veth2 up +n1 wg set wg0 peer "$pub2" endpoint 10.0.0.2:2 +n1 ping -W 1 -c 1 192.168.241.2 +ip1 addr add 10.0.0.10/24 dev veth1 +ip1 addr del 10.0.0.1/24 dev veth1 +n1 ping -W 1 -c 1 192.168.241.2 +n1 wg set wg0 peer "$pub2" endpoint [dead::2]:2 +n1 ping -W 1 -c 1 192.168.241.2 +ip1 addr add dead::10/96 dev veth1 +ip1 addr del dead::1/96 dev veth1 +n1 ping -W 1 -c 1 192.168.241.2 -- cgit v1.2.3-59-g8ed1b