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#include <linux/types.h> 9#include <linux/icmp.h> 10#include <linux/gfp.h> 11#include <linux/ip.h> 12#include <linux/netfilter.h> 13#include <linux/netfilter_ipv4.h> 14#include <linux/module.h> 15#include <linux/skbuff.h> 16#include <linux/proc_fs.h> 17#include <net/ip.h> 18#include <net/checksum.h> 19#include <linux/spinlock.h> 20 21#include <net/netfilter/nf_conntrack.h> 22#include <net/netfilter/nf_conntrack_core.h> 23#include <net/netfilter/nf_conntrack_extend.h> 24#include <net/netfilter/nf_nat.h> 25#include <net/netfilter/nf_nat_rule.h> 26#include <net/netfilter/nf_nat_protocol.h> 27#include <net/netfilter/nf_nat_core.h> 28#include <net/netfilter/nf_nat_helper.h> 29#include <linux/netfilter_ipv4/ip_tables.h> 30#ifdef CONFIG_IP_NF_TARGET_CONE 31#include <linux/netfilter_ipv4/ipt_cone.h> 32#endif /* CONFIG_IP_NF_TARGET_CONE */ 33#ifdef CONFIG_XFRM 34static void nat_decode_session(struct sk_buff *skb, struct flowi *fl) 35{ 36 const struct nf_conn *ct; 37 const struct nf_conntrack_tuple *t; 38 enum ip_conntrack_info ctinfo; 39 enum ip_conntrack_dir dir; 40 unsigned long statusbit; 41 42 ct = nf_ct_get(skb, &ctinfo); 43 if (ct == NULL) 44 return; 45 dir = CTINFO2DIR(ctinfo); 46 t = &ct->tuplehash[dir].tuple; 47 48 if (dir == IP_CT_DIR_ORIGINAL) 49 statusbit = IPS_DST_NAT; 50 else 51 statusbit = IPS_SRC_NAT; 52 53 if (ct->status & statusbit) { 54 fl->fl4_dst = t->dst.u3.ip; 55 if (t->dst.protonum == IPPROTO_TCP || 56 t->dst.protonum == IPPROTO_UDP || 57 t->dst.protonum == IPPROTO_UDPLITE || 58 t->dst.protonum == IPPROTO_DCCP || 59 t->dst.protonum == IPPROTO_SCTP) 60 fl->fl_ip_dport = t->dst.u.tcp.port; 61 } 62 63 statusbit ^= IPS_NAT_MASK; 64 65 if (ct->status & statusbit) { 66 fl->fl4_src = t->src.u3.ip; 67 if (t->dst.protonum == IPPROTO_TCP || 68 t->dst.protonum == IPPROTO_UDP || 69 t->dst.protonum == IPPROTO_UDPLITE || 70 t->dst.protonum == IPPROTO_DCCP || 71 t->dst.protonum == IPPROTO_SCTP) 72 fl->fl_ip_sport = t->src.u.tcp.port; 73 } 74} 75#endif 76 77static unsigned int 78nf_nat_fn(unsigned int hooknum, 79 struct sk_buff *skb, 80 const struct net_device *in, 81 const struct net_device *out, 82 int (*okfn)(struct sk_buff *)) 83{ 84 struct nf_conn *ct; 85 enum ip_conntrack_info ctinfo; 86 struct nf_conn_nat *nat; 87 /* maniptype == SRC for postrouting. */ 88 enum nf_nat_manip_type maniptype = HOOK2MANIP(hooknum); 89 90 /* We never see fragments: conntrack defrags on pre-routing 91 and local-out, and nf_nat_out protects post-routing. */ 92 NF_CT_ASSERT(!(ip_hdr(skb)->frag_off & htons(IP_MF | IP_OFFSET))); 93 94 ct = nf_ct_get(skb, &ctinfo); 95 /* Can't track? It's not due to stress, or conntrack would 96 have dropped it. Hence it's the user's responsibilty to 97 packet filter it out, or implement conntrack/NAT for that 98 protocol. 8) --RR */ 99 if (!ct) 100 return NF_ACCEPT; 101 102 /* Don't try to NAT if this packet is not conntracked */ 103 if (nf_ct_is_untracked(ct)) 104 return NF_ACCEPT; 105 106 nat = nfct_nat(ct); 107 if (!nat) { 108 /* NAT module was loaded late. */ 109 if (nf_ct_is_confirmed(ct)) 110 return NF_ACCEPT; 111 nat = nf_ct_ext_add(ct, NF_CT_EXT_NAT, GFP_ATOMIC); 112 if (nat == NULL) { 113 pr_debug("failed to add NAT extension\n"); 114 return NF_ACCEPT; 115 } 116 } 117 118 switch (ctinfo) { 119 case IP_CT_RELATED: 120 case IP_CT_RELATED+IP_CT_IS_REPLY: 121 if (ip_hdr(skb)->protocol == IPPROTO_ICMP) { 122 if (!nf_nat_icmp_reply_translation(ct, ctinfo, 123 hooknum, skb)) 124 return NF_DROP; 125 else 126 return NF_ACCEPT; 127 } 128 /* Fall thru... (Only ICMPs can be IP_CT_IS_REPLY) */ 129 case IP_CT_NEW: 130 131 /* Seen it before? This can happen for loopback, retrans, 132 or local packets.. */ 133 if (!nf_nat_initialized(ct, maniptype)) { 134 unsigned int ret; 135 136 ret = nf_nat_rule_find(skb, hooknum, in, out, ct); 137 if (ret != NF_ACCEPT) 138 return ret; 139#ifdef CONFIG_IP_NF_TARGET_CONE 140 /* Place to CONE NAT table */ 141 ipt_cone_place_in_hashes(ct); 142#endif /* CONFIG_IP_NF_TARGET_CONE */ 143 } else 144 pr_debug("Already setup manip %s for ct %p\n", 145 maniptype == IP_NAT_MANIP_SRC ? "SRC" : "DST", 146 ct); 147 break; 148 149 default: 150 /* ESTABLISHED */ 151 NF_CT_ASSERT(ctinfo == IP_CT_ESTABLISHED || 152 ctinfo == (IP_CT_ESTABLISHED+IP_CT_IS_REPLY)); 153 } 154 155 return nf_nat_packet(ct, ctinfo, hooknum, skb); 156} 157 158static unsigned int 159nf_nat_in(unsigned int hooknum, 160 struct sk_buff *skb, 161 const struct net_device *in, 162 const struct net_device *out, 163 int (*okfn)(struct sk_buff *)) 164{ 165 unsigned int ret; 166 __be32 daddr = ip_hdr(skb)->daddr; 167 168 ret = nf_nat_fn(hooknum, skb, in, out, okfn); 169 if (ret != NF_DROP && ret != NF_STOLEN && 170 daddr != ip_hdr(skb)->daddr) 171 skb_dst_drop(skb); 172 173 return ret; 174} 175 176static unsigned int 177nf_nat_out(unsigned int hooknum, 178 struct sk_buff *skb, 179 const struct net_device *in, 180 const struct net_device *out, 181 int (*okfn)(struct sk_buff *)) 182{ 183#ifdef CONFIG_XFRM 184 const struct nf_conn *ct; 185 enum ip_conntrack_info ctinfo; 186#endif 187 unsigned int ret; 188 189 /* root is playing with raw sockets. */ 190 if (skb->len < sizeof(struct iphdr) || 191 ip_hdrlen(skb) < sizeof(struct iphdr)) 192 return NF_ACCEPT; 193 194 ret = nf_nat_fn(hooknum, skb, in, out, okfn); 195#ifdef CONFIG_XFRM 196 if (ret != NF_DROP && ret != NF_STOLEN && 197 (ct = nf_ct_get(skb, &ctinfo)) != NULL) { 198 enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); 199 200 if ((ct->tuplehash[dir].tuple.src.u3.ip != 201 ct->tuplehash[!dir].tuple.dst.u3.ip) || 202 (ct->tuplehash[dir].tuple.src.u.all != 203 ct->tuplehash[!dir].tuple.dst.u.all) 204 ) 205 return ip_xfrm_me_harder(skb) == 0 ? ret : NF_DROP; 206 } 207#endif 208 return ret; 209} 210 211static unsigned int 212nf_nat_local_fn(unsigned int hooknum, 213 struct sk_buff *skb, 214 const struct net_device *in, 215 const struct net_device *out, 216 int (*okfn)(struct sk_buff *)) 217{ 218 const struct nf_conn *ct; 219 enum ip_conntrack_info ctinfo; 220 unsigned int ret; 221 222 /* root is playing with raw sockets. */ 223 if (skb->len < sizeof(struct iphdr) || 224 ip_hdrlen(skb) < sizeof(struct iphdr)) 225 return NF_ACCEPT; 226 227 ret = nf_nat_fn(hooknum, skb, in, out, okfn); 228 if (ret != NF_DROP && ret != NF_STOLEN && 229 (ct = nf_ct_get(skb, &ctinfo)) != NULL) { 230 enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); 231 232 if (ct->tuplehash[dir].tuple.dst.u3.ip != 233 ct->tuplehash[!dir].tuple.src.u3.ip) { 234 if (ip_route_me_harder(skb, RTN_UNSPEC)) 235 ret = NF_DROP; 236 } 237#ifdef CONFIG_XFRM 238 else if (ct->tuplehash[dir].tuple.dst.u.all != 239 ct->tuplehash[!dir].tuple.src.u.all) 240 if (ip_xfrm_me_harder(skb)) 241 ret = NF_DROP; 242#endif 243 } 244 return ret; 245} 246 247/* We must be after connection tracking and before packet filtering. */ 248 249static struct nf_hook_ops nf_nat_ops[] __read_mostly = { 250 /* Before packet filtering, change destination */ 251 { 252 .hook = nf_nat_in, 253 .owner = THIS_MODULE, 254 .pf = NFPROTO_IPV4, 255 .hooknum = NF_INET_PRE_ROUTING, 256 .priority = NF_IP_PRI_NAT_DST, 257 }, 258 /* After packet filtering, change source */ 259 { 260 .hook = nf_nat_out, 261 .owner = THIS_MODULE, 262 .pf = NFPROTO_IPV4, 263 .hooknum = NF_INET_POST_ROUTING, 264 .priority = NF_IP_PRI_NAT_SRC, 265 }, 266 /* Before packet filtering, change destination */ 267 { 268 .hook = nf_nat_local_fn, 269 .owner = THIS_MODULE, 270 .pf = NFPROTO_IPV4, 271 .hooknum = NF_INET_LOCAL_OUT, 272 .priority = NF_IP_PRI_NAT_DST, 273 }, 274 /* After packet filtering, change source */ 275 { 276 .hook = nf_nat_fn, 277 .owner = THIS_MODULE, 278 .pf = NFPROTO_IPV4, 279 .hooknum = NF_INET_LOCAL_IN, 280 .priority = NF_IP_PRI_NAT_SRC, 281 }, 282}; 283 284static int __init nf_nat_standalone_init(void) 285{ 286 int ret = 0; 287 288 need_ipv4_conntrack(); 289 290#ifdef CONFIG_XFRM 291 BUG_ON(ip_nat_decode_session != NULL); 292 rcu_assign_pointer(ip_nat_decode_session, nat_decode_session); 293#endif 294 ret = nf_nat_rule_init(); 295 if (ret < 0) { 296 pr_err("nf_nat_init: can't setup rules.\n"); 297 goto cleanup_decode_session; 298 } 299 ret = nf_register_hooks(nf_nat_ops, ARRAY_SIZE(nf_nat_ops)); 300 if (ret < 0) { 301 pr_err("nf_nat_init: can't register hooks.\n"); 302 goto cleanup_rule_init; 303 } 304 return ret; 305 306 cleanup_rule_init: 307 nf_nat_rule_cleanup(); 308 cleanup_decode_session: 309#ifdef CONFIG_XFRM 310 rcu_assign_pointer(ip_nat_decode_session, NULL); 311 synchronize_net(); 312#endif 313 return ret; 314} 315 316static void __exit nf_nat_standalone_fini(void) 317{ 318 nf_unregister_hooks(nf_nat_ops, ARRAY_SIZE(nf_nat_ops)); 319 nf_nat_rule_cleanup(); 320#ifdef CONFIG_XFRM 321 rcu_assign_pointer(ip_nat_decode_session, NULL); 322 synchronize_net(); 323#endif 324 /* Conntrack caches are unregistered in nf_conntrack_cleanup */ 325} 326 327module_init(nf_nat_standalone_init); 328module_exit(nf_nat_standalone_fini); 329 330MODULE_LICENSE("GPL"); 331MODULE_ALIAS("ip_nat"); 332