Skip to content

Commit 0b41713

Browse files
zx2c4davem330
authored andcommitted
icmp: introduce helper for nat'd source address in network device context
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 <[email protected]> Cc: Florian Westphal <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 07134cf commit 0b41713

File tree

4 files changed

+79
-0
lines changed

4 files changed

+79
-0
lines changed

include/linux/icmpv6.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,12 @@ static inline void icmpv6_send(struct sk_buff *skb,
3131
}
3232
#endif
3333

34+
#if IS_ENABLED(CONFIG_NF_NAT)
35+
void icmpv6_ndo_send(struct sk_buff *skb_in, u8 type, u8 code, __u32 info);
36+
#else
37+
#define icmpv6_ndo_send icmpv6_send
38+
#endif
39+
3440
extern int icmpv6_init(void);
3541
extern int icmpv6_err_convert(u8 type, u8 code,
3642
int *err);

include/net/icmp.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,12 @@ static inline void icmp_send(struct sk_buff *skb_in, int type, int code, __be32
4343
__icmp_send(skb_in, type, code, info, &IPCB(skb_in)->opt);
4444
}
4545

46+
#if IS_ENABLED(CONFIG_NF_NAT)
47+
void icmp_ndo_send(struct sk_buff *skb_in, int type, int code, __be32 info);
48+
#else
49+
#define icmp_ndo_send icmp_send
50+
#endif
51+
4652
int icmp_rcv(struct sk_buff *skb);
4753
int icmp_err(struct sk_buff *skb, u32 info);
4854
int icmp_init(void);

net/ipv4/icmp.c

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -748,6 +748,39 @@ out:;
748748
}
749749
EXPORT_SYMBOL(__icmp_send);
750750

751+
#if IS_ENABLED(CONFIG_NF_NAT)
752+
#include <net/netfilter/nf_conntrack.h>
753+
void icmp_ndo_send(struct sk_buff *skb_in, int type, int code, __be32 info)
754+
{
755+
struct sk_buff *cloned_skb = NULL;
756+
enum ip_conntrack_info ctinfo;
757+
struct nf_conn *ct;
758+
__be32 orig_ip;
759+
760+
ct = nf_ct_get(skb_in, &ctinfo);
761+
if (!ct || !(ct->status & IPS_SRC_NAT)) {
762+
icmp_send(skb_in, type, code, info);
763+
return;
764+
}
765+
766+
if (skb_shared(skb_in))
767+
skb_in = cloned_skb = skb_clone(skb_in, GFP_ATOMIC);
768+
769+
if (unlikely(!skb_in || skb_network_header(skb_in) < skb_in->head ||
770+
(skb_network_header(skb_in) + sizeof(struct iphdr)) >
771+
skb_tail_pointer(skb_in) || skb_ensure_writable(skb_in,
772+
skb_network_offset(skb_in) + sizeof(struct iphdr))))
773+
goto out;
774+
775+
orig_ip = ip_hdr(skb_in)->saddr;
776+
ip_hdr(skb_in)->saddr = ct->tuplehash[0].tuple.src.u3.ip;
777+
icmp_send(skb_in, type, code, info);
778+
ip_hdr(skb_in)->saddr = orig_ip;
779+
out:
780+
consume_skb(cloned_skb);
781+
}
782+
EXPORT_SYMBOL(icmp_ndo_send);
783+
#endif
751784

752785
static void icmp_socket_deliver(struct sk_buff *skb, u32 info)
753786
{

net/ipv6/ip6_icmp.c

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,4 +45,38 @@ void icmpv6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info)
4545
rcu_read_unlock();
4646
}
4747
EXPORT_SYMBOL(icmpv6_send);
48+
49+
#if IS_ENABLED(CONFIG_NF_NAT)
50+
#include <net/netfilter/nf_conntrack.h>
51+
void icmpv6_ndo_send(struct sk_buff *skb_in, u8 type, u8 code, __u32 info)
52+
{
53+
struct sk_buff *cloned_skb = NULL;
54+
enum ip_conntrack_info ctinfo;
55+
struct in6_addr orig_ip;
56+
struct nf_conn *ct;
57+
58+
ct = nf_ct_get(skb_in, &ctinfo);
59+
if (!ct || !(ct->status & IPS_SRC_NAT)) {
60+
icmpv6_send(skb_in, type, code, info);
61+
return;
62+
}
63+
64+
if (skb_shared(skb_in))
65+
skb_in = cloned_skb = skb_clone(skb_in, GFP_ATOMIC);
66+
67+
if (unlikely(!skb_in || skb_network_header(skb_in) < skb_in->head ||
68+
(skb_network_header(skb_in) + sizeof(struct ipv6hdr)) >
69+
skb_tail_pointer(skb_in) || skb_ensure_writable(skb_in,
70+
skb_network_offset(skb_in) + sizeof(struct ipv6hdr))))
71+
goto out;
72+
73+
orig_ip = ipv6_hdr(skb_in)->saddr;
74+
ipv6_hdr(skb_in)->saddr = ct->tuplehash[0].tuple.src.u3.in6;
75+
icmpv6_send(skb_in, type, code, info);
76+
ipv6_hdr(skb_in)->saddr = orig_ip;
77+
out:
78+
consume_skb(cloned_skb);
79+
}
80+
EXPORT_SYMBOL(icmpv6_ndo_send);
81+
#endif
4882
#endif

0 commit comments

Comments
 (0)