Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
ip6t_MASQUERADE.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2011 Patrick McHardy <[email protected]>
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 <[email protected]>");
135 MODULE_DESCRIPTION("Xtables: automatic address SNAT");