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