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