1/* (C) 1999-2001 Paul `Rusty' Russell 2 * (C) 2002-2006 Netfilter Core Team <coreteam@netfilter.org> 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License version 2 as 6 * published by the Free Software Foundation. 7 */ 8 9/* Everything about the rules for NAT. */ 10#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 11#include <linux/types.h> 12#include <linux/ip.h> 13#include <linux/netfilter.h> 14#include <linux/netfilter_ipv4.h> 15#include <linux/module.h> 16#include <linux/kmod.h> 17#include <linux/skbuff.h> 18#include <linux/proc_fs.h> 19#include <linux/slab.h> 20#include <net/checksum.h> 21#include <net/route.h> 22#include <linux/bitops.h> 23 24#include <linux/netfilter_ipv4/ip_tables.h> 25#include <net/netfilter/nf_nat.h> 26#include <net/netfilter/nf_nat_core.h> 27#include <net/netfilter/nf_nat_rule.h> 28 29#define NAT_VALID_HOOKS ((1 << NF_INET_PRE_ROUTING) | \ 30 (1 << NF_INET_POST_ROUTING) | \ 31 (1 << NF_INET_LOCAL_OUT) | \ 32 (1 << NF_INET_LOCAL_IN)) 33 34static const struct xt_table nat_table = { 35 .name = "nat", 36 .valid_hooks = NAT_VALID_HOOKS, 37 .me = THIS_MODULE, 38 .af = NFPROTO_IPV4, 39}; 40 41/* Source NAT */ 42static unsigned int 43ipt_snat_target(struct sk_buff *skb, const struct xt_action_param *par) 44{ 45 struct nf_conn *ct; 46 enum ip_conntrack_info ctinfo; 47 const struct nf_nat_multi_range_compat *mr = par->targinfo; 48 49 NF_CT_ASSERT(par->hooknum == NF_INET_POST_ROUTING || 50 par->hooknum == NF_INET_LOCAL_IN); 51 52 ct = nf_ct_get(skb, &ctinfo); 53 54 /* Connection must be valid and new. */ 55 NF_CT_ASSERT(ct && (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED || 56 ctinfo == IP_CT_RELATED + IP_CT_IS_REPLY)); 57 NF_CT_ASSERT(par->out != NULL); 58 59 return nf_nat_setup_info(ct, &mr->range[0], IP_NAT_MANIP_SRC); 60} 61 62static unsigned int 63ipt_dnat_target(struct sk_buff *skb, const struct xt_action_param *par) 64{ 65 struct nf_conn *ct; 66 enum ip_conntrack_info ctinfo; 67 const struct nf_nat_multi_range_compat *mr = par->targinfo; 68 69 NF_CT_ASSERT(par->hooknum == NF_INET_PRE_ROUTING || 70 par->hooknum == NF_INET_LOCAL_OUT); 71 72 ct = nf_ct_get(skb, &ctinfo); 73 74 /* Connection must be valid and new. */ 75 NF_CT_ASSERT(ct && (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED)); 76 77 return nf_nat_setup_info(ct, &mr->range[0], IP_NAT_MANIP_DST); 78} 79 80static int ipt_snat_checkentry(const struct xt_tgchk_param *par) 81{ 82 const struct nf_nat_multi_range_compat *mr = par->targinfo; 83 84 /* Must be a valid range */ 85 if (mr->rangesize != 1) { 86 pr_info("SNAT: multiple ranges no longer supported\n"); 87 return -EINVAL; 88 } 89 return 0; 90} 91 92static int ipt_dnat_checkentry(const struct xt_tgchk_param *par) 93{ 94 const struct nf_nat_multi_range_compat *mr = par->targinfo; 95 96 /* Must be a valid range */ 97 if (mr->rangesize != 1) { 98 pr_info("DNAT: multiple ranges no longer supported\n"); 99 return -EINVAL; 100 } 101 return 0; 102} 103 104static unsigned int 105alloc_null_binding(struct nf_conn *ct, unsigned int hooknum) 106{ 107 /* Force range to this IP; let proto decide mapping for 108 per-proto parts (hence not IP_NAT_RANGE_PROTO_SPECIFIED). 109 Use reply in case it's already been mangled (eg local packet). 110 */ 111 __be32 ip 112 = (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC 113 ? ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3.ip 114 : ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u3.ip); 115 struct nf_nat_range range 116 = { IP_NAT_RANGE_MAP_IPS, ip, ip, { 0 }, { 0 } }; 117 118 pr_debug("Allocating NULL binding for %p (%pI4)\n", ct, &ip); 119 return nf_nat_setup_info(ct, &range, HOOK2MANIP(hooknum)); 120} 121 122int nf_nat_rule_find(struct sk_buff *skb, 123 unsigned int hooknum, 124 const struct net_device *in, 125 const struct net_device *out, 126 struct nf_conn *ct) 127{ 128 struct net *net = nf_ct_net(ct); 129 int ret; 130 131 ret = ipt_do_table(skb, hooknum, in, out, net->ipv4.nat_table); 132 133 if (ret == NF_ACCEPT) { 134 if (!nf_nat_initialized(ct, HOOK2MANIP(hooknum))) 135 /* NUL mapping */ 136 ret = alloc_null_binding(ct, hooknum); 137 } 138 return ret; 139} 140 141static struct xt_target ipt_snat_reg __read_mostly = { 142 .name = "SNAT", 143 .target = ipt_snat_target, 144 .targetsize = sizeof(struct nf_nat_multi_range_compat), 145 .table = "nat", 146 .hooks = (1 << NF_INET_POST_ROUTING) | (1 << NF_INET_LOCAL_IN), 147 .checkentry = ipt_snat_checkentry, 148 .family = AF_INET, 149}; 150 151static struct xt_target ipt_dnat_reg __read_mostly = { 152 .name = "DNAT", 153 .target = ipt_dnat_target, 154 .targetsize = sizeof(struct nf_nat_multi_range_compat), 155 .table = "nat", 156 .hooks = (1 << NF_INET_PRE_ROUTING) | (1 << NF_INET_LOCAL_OUT), 157 .checkentry = ipt_dnat_checkentry, 158 .family = AF_INET, 159}; 160 161static int __net_init nf_nat_rule_net_init(struct net *net) 162{ 163 struct ipt_replace *repl; 164 165 repl = ipt_alloc_initial_table(&nat_table); 166 if (repl == NULL) 167 return -ENOMEM; 168 net->ipv4.nat_table = ipt_register_table(net, &nat_table, repl); 169 kfree(repl); 170 if (IS_ERR(net->ipv4.nat_table)) 171 return PTR_ERR(net->ipv4.nat_table); 172 return 0; 173} 174 175static void __net_exit nf_nat_rule_net_exit(struct net *net) 176{ 177 ipt_unregister_table(net, net->ipv4.nat_table); 178} 179 180static struct pernet_operations nf_nat_rule_net_ops = { 181 .init = nf_nat_rule_net_init, 182 .exit = nf_nat_rule_net_exit, 183}; 184 185int __init nf_nat_rule_init(void) 186{ 187 int ret; 188 189 ret = register_pernet_subsys(&nf_nat_rule_net_ops); 190 if (ret != 0) 191 goto out; 192 ret = xt_register_target(&ipt_snat_reg); 193 if (ret != 0) 194 goto unregister_table; 195 196 ret = xt_register_target(&ipt_dnat_reg); 197 if (ret != 0) 198 goto unregister_snat; 199 200 return ret; 201 202 unregister_snat: 203 xt_unregister_target(&ipt_snat_reg); 204 unregister_table: 205 unregister_pernet_subsys(&nf_nat_rule_net_ops); 206 out: 207 return ret; 208} 209 210void nf_nat_rule_cleanup(void) 211{ 212 xt_unregister_target(&ipt_dnat_reg); 213 xt_unregister_target(&ipt_snat_reg); 214 unregister_pernet_subsys(&nf_nat_rule_net_ops); 215} 216