diff options
author | Jason A. Donenfeld <Jason@zx2c4.com> | 2017-06-23 20:45:24 +0200 |
---|---|---|
committer | Jason A. Donenfeld <Jason@zx2c4.com> | 2017-06-26 12:35:06 +0200 |
commit | 36fe0f3a410858990c992132b4ae8ba4bc511739 (patch) | |
tree | 4be2cfee73875cbd647ea030c382eca917716e65 /src/socket.c | |
parent | 9eed02a30cf9c5ad36c94724ca3ac3b8f09cf7d2 (diff) |
socket: verify saddr belongs to interface
This helps "unstick" stuck source addresses, when changing routes
dynamically.
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
Diffstat (limited to 'src/socket.c')
-rw-r--r-- | src/socket.c | 5 |
1 files changed, 4 insertions, 1 deletions
diff --git a/src/socket.c b/src/socket.c index acf3b4a..76e4e24 100644 --- a/src/socket.c +++ b/src/socket.c @@ -10,6 +10,7 @@ #include <linux/net.h> #include <linux/if_vlan.h> #include <linux/if_ether.h> +#include <linux/inetdevice.h> #include <net/udp_tunnel.h> #include <net/ipv6.h> @@ -44,10 +45,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)) { + if (unlikely(endpoint->src4.s_addr && ((IS_ERR(rt) && PTR_ERR(rt) == -EINVAL) || (!IS_ERR(rt) && !inet_confirm_addr(sock_net(sock), __in_dev_get_rcu(rt->dst.dev), 0, fl.saddr, RT_SCOPE_HOST))))) { endpoint->src4.s_addr = fl.saddr = 0; if (cache) dst_cache_reset(cache); + if (!IS_ERR(rt)) + dst_release(&rt->dst); rt = ip_route_output_flow(sock_net(sock), &fl, sock); } if (unlikely(IS_ERR(rt))) { |