summaryrefslogtreecommitdiffstats
path: root/target/linux/generic/backport-5.4/080-wireguard-0072-icmp-introduce-helper-for-nat-d-source-address-in-ne.patch
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/generic/backport-5.4/080-wireguard-0072-icmp-introduce-helper-for-nat-d-source-address-in-ne.patch')
-rw-r--r--target/linux/generic/backport-5.4/080-wireguard-0072-icmp-introduce-helper-for-nat-d-source-address-in-ne.patch148
1 files changed, 148 insertions, 0 deletions
diff --git a/target/linux/generic/backport-5.4/080-wireguard-0072-icmp-introduce-helper-for-nat-d-source-address-in-ne.patch b/target/linux/generic/backport-5.4/080-wireguard-0072-icmp-introduce-helper-for-nat-d-source-address-in-ne.patch
new file mode 100644
index 0000000000..8b53cc6226
--- /dev/null
+++ b/target/linux/generic/backport-5.4/080-wireguard-0072-icmp-introduce-helper-for-nat-d-source-address-in-ne.patch
@@ -0,0 +1,148 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: "Jason A. Donenfeld" <Jason@zx2c4.com>
+Date: Tue, 11 Feb 2020 20:47:05 +0100
+Subject: [PATCH] icmp: introduce helper for nat'd source address in network
+ device context
+
+commit 0b41713b606694257b90d61ba7e2712d8457648b upstream.
+
+This introduces a helper function to be called only by network drivers
+that wraps calls to icmp[v6]_send in a conntrack transformation, in case
+NAT has been used. We don't want to pollute the non-driver path, though,
+so we introduce this as a helper to be called by places that actually
+make use of this, as suggested by Florian.
+
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+Cc: Florian Westphal <fw@strlen.de>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
+---
+ include/linux/icmpv6.h | 10 ++++++++++
+ include/net/icmp.h | 6 ++++++
+ net/ipv4/icmp.c | 33 +++++++++++++++++++++++++++++++++
+ net/ipv6/ip6_icmp.c | 34 ++++++++++++++++++++++++++++++++++
+ 4 files changed, 83 insertions(+)
+
+--- a/include/linux/icmpv6.h
++++ b/include/linux/icmpv6.h
+@@ -22,12 +22,22 @@ extern int inet6_unregister_icmp_sender(
+ int ip6_err_gen_icmpv6_unreach(struct sk_buff *skb, int nhs, int type,
+ unsigned int data_len);
+
++#if IS_ENABLED(CONFIG_NF_NAT)
++void icmpv6_ndo_send(struct sk_buff *skb_in, u8 type, u8 code, __u32 info);
++#else
++#define icmpv6_ndo_send icmpv6_send
++#endif
++
+ #else
+
+ static inline void icmpv6_send(struct sk_buff *skb,
+ u8 type, u8 code, __u32 info)
+ {
++}
+
++static inline void icmpv6_ndo_send(struct sk_buff *skb,
++ u8 type, u8 code, __u32 info)
++{
+ }
+ #endif
+
+--- a/include/net/icmp.h
++++ b/include/net/icmp.h
+@@ -43,6 +43,12 @@ static inline void icmp_send(struct sk_b
+ __icmp_send(skb_in, type, code, info, &IPCB(skb_in)->opt);
+ }
+
++#if IS_ENABLED(CONFIG_NF_NAT)
++void icmp_ndo_send(struct sk_buff *skb_in, int type, int code, __be32 info);
++#else
++#define icmp_ndo_send icmp_send
++#endif
++
+ int icmp_rcv(struct sk_buff *skb);
+ int icmp_err(struct sk_buff *skb, u32 info);
+ int icmp_init(void);
+--- a/net/ipv4/icmp.c
++++ b/net/ipv4/icmp.c
+@@ -750,6 +750,39 @@ out:;
+ }
+ EXPORT_SYMBOL(__icmp_send);
+
++#if IS_ENABLED(CONFIG_NF_NAT)
++#include <net/netfilter/nf_conntrack.h>
++void icmp_ndo_send(struct sk_buff *skb_in, int type, int code, __be32 info)
++{
++ struct sk_buff *cloned_skb = NULL;
++ enum ip_conntrack_info ctinfo;
++ struct nf_conn *ct;
++ __be32 orig_ip;
++
++ ct = nf_ct_get(skb_in, &ctinfo);
++ if (!ct || !(ct->status & IPS_SRC_NAT)) {
++ icmp_send(skb_in, type, code, info);
++ return;
++ }
++
++ if (skb_shared(skb_in))
++ skb_in = cloned_skb = skb_clone(skb_in, GFP_ATOMIC);
++
++ if (unlikely(!skb_in || skb_network_header(skb_in) < skb_in->head ||
++ (skb_network_header(skb_in) + sizeof(struct iphdr)) >
++ skb_tail_pointer(skb_in) || skb_ensure_writable(skb_in,
++ skb_network_offset(skb_in) + sizeof(struct iphdr))))
++ goto out;
++
++ orig_ip = ip_hdr(skb_in)->saddr;
++ ip_hdr(skb_in)->saddr = ct->tuplehash[0].tuple.src.u3.ip;
++ icmp_send(skb_in, type, code, info);
++ ip_hdr(skb_in)->saddr = orig_ip;
++out:
++ consume_skb(cloned_skb);
++}
++EXPORT_SYMBOL(icmp_ndo_send);
++#endif
+
+ static void icmp_socket_deliver(struct sk_buff *skb, u32 info)
+ {
+--- a/net/ipv6/ip6_icmp.c
++++ b/net/ipv6/ip6_icmp.c
+@@ -45,4 +45,38 @@ out:
+ rcu_read_unlock();
+ }
+ EXPORT_SYMBOL(icmpv6_send);
++
++#if IS_ENABLED(CONFIG_NF_NAT)
++#include <net/netfilter/nf_conntrack.h>
++void icmpv6_ndo_send(struct sk_buff *skb_in, u8 type, u8 code, __u32 info)
++{
++ struct sk_buff *cloned_skb = NULL;
++ enum ip_conntrack_info ctinfo;
++ struct in6_addr orig_ip;
++ struct nf_conn *ct;
++
++ ct = nf_ct_get(skb_in, &ctinfo);
++ if (!ct || !(ct->status & IPS_SRC_NAT)) {
++ icmpv6_send(skb_in, type, code, info);
++ return;
++ }
++
++ if (skb_shared(skb_in))
++ skb_in = cloned_skb = skb_clone(skb_in, GFP_ATOMIC);
++
++ if (unlikely(!skb_in || skb_network_header(skb_in) < skb_in->head ||
++ (skb_network_header(skb_in) + sizeof(struct ipv6hdr)) >
++ skb_tail_pointer(skb_in) || skb_ensure_writable(skb_in,
++ skb_network_offset(skb_in) + sizeof(struct ipv6hdr))))
++ goto out;
++
++ orig_ip = ipv6_hdr(skb_in)->saddr;
++ ipv6_hdr(skb_in)->saddr = ct->tuplehash[0].tuple.src.u3.in6;
++ icmpv6_send(skb_in, type, code, info);
++ ipv6_hdr(skb_in)->saddr = orig_ip;
++out:
++ consume_skb(cloned_skb);
++}
++EXPORT_SYMBOL(icmpv6_ndo_send);
++#endif
+ #endif