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 23static 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 33static unsigned int ip6table_nat_do_chain(const struct nf_hook_ops *ops, 34 struct sk_buff *skb, 35 const struct nf_hook_state *state, 36 struct nf_conn *ct) 37{ 38 struct net *net = nf_ct_net(ct); 39 40 return ip6t_do_table(skb, ops->hooknum, state, net->ipv6.ip6table_nat); 41} 42 43static unsigned int ip6table_nat_fn(const struct nf_hook_ops *ops, 44 struct sk_buff *skb, 45 const struct nf_hook_state *state) 46{ 47 return nf_nat_ipv6_fn(ops, skb, state, ip6table_nat_do_chain); 48} 49 50static unsigned int ip6table_nat_in(const struct nf_hook_ops *ops, 51 struct sk_buff *skb, 52 const struct nf_hook_state *state) 53{ 54 return nf_nat_ipv6_in(ops, skb, state, ip6table_nat_do_chain); 55} 56 57static unsigned int ip6table_nat_out(const struct nf_hook_ops *ops, 58 struct sk_buff *skb, 59 const struct nf_hook_state *state) 60{ 61 return nf_nat_ipv6_out(ops, skb, state, ip6table_nat_do_chain); 62} 63 64static unsigned int ip6table_nat_local_fn(const struct nf_hook_ops *ops, 65 struct sk_buff *skb, 66 const struct nf_hook_state *state) 67{ 68 return nf_nat_ipv6_local_fn(ops, skb, state, ip6table_nat_do_chain); 69} 70 71static struct nf_hook_ops nf_nat_ipv6_ops[] __read_mostly = { 72 /* Before packet filtering, change destination */ 73 { 74 .hook = ip6table_nat_in, 75 .owner = THIS_MODULE, 76 .pf = NFPROTO_IPV6, 77 .hooknum = NF_INET_PRE_ROUTING, 78 .priority = NF_IP6_PRI_NAT_DST, 79 }, 80 /* After packet filtering, change source */ 81 { 82 .hook = ip6table_nat_out, 83 .owner = THIS_MODULE, 84 .pf = NFPROTO_IPV6, 85 .hooknum = NF_INET_POST_ROUTING, 86 .priority = NF_IP6_PRI_NAT_SRC, 87 }, 88 /* Before packet filtering, change destination */ 89 { 90 .hook = ip6table_nat_local_fn, 91 .owner = THIS_MODULE, 92 .pf = NFPROTO_IPV6, 93 .hooknum = NF_INET_LOCAL_OUT, 94 .priority = NF_IP6_PRI_NAT_DST, 95 }, 96 /* After packet filtering, change source */ 97 { 98 .hook = ip6table_nat_fn, 99 .owner = THIS_MODULE, 100 .pf = NFPROTO_IPV6, 101 .hooknum = NF_INET_LOCAL_IN, 102 .priority = NF_IP6_PRI_NAT_SRC, 103 }, 104}; 105 106static int __net_init ip6table_nat_net_init(struct net *net) 107{ 108 struct ip6t_replace *repl; 109 110 repl = ip6t_alloc_initial_table(&nf_nat_ipv6_table); 111 if (repl == NULL) 112 return -ENOMEM; 113 net->ipv6.ip6table_nat = ip6t_register_table(net, &nf_nat_ipv6_table, repl); 114 kfree(repl); 115 return PTR_ERR_OR_ZERO(net->ipv6.ip6table_nat); 116} 117 118static void __net_exit ip6table_nat_net_exit(struct net *net) 119{ 120 ip6t_unregister_table(net, net->ipv6.ip6table_nat); 121} 122 123static struct pernet_operations ip6table_nat_net_ops = { 124 .init = ip6table_nat_net_init, 125 .exit = ip6table_nat_net_exit, 126}; 127 128static int __init ip6table_nat_init(void) 129{ 130 int err; 131 132 err = register_pernet_subsys(&ip6table_nat_net_ops); 133 if (err < 0) 134 goto err1; 135 136 err = nf_register_hooks(nf_nat_ipv6_ops, ARRAY_SIZE(nf_nat_ipv6_ops)); 137 if (err < 0) 138 goto err2; 139 return 0; 140 141err2: 142 unregister_pernet_subsys(&ip6table_nat_net_ops); 143err1: 144 return err; 145} 146 147static void __exit ip6table_nat_exit(void) 148{ 149 nf_unregister_hooks(nf_nat_ipv6_ops, ARRAY_SIZE(nf_nat_ipv6_ops)); 150 unregister_pernet_subsys(&ip6table_nat_net_ops); 151} 152 153module_init(ip6table_nat_init); 154module_exit(ip6table_nat_exit); 155 156MODULE_LICENSE("GPL"); 157