mirror of
https://github.com/openwrt/openwrt.git
synced 2024-12-29 10:08:59 +00:00
149 lines
4.4 KiB
Diff
149 lines
4.4 KiB
Diff
|
From 9793cc7357e8d70fed9cb350d2d39346328cc73b 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 071/124] 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
|