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