Patrick McHardy | 58a317f | 2012-08-26 19:14:12 +0200 | [diff] [blame] | 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 IPv4 NAT code. Development of IPv6 NAT |
| 9 | * funded by Astaro. |
| 10 | */ |
| 11 | |
| 12 | #include <linux/module.h> |
| 13 | #include <linux/netfilter.h> |
| 14 | #include <linux/netfilter_ipv6.h> |
| 15 | #include <linux/netfilter_ipv6/ip6_tables.h> |
| 16 | #include <linux/ipv6.h> |
| 17 | #include <net/ipv6.h> |
| 18 | |
| 19 | #include <net/netfilter/nf_nat.h> |
| 20 | #include <net/netfilter/nf_nat_core.h> |
| 21 | #include <net/netfilter/nf_nat_l3proto.h> |
| 22 | |
| 23 | static const struct xt_table nf_nat_ipv6_table = { |
| 24 | .name = "nat", |
| 25 | .valid_hooks = (1 << NF_INET_PRE_ROUTING) | |
| 26 | (1 << NF_INET_POST_ROUTING) | |
| 27 | (1 << NF_INET_LOCAL_OUT) | |
| 28 | (1 << NF_INET_LOCAL_IN), |
| 29 | .me = THIS_MODULE, |
| 30 | .af = NFPROTO_IPV6, |
| 31 | }; |
| 32 | |
Pablo Neira Ayuso | 2a5538e | 2014-08-25 12:05:27 +0200 | [diff] [blame] | 33 | static unsigned int ip6table_nat_do_chain(const struct nf_hook_ops *ops, |
| 34 | struct sk_buff *skb, |
| 35 | const struct net_device *in, |
| 36 | const struct net_device *out, |
| 37 | struct nf_conn *ct) |
Patrick McHardy | 58a317f | 2012-08-26 19:14:12 +0200 | [diff] [blame] | 38 | { |
| 39 | struct net *net = nf_ct_net(ct); |
Patrick McHardy | 58a317f | 2012-08-26 19:14:12 +0200 | [diff] [blame] | 40 | |
Pablo Neira Ayuso | 2a5538e | 2014-08-25 12:05:27 +0200 | [diff] [blame] | 41 | return ip6t_do_table(skb, ops->hooknum, in, out, net->ipv6.ip6table_nat); |
Patrick McHardy | 58a317f | 2012-08-26 19:14:12 +0200 | [diff] [blame] | 42 | } |
| 43 | |
Pablo Neira Ayuso | 2a5538e | 2014-08-25 12:05:27 +0200 | [diff] [blame] | 44 | static unsigned int ip6table_nat_fn(const struct nf_hook_ops *ops, |
| 45 | struct sk_buff *skb, |
David S. Miller | 238e54c | 2015-04-03 20:32:56 -0400 | [diff] [blame^] | 46 | const struct nf_hook_state *state) |
Patrick McHardy | 58a317f | 2012-08-26 19:14:12 +0200 | [diff] [blame] | 47 | { |
David S. Miller | 238e54c | 2015-04-03 20:32:56 -0400 | [diff] [blame^] | 48 | return nf_nat_ipv6_fn(ops, skb, state->in, state->out, |
| 49 | ip6table_nat_do_chain); |
Patrick McHardy | 58a317f | 2012-08-26 19:14:12 +0200 | [diff] [blame] | 50 | } |
| 51 | |
Pablo Neira Ayuso | 2a5538e | 2014-08-25 12:05:27 +0200 | [diff] [blame] | 52 | static unsigned int ip6table_nat_in(const struct nf_hook_ops *ops, |
| 53 | struct sk_buff *skb, |
David S. Miller | 238e54c | 2015-04-03 20:32:56 -0400 | [diff] [blame^] | 54 | const struct nf_hook_state *state) |
Patrick McHardy | 58a317f | 2012-08-26 19:14:12 +0200 | [diff] [blame] | 55 | { |
David S. Miller | 238e54c | 2015-04-03 20:32:56 -0400 | [diff] [blame^] | 56 | return nf_nat_ipv6_in(ops, skb, state->in, state->out, |
| 57 | ip6table_nat_do_chain); |
Patrick McHardy | 58a317f | 2012-08-26 19:14:12 +0200 | [diff] [blame] | 58 | } |
| 59 | |
Pablo Neira Ayuso | 2a5538e | 2014-08-25 12:05:27 +0200 | [diff] [blame] | 60 | static unsigned int ip6table_nat_out(const struct nf_hook_ops *ops, |
| 61 | struct sk_buff *skb, |
David S. Miller | 238e54c | 2015-04-03 20:32:56 -0400 | [diff] [blame^] | 62 | const struct nf_hook_state *state) |
Patrick McHardy | 58a317f | 2012-08-26 19:14:12 +0200 | [diff] [blame] | 63 | { |
David S. Miller | 238e54c | 2015-04-03 20:32:56 -0400 | [diff] [blame^] | 64 | return nf_nat_ipv6_out(ops, skb, state->in, state->out, |
| 65 | ip6table_nat_do_chain); |
Patrick McHardy | 58a317f | 2012-08-26 19:14:12 +0200 | [diff] [blame] | 66 | } |
| 67 | |
Pablo Neira Ayuso | 2a5538e | 2014-08-25 12:05:27 +0200 | [diff] [blame] | 68 | static unsigned int ip6table_nat_local_fn(const struct nf_hook_ops *ops, |
| 69 | struct sk_buff *skb, |
David S. Miller | 238e54c | 2015-04-03 20:32:56 -0400 | [diff] [blame^] | 70 | const struct nf_hook_state *state) |
Patrick McHardy | 58a317f | 2012-08-26 19:14:12 +0200 | [diff] [blame] | 71 | { |
David S. Miller | 238e54c | 2015-04-03 20:32:56 -0400 | [diff] [blame^] | 72 | return nf_nat_ipv6_local_fn(ops, skb, state->in, state->out, |
| 73 | ip6table_nat_do_chain); |
Patrick McHardy | 58a317f | 2012-08-26 19:14:12 +0200 | [diff] [blame] | 74 | } |
| 75 | |
| 76 | static struct nf_hook_ops nf_nat_ipv6_ops[] __read_mostly = { |
| 77 | /* Before packet filtering, change destination */ |
| 78 | { |
Pablo Neira Ayuso | 2a5538e | 2014-08-25 12:05:27 +0200 | [diff] [blame] | 79 | .hook = ip6table_nat_in, |
Patrick McHardy | 58a317f | 2012-08-26 19:14:12 +0200 | [diff] [blame] | 80 | .owner = THIS_MODULE, |
| 81 | .pf = NFPROTO_IPV6, |
| 82 | .hooknum = NF_INET_PRE_ROUTING, |
| 83 | .priority = NF_IP6_PRI_NAT_DST, |
| 84 | }, |
| 85 | /* After packet filtering, change source */ |
| 86 | { |
Pablo Neira Ayuso | 2a5538e | 2014-08-25 12:05:27 +0200 | [diff] [blame] | 87 | .hook = ip6table_nat_out, |
Patrick McHardy | 58a317f | 2012-08-26 19:14:12 +0200 | [diff] [blame] | 88 | .owner = THIS_MODULE, |
| 89 | .pf = NFPROTO_IPV6, |
| 90 | .hooknum = NF_INET_POST_ROUTING, |
| 91 | .priority = NF_IP6_PRI_NAT_SRC, |
| 92 | }, |
| 93 | /* Before packet filtering, change destination */ |
| 94 | { |
Pablo Neira Ayuso | 2a5538e | 2014-08-25 12:05:27 +0200 | [diff] [blame] | 95 | .hook = ip6table_nat_local_fn, |
Patrick McHardy | 58a317f | 2012-08-26 19:14:12 +0200 | [diff] [blame] | 96 | .owner = THIS_MODULE, |
| 97 | .pf = NFPROTO_IPV6, |
| 98 | .hooknum = NF_INET_LOCAL_OUT, |
| 99 | .priority = NF_IP6_PRI_NAT_DST, |
| 100 | }, |
| 101 | /* After packet filtering, change source */ |
| 102 | { |
Pablo Neira Ayuso | 2a5538e | 2014-08-25 12:05:27 +0200 | [diff] [blame] | 103 | .hook = ip6table_nat_fn, |
Patrick McHardy | 58a317f | 2012-08-26 19:14:12 +0200 | [diff] [blame] | 104 | .owner = THIS_MODULE, |
| 105 | .pf = NFPROTO_IPV6, |
| 106 | .hooknum = NF_INET_LOCAL_IN, |
| 107 | .priority = NF_IP6_PRI_NAT_SRC, |
| 108 | }, |
| 109 | }; |
| 110 | |
| 111 | static int __net_init ip6table_nat_net_init(struct net *net) |
| 112 | { |
| 113 | struct ip6t_replace *repl; |
| 114 | |
| 115 | repl = ip6t_alloc_initial_table(&nf_nat_ipv6_table); |
| 116 | if (repl == NULL) |
| 117 | return -ENOMEM; |
| 118 | net->ipv6.ip6table_nat = ip6t_register_table(net, &nf_nat_ipv6_table, repl); |
| 119 | kfree(repl); |
Rusty Russell | 8c6ffba | 2013-07-15 11:20:32 +0930 | [diff] [blame] | 120 | return PTR_ERR_OR_ZERO(net->ipv6.ip6table_nat); |
Patrick McHardy | 58a317f | 2012-08-26 19:14:12 +0200 | [diff] [blame] | 121 | } |
| 122 | |
| 123 | static void __net_exit ip6table_nat_net_exit(struct net *net) |
| 124 | { |
| 125 | ip6t_unregister_table(net, net->ipv6.ip6table_nat); |
| 126 | } |
| 127 | |
| 128 | static struct pernet_operations ip6table_nat_net_ops = { |
| 129 | .init = ip6table_nat_net_init, |
| 130 | .exit = ip6table_nat_net_exit, |
| 131 | }; |
| 132 | |
| 133 | static int __init ip6table_nat_init(void) |
| 134 | { |
| 135 | int err; |
| 136 | |
| 137 | err = register_pernet_subsys(&ip6table_nat_net_ops); |
| 138 | if (err < 0) |
| 139 | goto err1; |
| 140 | |
| 141 | err = nf_register_hooks(nf_nat_ipv6_ops, ARRAY_SIZE(nf_nat_ipv6_ops)); |
| 142 | if (err < 0) |
| 143 | goto err2; |
| 144 | return 0; |
| 145 | |
| 146 | err2: |
| 147 | unregister_pernet_subsys(&ip6table_nat_net_ops); |
| 148 | err1: |
| 149 | return err; |
| 150 | } |
| 151 | |
| 152 | static void __exit ip6table_nat_exit(void) |
| 153 | { |
| 154 | nf_unregister_hooks(nf_nat_ipv6_ops, ARRAY_SIZE(nf_nat_ipv6_ops)); |
| 155 | unregister_pernet_subsys(&ip6table_nat_net_ops); |
| 156 | } |
| 157 | |
| 158 | module_init(ip6table_nat_init); |
| 159 | module_exit(ip6table_nat_exit); |
| 160 | |
| 161 | MODULE_LICENSE("GPL"); |