iptable_nat.c (3708B)
1// SPDX-License-Identifier: GPL-2.0-only 2/* (C) 1999-2001 Paul `Rusty' Russell 3 * (C) 2002-2006 Netfilter Core Team <coreteam@netfilter.org> 4 * (C) 2011 Patrick McHardy <kaber@trash.net> 5 */ 6 7#include <linux/module.h> 8#include <linux/netfilter.h> 9#include <linux/netfilter_ipv4.h> 10#include <linux/netfilter_ipv4/ip_tables.h> 11#include <linux/ip.h> 12#include <net/ip.h> 13 14#include <net/netfilter/nf_nat.h> 15 16struct iptable_nat_pernet { 17 struct nf_hook_ops *nf_nat_ops; 18}; 19 20static unsigned int iptable_nat_net_id __read_mostly; 21 22static const struct xt_table nf_nat_ipv4_table = { 23 .name = "nat", 24 .valid_hooks = (1 << NF_INET_PRE_ROUTING) | 25 (1 << NF_INET_POST_ROUTING) | 26 (1 << NF_INET_LOCAL_OUT) | 27 (1 << NF_INET_LOCAL_IN), 28 .me = THIS_MODULE, 29 .af = NFPROTO_IPV4, 30}; 31 32static const struct nf_hook_ops nf_nat_ipv4_ops[] = { 33 { 34 .hook = ipt_do_table, 35 .pf = NFPROTO_IPV4, 36 .hooknum = NF_INET_PRE_ROUTING, 37 .priority = NF_IP_PRI_NAT_DST, 38 }, 39 { 40 .hook = ipt_do_table, 41 .pf = NFPROTO_IPV4, 42 .hooknum = NF_INET_POST_ROUTING, 43 .priority = NF_IP_PRI_NAT_SRC, 44 }, 45 { 46 .hook = ipt_do_table, 47 .pf = NFPROTO_IPV4, 48 .hooknum = NF_INET_LOCAL_OUT, 49 .priority = NF_IP_PRI_NAT_DST, 50 }, 51 { 52 .hook = ipt_do_table, 53 .pf = NFPROTO_IPV4, 54 .hooknum = NF_INET_LOCAL_IN, 55 .priority = NF_IP_PRI_NAT_SRC, 56 }, 57}; 58 59static int ipt_nat_register_lookups(struct net *net) 60{ 61 struct iptable_nat_pernet *xt_nat_net; 62 struct nf_hook_ops *ops; 63 struct xt_table *table; 64 int i, ret; 65 66 xt_nat_net = net_generic(net, iptable_nat_net_id); 67 table = xt_find_table(net, NFPROTO_IPV4, "nat"); 68 if (WARN_ON_ONCE(!table)) 69 return -ENOENT; 70 71 ops = kmemdup(nf_nat_ipv4_ops, sizeof(nf_nat_ipv4_ops), GFP_KERNEL); 72 if (!ops) 73 return -ENOMEM; 74 75 for (i = 0; i < ARRAY_SIZE(nf_nat_ipv4_ops); i++) { 76 ops[i].priv = table; 77 ret = nf_nat_ipv4_register_fn(net, &ops[i]); 78 if (ret) { 79 while (i) 80 nf_nat_ipv4_unregister_fn(net, &ops[--i]); 81 82 kfree(ops); 83 return ret; 84 } 85 } 86 87 xt_nat_net->nf_nat_ops = ops; 88 return 0; 89} 90 91static void ipt_nat_unregister_lookups(struct net *net) 92{ 93 struct iptable_nat_pernet *xt_nat_net = net_generic(net, iptable_nat_net_id); 94 struct nf_hook_ops *ops = xt_nat_net->nf_nat_ops; 95 int i; 96 97 if (!ops) 98 return; 99 100 for (i = 0; i < ARRAY_SIZE(nf_nat_ipv4_ops); i++) 101 nf_nat_ipv4_unregister_fn(net, &ops[i]); 102 103 kfree(ops); 104} 105 106static int iptable_nat_table_init(struct net *net) 107{ 108 struct ipt_replace *repl; 109 int ret; 110 111 repl = ipt_alloc_initial_table(&nf_nat_ipv4_table); 112 if (repl == NULL) 113 return -ENOMEM; 114 115 ret = ipt_register_table(net, &nf_nat_ipv4_table, repl, NULL); 116 if (ret < 0) { 117 kfree(repl); 118 return ret; 119 } 120 121 ret = ipt_nat_register_lookups(net); 122 if (ret < 0) 123 ipt_unregister_table_exit(net, "nat"); 124 125 kfree(repl); 126 return ret; 127} 128 129static void __net_exit iptable_nat_net_pre_exit(struct net *net) 130{ 131 ipt_nat_unregister_lookups(net); 132} 133 134static void __net_exit iptable_nat_net_exit(struct net *net) 135{ 136 ipt_unregister_table_exit(net, "nat"); 137} 138 139static struct pernet_operations iptable_nat_net_ops = { 140 .pre_exit = iptable_nat_net_pre_exit, 141 .exit = iptable_nat_net_exit, 142 .id = &iptable_nat_net_id, 143 .size = sizeof(struct iptable_nat_pernet), 144}; 145 146static int __init iptable_nat_init(void) 147{ 148 int ret = xt_register_template(&nf_nat_ipv4_table, 149 iptable_nat_table_init); 150 151 if (ret < 0) 152 return ret; 153 154 ret = register_pernet_subsys(&iptable_nat_net_ops); 155 if (ret < 0) { 156 xt_unregister_template(&nf_nat_ipv4_table); 157 return ret; 158 } 159 160 return ret; 161} 162 163static void __exit iptable_nat_exit(void) 164{ 165 unregister_pernet_subsys(&iptable_nat_net_ops); 166 xt_unregister_template(&nf_nat_ipv4_table); 167} 168 169module_init(iptable_nat_init); 170module_exit(iptable_nat_exit); 171 172MODULE_LICENSE("GPL");