summaryrefslogtreecommitdiffstatshomepage
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
commit6235b5aa4293e96d9eb798a0aba5fdb0f9fcca2d (patch)
treef46ea35cf01b9475ef003fea5d71ed2e04bf69bd
parentratelimiter: rewrite from scratch (diff)
downloadwireguard-monolithic-historical-6235b5aa4293e96d9eb798a0aba5fdb0f9fcca2d.tar.xz
wireguard-monolithic-historical-6235b5aa4293e96d9eb798a0aba5fdb0f9fcca2d.zip
socket: verify saddr belongs to interface
This helps "unstick" stuck source addresses, when changing routes dynamically.
-rw-r--r--src/compat/compat.h5
-rw-r--r--src/socket.c5
2 files changed, 9 insertions, 1 deletions
diff --git a/src/compat/compat.h b/src/compat/compat.h
index feb4347..eb17c8e 100644
--- a/src/compat/compat.h
+++ b/src/compat/compat.h
@@ -279,6 +279,11 @@ static inline u64 ktime_get_ns(void)
}
#endif
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0)
+#include <linux/inetdevice.h>
+#define inet_confirm_addr(a,b,c,d,e) inet_confirm_addr(b,c,d,e)
+#endif
+
/* https://lkml.org/lkml/2015/6/12/415 */
#include <linux/netdevice.h>
static inline struct net_device *netdev_pub(void *dev)
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))) {