]> Pileus Git - ~andy/linux/blob - net/ipv6/netfilter/ip6t_MASQUERADE.c
Merge branch 'release' of git://git.kernel.org/pub/scm/linux/kernel/git/lenb/linux
[~andy/linux] / net / ipv6 / netfilter / ip6t_MASQUERADE.c
1 /*
2  * Copyright (c) 2011 Patrick McHardy <kaber@trash.net>
3  *
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.
7  *
8  * Based on Rusty Russell's IPv6 MASQUERADE target. Development of IPv6
9  * NAT funded by Astaro.
10  */
11
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>
21 #include <net/ipv6.h>
22
23 static unsigned int
24 masquerade_tg6(struct sk_buff *skb, const struct xt_action_param *par)
25 {
26         const struct nf_nat_range *range = par->targinfo;
27         enum ip_conntrack_info ctinfo;
28         struct in6_addr src;
29         struct nf_conn *ct;
30         struct nf_nat_range newrange;
31
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));
35
36         if (ipv6_dev_get_saddr(dev_net(par->out), par->out,
37                                &ipv6_hdr(skb)->daddr, 0, &src) < 0)
38                 return NF_DROP;
39
40         nfct_nat(ct)->masq_index = par->out->ifindex;
41
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;
47
48         return nf_nat_setup_info(ct, &newrange, NF_NAT_MANIP_SRC);
49 }
50
51 static int masquerade_tg6_checkentry(const struct xt_tgchk_param *par)
52 {
53         const struct nf_nat_range *range = par->targinfo;
54
55         if (range->flags & NF_NAT_RANGE_MAP_IPS)
56                 return -EINVAL;
57         return 0;
58 }
59
60 static int device_cmp(struct nf_conn *ct, void *ifindex)
61 {
62         const struct nf_conn_nat *nat = nfct_nat(ct);
63
64         if (!nat)
65                 return 0;
66         if (nf_ct_l3num(ct) != NFPROTO_IPV6)
67                 return 0;
68         return nat->masq_index == (int)(long)ifindex;
69 }
70
71 static int masq_device_event(struct notifier_block *this,
72                              unsigned long event, void *ptr)
73 {
74         const struct net_device *dev = ptr;
75         struct net *net = dev_net(dev);
76
77         if (event == NETDEV_DOWN)
78                 nf_ct_iterate_cleanup(net, device_cmp,
79                                       (void *)(long)dev->ifindex);
80
81         return NOTIFY_DONE;
82 }
83
84 static struct notifier_block masq_dev_notifier = {
85         .notifier_call  = masq_device_event,
86 };
87
88 static int masq_inet_event(struct notifier_block *this,
89                            unsigned long event, void *ptr)
90 {
91         struct inet6_ifaddr *ifa = ptr;
92
93         return masq_device_event(this, event, ifa->idev->dev);
94 }
95
96 static struct notifier_block masq_inet_notifier = {
97         .notifier_call  = masq_inet_event,
98 };
99
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),
106         .table          = "nat",
107         .hooks          = 1 << NF_INET_POST_ROUTING,
108         .me             = THIS_MODULE,
109 };
110
111 static int __init masquerade_tg6_init(void)
112 {
113         int err;
114
115         err = xt_register_target(&masquerade_tg6_reg);
116         if (err == 0) {
117                 register_netdevice_notifier(&masq_dev_notifier);
118                 register_inet6addr_notifier(&masq_inet_notifier);
119         }
120
121         return err;
122 }
123 static void __exit masquerade_tg6_exit(void)
124 {
125         unregister_inet6addr_notifier(&masq_inet_notifier);
126         unregister_netdevice_notifier(&masq_dev_notifier);
127         xt_unregister_target(&masquerade_tg6_reg);
128 }
129
130 module_init(masquerade_tg6_init);
131 module_exit(masquerade_tg6_exit);
132
133 MODULE_LICENSE("GPL");
134 MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
135 MODULE_DESCRIPTION("Xtables: automatic address SNAT");