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/netdevice.h>
15 #include <linux/ipv6.h>
16 #include <linux/netfilter.h>
17 #include <linux/netfilter_ipv6.h>
18 #include <linux/netfilter/x_tables.h>
19 #include <net/netfilter/nf_nat.h>
20 #include <net/addrconf.h>
24 masquerade_tg6(struct sk_buff
*skb
, const struct xt_action_param
*par
)
26 const struct nf_nat_range
*range
= par
->targinfo
;
27 enum ip_conntrack_info ctinfo
;
30 struct nf_nat_range newrange
;
32 ct
= nf_ct_get(skb
, &ctinfo
);
33 NF_CT_ASSERT(ct
&& (ctinfo
== IP_CT_NEW
|| ctinfo
== IP_CT_RELATED
||
34 ctinfo
== IP_CT_RELATED_REPLY
));
36 if (ipv6_dev_get_saddr(dev_net(par
->out
), par
->out
,
37 &ipv6_hdr(skb
)->daddr
, 0, &src
) < 0)
40 nfct_nat(ct
)->masq_index
= par
->out
->ifindex
;
42 newrange
.flags
= range
->flags
| NF_NAT_RANGE_MAP_IPS
;
43 newrange
.min_addr
.in6
= src
;
44 newrange
.max_addr
.in6
= src
;
45 newrange
.min_proto
= range
->min_proto
;
46 newrange
.max_proto
= range
->max_proto
;
48 return nf_nat_setup_info(ct
, &newrange
, NF_NAT_MANIP_SRC
);
51 static int masquerade_tg6_checkentry(const struct xt_tgchk_param
*par
)
53 const struct nf_nat_range
*range
= par
->targinfo
;
55 if (range
->flags
& NF_NAT_RANGE_MAP_IPS
)
60 static int device_cmp(struct nf_conn
*ct
, void *ifindex
)
62 const struct nf_conn_nat
*nat
= nfct_nat(ct
);
66 if (nf_ct_l3num(ct
) != NFPROTO_IPV6
)
68 return nat
->masq_index
== (int)(long)ifindex
;
71 static int masq_device_event(struct notifier_block
*this,
72 unsigned long event
, void *ptr
)
74 const struct net_device
*dev
= netdev_notifier_info_to_dev(ptr
);
75 struct net
*net
= dev_net(dev
);
77 if (event
== NETDEV_DOWN
)
78 nf_ct_iterate_cleanup(net
, device_cmp
,
79 (void *)(long)dev
->ifindex
);
84 static struct notifier_block masq_dev_notifier
= {
85 .notifier_call
= masq_device_event
,
88 static int masq_inet_event(struct notifier_block
*this,
89 unsigned long event
, void *ptr
)
91 struct inet6_ifaddr
*ifa
= ptr
;
93 return masq_device_event(this, event
, ifa
->idev
->dev
);
96 static struct notifier_block masq_inet_notifier
= {
97 .notifier_call
= masq_inet_event
,
100 static struct xt_target masquerade_tg6_reg __read_mostly
= {
101 .name
= "MASQUERADE",
102 .family
= NFPROTO_IPV6
,
103 .checkentry
= masquerade_tg6_checkentry
,
104 .target
= masquerade_tg6
,
105 .targetsize
= sizeof(struct nf_nat_range
),
107 .hooks
= 1 << NF_INET_POST_ROUTING
,
111 static int __init
masquerade_tg6_init(void)
115 err
= xt_register_target(&masquerade_tg6_reg
);
117 register_netdevice_notifier(&masq_dev_notifier
);
118 register_inet6addr_notifier(&masq_inet_notifier
);
123 static void __exit
masquerade_tg6_exit(void)
125 unregister_inet6addr_notifier(&masq_inet_notifier
);
126 unregister_netdevice_notifier(&masq_dev_notifier
);
127 xt_unregister_target(&masquerade_tg6_reg
);
130 module_init(masquerade_tg6_init
);
131 module_exit(masquerade_tg6_exit
);
133 MODULE_LICENSE("GPL");
134 MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
135 MODULE_DESCRIPTION("Xtables: automatic address SNAT");