summaryrefslogtreecommitdiffhomepage
path: root/src/socket.c
diff options
context:
space:
mode:
authorJason A. Donenfeld <Jason@zx2c4.com>2017-06-23 20:45:24 +0200
committerJason A. Donenfeld <Jason@zx2c4.com>2017-06-26 12:35:06 +0200
commit36fe0f3a410858990c992132b4ae8ba4bc511739 (patch)
tree4be2cfee73875cbd647ea030c382eca917716e65 /src/socket.c
parent9eed02a30cf9c5ad36c94724ca3ac3b8f09cf7d2 (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.c5
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))) {