1 /* (C) 1999-2001 Paul `Rusty' Russell 2 * (C) 2002-2006 Netfilter Core Team <coreteam@netfilter.org> 3 * (C) 2011 Patrick McHardy <kaber@trash.net> 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License version 2 as 7 * published by the Free Software Foundation. 8 */ 9 10 #include <linux/module.h> 11 #include <linux/netfilter.h> 12 #include <linux/netfilter_ipv4.h> 13 #include <linux/netfilter_ipv4/ip_tables.h> 14 #include <linux/ip.h> 15 #include <net/ip.h> 16 17 #include <net/netfilter/nf_nat.h> 18 #include <net/netfilter/nf_nat_core.h> 19 #include <net/netfilter/nf_nat_l3proto.h> 20 21 static int __net_init iptable_nat_table_init(struct net *net); 22 23 static const struct xt_table nf_nat_ipv4_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_IPV4, 31 .table_init = iptable_nat_table_init, 32 }; 33 34 static unsigned int iptable_nat_do_chain(void *priv, 35 struct sk_buff *skb, 36 const struct nf_hook_state *state) 37 { 38 return ipt_do_table(skb, state, state->net->ipv4.nat_table); 39 } 40 41 static const struct nf_hook_ops nf_nat_ipv4_ops[] = { 42 { 43 .hook = iptable_nat_do_chain, 44 .pf = NFPROTO_IPV4, 45 .hooknum = NF_INET_PRE_ROUTING, 46 .priority = NF_IP_PRI_NAT_DST, 47 }, 48 { 49 .hook = iptable_nat_do_chain, 50 .pf = NFPROTO_IPV4, 51 .hooknum = NF_INET_POST_ROUTING, 52 .priority = NF_IP_PRI_NAT_SRC, 53 }, 54 { 55 .hook = iptable_nat_do_chain, 56 .pf = NFPROTO_IPV4, 57 .hooknum = NF_INET_LOCAL_OUT, 58 .priority = NF_IP_PRI_NAT_DST, 59 }, 60 { 61 .hook = iptable_nat_do_chain, 62 .pf = NFPROTO_IPV4, 63 .hooknum = NF_INET_LOCAL_IN, 64 .priority = NF_IP_PRI_NAT_SRC, 65 }, 66 }; 67 68 static int ipt_nat_register_lookups(struct net *net) 69 { 70 int i, ret; 71 72 for (i = 0; i < ARRAY_SIZE(nf_nat_ipv4_ops); i++) { 73 ret = nf_nat_l3proto_ipv4_register_fn(net, &nf_nat_ipv4_ops[i]); 74 if (ret) { 75 while (i) 76 nf_nat_l3proto_ipv4_unregister_fn(net, &nf_nat_ipv4_ops[--i]); 77 78 return ret; 79 } 80 } 81 82 return 0; 83 } 84 85 static void ipt_nat_unregister_lookups(struct net *net) 86 { 87 int i; 88 89 for (i = 0; i < ARRAY_SIZE(nf_nat_ipv4_ops); i++) 90 nf_nat_l3proto_ipv4_unregister_fn(net, &nf_nat_ipv4_ops[i]); 91 } 92 93 static int __net_init iptable_nat_table_init(struct net *net) 94 { 95 struct ipt_replace *repl; 96 int ret; 97 98 if (net->ipv4.nat_table) 99 return 0; 100 101 repl = ipt_alloc_initial_table(&nf_nat_ipv4_table); 102 if (repl == NULL) 103 return -ENOMEM; 104 ret = ipt_register_table(net, &nf_nat_ipv4_table, repl, 105 NULL, &net->ipv4.nat_table); 106 if (ret < 0) { 107 kfree(repl); 108 return ret; 109 } 110 111 ret = ipt_nat_register_lookups(net); 112 if (ret < 0) { 113 ipt_unregister_table(net, net->ipv4.nat_table, NULL); 114 net->ipv4.nat_table = NULL; 115 } 116 117 kfree(repl); 118 return ret; 119 } 120 121 static void __net_exit iptable_nat_net_exit(struct net *net) 122 { 123 if (!net->ipv4.nat_table) 124 return; 125 ipt_nat_unregister_lookups(net); 126 ipt_unregister_table(net, net->ipv4.nat_table, NULL); 127 net->ipv4.nat_table = NULL; 128 } 129 130 static struct pernet_operations iptable_nat_net_ops = { 131 .exit = iptable_nat_net_exit, 132 }; 133 134 static int __init iptable_nat_init(void) 135 { 136 int ret = register_pernet_subsys(&iptable_nat_net_ops); 137 138 if (ret) 139 return ret; 140 141 ret = iptable_nat_table_init(&init_net); 142 if (ret) 143 unregister_pernet_subsys(&iptable_nat_net_ops); 144 return ret; 145 } 146 147 static void __exit iptable_nat_exit(void) 148 { 149 unregister_pernet_subsys(&iptable_nat_net_ops); 150 } 151 152 module_init(iptable_nat_init); 153 module_exit(iptable_nat_exit); 154 155 MODULE_LICENSE("GPL"); 156