1 From 9793cc7357e8d70fed9cb350d2d39346328cc73b Mon Sep 17 00:00:00 2001
2 From: "Jason A. Donenfeld" <Jason@zx2c4.com>
3 Date: Tue, 11 Feb 2020 20:47:05 +0100
4 Subject: [PATCH 071/124] icmp: introduce helper for nat'd source address in
7 commit 0b41713b606694257b90d61ba7e2712d8457648b upstream.
9 This introduces a helper function to be called only by network drivers
10 that wraps calls to icmp[v6]_send in a conntrack transformation, in case
11 NAT has been used. We don't want to pollute the non-driver path, though,
12 so we introduce this as a helper to be called by places that actually
13 make use of this, as suggested by Florian.
15 Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
16 Cc: Florian Westphal <fw@strlen.de>
17 Signed-off-by: David S. Miller <davem@davemloft.net>
18 Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
20 include/linux/icmpv6.h | 10 ++++++++++
21 include/net/icmp.h | 6 ++++++
22 net/ipv4/icmp.c | 33 +++++++++++++++++++++++++++++++++
23 net/ipv6/ip6_icmp.c | 34 ++++++++++++++++++++++++++++++++++
24 4 files changed, 83 insertions(+)
26 --- a/include/linux/icmpv6.h
27 +++ b/include/linux/icmpv6.h
28 @@ -22,12 +22,22 @@ extern int inet6_unregister_icmp_sender(
29 int ip6_err_gen_icmpv6_unreach(struct sk_buff *skb, int nhs, int type,
30 unsigned int data_len);
32 +#if IS_ENABLED(CONFIG_NF_NAT)
33 +void icmpv6_ndo_send(struct sk_buff *skb_in, u8 type, u8 code, __u32 info);
35 +#define icmpv6_ndo_send icmpv6_send
40 static inline void icmpv6_send(struct sk_buff *skb,
41 u8 type, u8 code, __u32 info)
45 +static inline void icmpv6_ndo_send(struct sk_buff *skb,
46 + u8 type, u8 code, __u32 info)
51 --- a/include/net/icmp.h
52 +++ b/include/net/icmp.h
53 @@ -43,6 +43,12 @@ static inline void icmp_send(struct sk_b
54 __icmp_send(skb_in, type, code, info, &IPCB(skb_in)->opt);
57 +#if IS_ENABLED(CONFIG_NF_NAT)
58 +void icmp_ndo_send(struct sk_buff *skb_in, int type, int code, __be32 info);
60 +#define icmp_ndo_send icmp_send
63 int icmp_rcv(struct sk_buff *skb);
64 int icmp_err(struct sk_buff *skb, u32 info);
68 @@ -750,6 +750,39 @@ out:;
70 EXPORT_SYMBOL(__icmp_send);
72 +#if IS_ENABLED(CONFIG_NF_NAT)
73 +#include <net/netfilter/nf_conntrack.h>
74 +void icmp_ndo_send(struct sk_buff *skb_in, int type, int code, __be32 info)
76 + struct sk_buff *cloned_skb = NULL;
77 + enum ip_conntrack_info ctinfo;
81 + ct = nf_ct_get(skb_in, &ctinfo);
82 + if (!ct || !(ct->status & IPS_SRC_NAT)) {
83 + icmp_send(skb_in, type, code, info);
87 + if (skb_shared(skb_in))
88 + skb_in = cloned_skb = skb_clone(skb_in, GFP_ATOMIC);
90 + if (unlikely(!skb_in || skb_network_header(skb_in) < skb_in->head ||
91 + (skb_network_header(skb_in) + sizeof(struct iphdr)) >
92 + skb_tail_pointer(skb_in) || skb_ensure_writable(skb_in,
93 + skb_network_offset(skb_in) + sizeof(struct iphdr))))
96 + orig_ip = ip_hdr(skb_in)->saddr;
97 + ip_hdr(skb_in)->saddr = ct->tuplehash[0].tuple.src.u3.ip;
98 + icmp_send(skb_in, type, code, info);
99 + ip_hdr(skb_in)->saddr = orig_ip;
101 + consume_skb(cloned_skb);
103 +EXPORT_SYMBOL(icmp_ndo_send);
106 static void icmp_socket_deliver(struct sk_buff *skb, u32 info)
108 --- a/net/ipv6/ip6_icmp.c
109 +++ b/net/ipv6/ip6_icmp.c
110 @@ -45,4 +45,38 @@ out:
113 EXPORT_SYMBOL(icmpv6_send);
115 +#if IS_ENABLED(CONFIG_NF_NAT)
116 +#include <net/netfilter/nf_conntrack.h>
117 +void icmpv6_ndo_send(struct sk_buff *skb_in, u8 type, u8 code, __u32 info)
119 + struct sk_buff *cloned_skb = NULL;
120 + enum ip_conntrack_info ctinfo;
121 + struct in6_addr orig_ip;
122 + struct nf_conn *ct;
124 + ct = nf_ct_get(skb_in, &ctinfo);
125 + if (!ct || !(ct->status & IPS_SRC_NAT)) {
126 + icmpv6_send(skb_in, type, code, info);
130 + if (skb_shared(skb_in))
131 + skb_in = cloned_skb = skb_clone(skb_in, GFP_ATOMIC);
133 + if (unlikely(!skb_in || skb_network_header(skb_in) < skb_in->head ||
134 + (skb_network_header(skb_in) + sizeof(struct ipv6hdr)) >
135 + skb_tail_pointer(skb_in) || skb_ensure_writable(skb_in,
136 + skb_network_offset(skb_in) + sizeof(struct ipv6hdr))))
139 + orig_ip = ipv6_hdr(skb_in)->saddr;
140 + ipv6_hdr(skb_in)->saddr = ct->tuplehash[0].tuple.src.u3.in6;
141 + icmpv6_send(skb_in, type, code, info);
142 + ipv6_hdr(skb_in)->saddr = orig_ip;
144 + consume_skb(cloned_skb);
146 +EXPORT_SYMBOL(icmpv6_ndo_send);