2 * Copyright (c) 2011 Patrick McHardy <kaber@trash.net>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
8 * Based on Rusty Russell's IPv6 MASQUERADE target. Development of IPv6
9 * NAT funded by Astaro.
12 #include <linux/kernel.h>
13 #include <linux/module.h>
14 #include <linux/atomic.h>
15 #include <linux/netdevice.h>
16 #include <linux/ipv6.h>
17 #include <linux/netfilter.h>
18 #include <linux/netfilter_ipv6.h>
19 #include <net/netfilter/nf_nat.h>
20 #include <net/addrconf.h>
22 #include <net/netfilter/ipv6/nf_nat_masquerade.h>
25 nf_nat_masquerade_ipv6(struct sk_buff
*skb
, const struct nf_nat_range
*range
,
26 const struct net_device
*out
)
28 enum ip_conntrack_info ctinfo
;
31 struct nf_nat_range newrange
;
33 ct
= nf_ct_get(skb
, &ctinfo
);
34 NF_CT_ASSERT(ct
&& (ctinfo
== IP_CT_NEW
|| ctinfo
== IP_CT_RELATED
||
35 ctinfo
== IP_CT_RELATED_REPLY
));
37 if (ipv6_dev_get_saddr(nf_ct_net(ct
), out
,
38 &ipv6_hdr(skb
)->daddr
, 0, &src
) < 0)
41 nfct_nat(ct
)->masq_index
= out
->ifindex
;
43 newrange
.flags
= range
->flags
| NF_NAT_RANGE_MAP_IPS
;
44 newrange
.min_addr
.in6
= src
;
45 newrange
.max_addr
.in6
= src
;
46 newrange
.min_proto
= range
->min_proto
;
47 newrange
.max_proto
= range
->max_proto
;
49 return nf_nat_setup_info(ct
, &newrange
, NF_NAT_MANIP_SRC
);
51 EXPORT_SYMBOL_GPL(nf_nat_masquerade_ipv6
);
53 static int device_cmp(struct nf_conn
*ct
, void *ifindex
)
55 const struct nf_conn_nat
*nat
= nfct_nat(ct
);
59 if (nf_ct_l3num(ct
) != NFPROTO_IPV6
)
61 return nat
->masq_index
== (int)(long)ifindex
;
64 static int masq_device_event(struct notifier_block
*this,
65 unsigned long event
, void *ptr
)
67 const struct net_device
*dev
= netdev_notifier_info_to_dev(ptr
);
68 struct net
*net
= dev_net(dev
);
70 if (event
== NETDEV_DOWN
)
71 nf_ct_iterate_cleanup(net
, device_cmp
,
72 (void *)(long)dev
->ifindex
, 0, 0);
77 static struct notifier_block masq_dev_notifier
= {
78 .notifier_call
= masq_device_event
,
81 static int masq_inet_event(struct notifier_block
*this,
82 unsigned long event
, void *ptr
)
84 struct inet6_ifaddr
*ifa
= ptr
;
85 struct netdev_notifier_info info
;
87 netdev_notifier_info_init(&info
, ifa
->idev
->dev
);
88 return masq_device_event(this, event
, &info
);
91 static struct notifier_block masq_inet_notifier
= {
92 .notifier_call
= masq_inet_event
,
95 static atomic_t masquerade_notifier_refcount
= ATOMIC_INIT(0);
97 void nf_nat_masquerade_ipv6_register_notifier(void)
99 /* check if the notifier is already set */
100 if (atomic_inc_return(&masquerade_notifier_refcount
) > 1)
103 register_netdevice_notifier(&masq_dev_notifier
);
104 register_inet6addr_notifier(&masq_inet_notifier
);
106 EXPORT_SYMBOL_GPL(nf_nat_masquerade_ipv6_register_notifier
);
108 void nf_nat_masquerade_ipv6_unregister_notifier(void)
110 /* check if the notifier still has clients */
111 if (atomic_dec_return(&masquerade_notifier_refcount
) > 0)
114 unregister_inet6addr_notifier(&masq_inet_notifier
);
115 unregister_netdevice_notifier(&masq_dev_notifier
);
117 EXPORT_SYMBOL_GPL(nf_nat_masquerade_ipv6_unregister_notifier
);
119 MODULE_LICENSE("GPL");
120 MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");