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 16 struct iptable_nat_pernet { 17 struct nf_hook_ops *nf_nat_ops; 18 }; 19 20 static int __net_init iptable_nat_table_init(struct net *net); 21 22 static unsigned int iptable_nat_net_id __read_mostly; 23 24 static const struct xt_table nf_nat_ipv4_table = { 25 .name = "nat", 26 .valid_hooks = (1 << NF_INET_PRE_ROUTING) | 27 (1 << NF_INET_POST_ROUTING) | 28 (1 << NF_INET_LOCAL_OUT) | 29 (1 << NF_INET_LOCAL_IN), 30 .me = THIS_MODULE, 31 .af = NFPROTO_IPV4, 32 .table_init = iptable_nat_table_init, 33 }; 34 35 static unsigned int iptable_nat_do_chain(void *priv, 36 struct sk_buff *skb, 37 const struct nf_hook_state *state) 38 { 39 return ipt_do_table(skb, state, priv); 40 } 41 42 static const struct nf_hook_ops nf_nat_ipv4_ops[] = { 43 { 44 .hook = iptable_nat_do_chain, 45 .pf = NFPROTO_IPV4, 46 .hooknum = NF_INET_PRE_ROUTING, 47 .priority = NF_IP_PRI_NAT_DST, 48 }, 49 { 50 .hook = iptable_nat_do_chain, 51 .pf = NFPROTO_IPV4, 52 .hooknum = NF_INET_POST_ROUTING, 53 .priority = NF_IP_PRI_NAT_SRC, 54 }, 55 { 56 .hook = iptable_nat_do_chain, 57 .pf = NFPROTO_IPV4, 58 .hooknum = NF_INET_LOCAL_OUT, 59 .priority = NF_IP_PRI_NAT_DST, 60 }, 61 { 62 .hook = iptable_nat_do_chain, 63 .pf = NFPROTO_IPV4, 64 .hooknum = NF_INET_LOCAL_IN, 65 .priority = NF_IP_PRI_NAT_SRC, 66 }, 67 }; 68 69 static int ipt_nat_register_lookups(struct net *net) 70 { 71 struct iptable_nat_pernet *xt_nat_net; 72 struct nf_hook_ops *ops; 73 struct xt_table *table; 74 int i, ret; 75 76 xt_nat_net = net_generic(net, iptable_nat_net_id); 77 table = xt_find_table(net, NFPROTO_IPV4, "nat"); 78 if (WARN_ON_ONCE(!table)) 79 return -ENOENT; 80 81 ops = kmemdup(nf_nat_ipv4_ops, sizeof(nf_nat_ipv4_ops), GFP_KERNEL); 82 if (!ops) 83 return -ENOMEM; 84 85 for (i = 0; i < ARRAY_SIZE(nf_nat_ipv4_ops); i++) { 86 ops[i].priv = table; 87 ret = nf_nat_ipv4_register_fn(net, &ops[i]); 88 if (ret) { 89 while (i) 90 nf_nat_ipv4_unregister_fn(net, &ops[--i]); 91 92 kfree(ops); 93 return ret; 94 } 95 } 96 97 xt_nat_net->nf_nat_ops = ops; 98 return 0; 99 } 100 101 static void ipt_nat_unregister_lookups(struct net *net) 102 { 103 struct iptable_nat_pernet *xt_nat_net = net_generic(net, iptable_nat_net_id); 104 struct nf_hook_ops *ops = xt_nat_net->nf_nat_ops; 105 int i; 106 107 if (!ops) 108 return; 109 110 for (i = 0; i < ARRAY_SIZE(nf_nat_ipv4_ops); i++) 111 nf_nat_ipv4_unregister_fn(net, &ops[i]); 112 113 kfree(ops); 114 } 115 116 static int __net_init iptable_nat_table_init(struct net *net) 117 { 118 struct ipt_replace *repl; 119 int ret; 120 121 repl = ipt_alloc_initial_table(&nf_nat_ipv4_table); 122 if (repl == NULL) 123 return -ENOMEM; 124 125 ret = ipt_register_table(net, &nf_nat_ipv4_table, repl, NULL); 126 if (ret < 0) { 127 kfree(repl); 128 return ret; 129 } 130 131 ret = ipt_nat_register_lookups(net); 132 if (ret < 0) 133 ipt_unregister_table_exit(net, "nat"); 134 135 kfree(repl); 136 return ret; 137 } 138 139 static void __net_exit iptable_nat_net_pre_exit(struct net *net) 140 { 141 ipt_nat_unregister_lookups(net); 142 } 143 144 static void __net_exit iptable_nat_net_exit(struct net *net) 145 { 146 ipt_unregister_table_exit(net, "nat"); 147 } 148 149 static struct pernet_operations iptable_nat_net_ops = { 150 .pre_exit = iptable_nat_net_pre_exit, 151 .exit = iptable_nat_net_exit, 152 .id = &iptable_nat_net_id, 153 .size = sizeof(struct iptable_nat_pernet), 154 }; 155 156 static int __init iptable_nat_init(void) 157 { 158 int ret = register_pernet_subsys(&iptable_nat_net_ops); 159 160 if (ret) 161 return ret; 162 163 ret = iptable_nat_table_init(&init_net); 164 if (ret) 165 unregister_pernet_subsys(&iptable_nat_net_ops); 166 return ret; 167 } 168 169 static void __exit iptable_nat_exit(void) 170 { 171 unregister_pernet_subsys(&iptable_nat_net_ops); 172 } 173 174 module_init(iptable_nat_init); 175 module_exit(iptable_nat_exit); 176 177 MODULE_LICENSE("GPL"); 178