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 const struct xt_table nf_nat_ipv4_table = { 22 .name = "nat", 23 .valid_hooks = (1 << NF_INET_PRE_ROUTING) | 24 (1 << NF_INET_POST_ROUTING) | 25 (1 << NF_INET_LOCAL_OUT) | 26 (1 << NF_INET_LOCAL_IN), 27 .me = THIS_MODULE, 28 .af = NFPROTO_IPV4, 29 }; 30 31 static unsigned int iptable_nat_do_chain(void *priv, 32 struct sk_buff *skb, 33 const struct nf_hook_state *state, 34 struct nf_conn *ct) 35 { 36 return ipt_do_table(skb, state, state->net->ipv4.nat_table); 37 } 38 39 static unsigned int iptable_nat_ipv4_fn(void *priv, 40 struct sk_buff *skb, 41 const struct nf_hook_state *state) 42 { 43 return nf_nat_ipv4_fn(priv, skb, state, iptable_nat_do_chain); 44 } 45 46 static unsigned int iptable_nat_ipv4_in(void *priv, 47 struct sk_buff *skb, 48 const struct nf_hook_state *state) 49 { 50 return nf_nat_ipv4_in(priv, skb, state, iptable_nat_do_chain); 51 } 52 53 static unsigned int iptable_nat_ipv4_out(void *priv, 54 struct sk_buff *skb, 55 const struct nf_hook_state *state) 56 { 57 return nf_nat_ipv4_out(priv, skb, state, iptable_nat_do_chain); 58 } 59 60 static unsigned int iptable_nat_ipv4_local_fn(void *priv, 61 struct sk_buff *skb, 62 const struct nf_hook_state *state) 63 { 64 return nf_nat_ipv4_local_fn(priv, skb, state, iptable_nat_do_chain); 65 } 66 67 static struct nf_hook_ops nf_nat_ipv4_ops[] __read_mostly = { 68 /* Before packet filtering, change destination */ 69 { 70 .hook = iptable_nat_ipv4_in, 71 .pf = NFPROTO_IPV4, 72 .hooknum = NF_INET_PRE_ROUTING, 73 .priority = NF_IP_PRI_NAT_DST, 74 }, 75 /* After packet filtering, change source */ 76 { 77 .hook = iptable_nat_ipv4_out, 78 .pf = NFPROTO_IPV4, 79 .hooknum = NF_INET_POST_ROUTING, 80 .priority = NF_IP_PRI_NAT_SRC, 81 }, 82 /* Before packet filtering, change destination */ 83 { 84 .hook = iptable_nat_ipv4_local_fn, 85 .pf = NFPROTO_IPV4, 86 .hooknum = NF_INET_LOCAL_OUT, 87 .priority = NF_IP_PRI_NAT_DST, 88 }, 89 /* After packet filtering, change source */ 90 { 91 .hook = iptable_nat_ipv4_fn, 92 .pf = NFPROTO_IPV4, 93 .hooknum = NF_INET_LOCAL_IN, 94 .priority = NF_IP_PRI_NAT_SRC, 95 }, 96 }; 97 98 static int __net_init iptable_nat_net_init(struct net *net) 99 { 100 struct ipt_replace *repl; 101 102 repl = ipt_alloc_initial_table(&nf_nat_ipv4_table); 103 if (repl == NULL) 104 return -ENOMEM; 105 net->ipv4.nat_table = ipt_register_table(net, &nf_nat_ipv4_table, repl); 106 kfree(repl); 107 return PTR_ERR_OR_ZERO(net->ipv4.nat_table); 108 } 109 110 static void __net_exit iptable_nat_net_exit(struct net *net) 111 { 112 ipt_unregister_table(net, net->ipv4.nat_table); 113 } 114 115 static struct pernet_operations iptable_nat_net_ops = { 116 .init = iptable_nat_net_init, 117 .exit = iptable_nat_net_exit, 118 }; 119 120 static int __init iptable_nat_init(void) 121 { 122 int err; 123 124 err = register_pernet_subsys(&iptable_nat_net_ops); 125 if (err < 0) 126 goto err1; 127 128 err = nf_register_hooks(nf_nat_ipv4_ops, ARRAY_SIZE(nf_nat_ipv4_ops)); 129 if (err < 0) 130 goto err2; 131 return 0; 132 133 err2: 134 unregister_pernet_subsys(&iptable_nat_net_ops); 135 err1: 136 return err; 137 } 138 139 static void __exit iptable_nat_exit(void) 140 { 141 nf_unregister_hooks(nf_nat_ipv4_ops, ARRAY_SIZE(nf_nat_ipv4_ops)); 142 unregister_pernet_subsys(&iptable_nat_net_ops); 143 } 144 145 module_init(iptable_nat_init); 146 module_exit(iptable_nat_exit); 147 148 MODULE_LICENSE("GPL"); 149