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 struct nf_hook_ops nf_nat_ipv6_ops[] __read_mostly = { 73 /* Before packet filtering, change destination */ 74 { 75 .hook = ip6table_nat_in, 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 .pf = NFPROTO_IPV6, 84 .hooknum = NF_INET_POST_ROUTING, 85 .priority = NF_IP6_PRI_NAT_SRC, 86 }, 87 /* Before packet filtering, change destination */ 88 { 89 .hook = ip6table_nat_local_fn, 90 .pf = NFPROTO_IPV6, 91 .hooknum = NF_INET_LOCAL_OUT, 92 .priority = NF_IP6_PRI_NAT_DST, 93 }, 94 /* After packet filtering, change source */ 95 { 96 .hook = ip6table_nat_fn, 97 .pf = NFPROTO_IPV6, 98 .hooknum = NF_INET_LOCAL_IN, 99 .priority = NF_IP6_PRI_NAT_SRC, 100 }, 101 }; 102 103 static int __net_init ip6table_nat_table_init(struct net *net) 104 { 105 struct ip6t_replace *repl; 106 int ret; 107 108 if (net->ipv6.ip6table_nat) 109 return 0; 110 111 repl = ip6t_alloc_initial_table(&nf_nat_ipv6_table); 112 if (repl == NULL) 113 return -ENOMEM; 114 ret = ip6t_register_table(net, &nf_nat_ipv6_table, repl, 115 nf_nat_ipv6_ops, &net->ipv6.ip6table_nat); 116 kfree(repl); 117 return ret; 118 } 119 120 static void __net_exit ip6table_nat_net_exit(struct net *net) 121 { 122 if (!net->ipv6.ip6table_nat) 123 return; 124 ip6t_unregister_table(net, net->ipv6.ip6table_nat, nf_nat_ipv6_ops); 125 net->ipv6.ip6table_nat = NULL; 126 } 127 128 static struct pernet_operations ip6table_nat_net_ops = { 129 .exit = ip6table_nat_net_exit, 130 }; 131 132 static int __init ip6table_nat_init(void) 133 { 134 int ret = register_pernet_subsys(&ip6table_nat_net_ops); 135 136 if (ret) 137 return ret; 138 139 ret = ip6table_nat_table_init(&init_net); 140 if (ret) 141 unregister_pernet_subsys(&ip6table_nat_net_ops); 142 return ret; 143 } 144 145 static void __exit ip6table_nat_exit(void) 146 { 147 unregister_pernet_subsys(&ip6table_nat_net_ops); 148 } 149 150 module_init(ip6table_nat_init); 151 module_exit(ip6table_nat_exit); 152 153 MODULE_LICENSE("GPL"); 154