Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[NETFILTER]: Add NAT support for nf_conntrack

Add NAT support for nf_conntrack. Joint work of Jozsef Kadlecsik,
Yasuyuki Kozakai, Martin Josefsson and myself.

Signed-off-by: Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
Signed-off-by: Patrick McHardy <kaber@trash.net>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Jozsef Kadlecsik and committed by
David S. Miller
5b1158e9 d2483dde

+2668 -60
+1 -1
include/linux/netfilter.h
··· 357 357 static inline void 358 358 nf_nat_decode_session(struct sk_buff *skb, struct flowi *fl, int family) 359 359 { 360 - #ifdef CONFIG_IP_NF_NAT_NEEDED 360 + #if defined(CONFIG_IP_NF_NAT_NEEDED) || defined(CONFIG_NF_NAT_NEEDED) 361 361 void (*decodefn)(struct sk_buff *, struct flowi *); 362 362 363 363 if (family == AF_INET && (decodefn = ip_nat_decode_session) != NULL)
+7 -13
include/net/netfilter/ipv4/nf_conntrack_ipv4.h
··· 9 9 #ifndef _NF_CONNTRACK_IPV4_H 10 10 #define _NF_CONNTRACK_IPV4_H 11 11 12 - #ifdef CONFIG_IP_NF_NAT_NEEDED 13 - #include <linux/netfilter_ipv4/ip_nat.h> 12 + #ifdef CONFIG_NF_NAT_NEEDED 13 + #include <net/netfilter/nf_nat.h> 14 14 15 15 /* per conntrack: nat application helper private data */ 16 - union ip_conntrack_nat_help { 16 + union nf_conntrack_nat_help { 17 17 /* insert nat helper private data here */ 18 18 }; 19 19 20 - struct nf_conntrack_ipv4_nat { 21 - struct ip_nat_info info; 22 - union ip_conntrack_nat_help help; 20 + struct nf_conn_nat { 21 + struct nf_nat_info info; 22 + union nf_conntrack_nat_help help; 23 23 #if defined(CONFIG_IP_NF_TARGET_MASQUERADE) || \ 24 24 defined(CONFIG_IP_NF_TARGET_MASQUERADE_MODULE) 25 25 int masq_index; 26 26 #endif 27 27 }; 28 - #endif /* CONFIG_IP_NF_NAT_NEEDED */ 29 - 30 - struct nf_conntrack_ipv4 { 31 - #ifdef CONFIG_IP_NF_NAT_NEEDED 32 - struct nf_conntrack_ipv4_nat *nat; 33 - #endif 34 - }; 28 + #endif /* CONFIG_NF_NAT_NEEDED */ 35 29 36 30 /* Returns new sk_buff, or NULL */ 37 31 struct sk_buff *
+29 -2
include/net/netfilter/nf_conntrack.h
··· 264 264 265 265 /* valid combinations: 266 266 * basic: nf_conn, nf_conn .. nf_conn_help 267 - * nat: nf_conn .. nf_conn_nat, nf_conn .. nf_conn_nat, nf_conn help 267 + * nat: nf_conn .. nf_conn_nat, nf_conn .. nf_conn_nat .. nf_conn help 268 268 */ 269 + #ifdef CONFIG_NF_NAT_NEEDED 270 + static inline struct nf_conn_nat *nfct_nat(const struct nf_conn *ct) 271 + { 272 + unsigned int offset = sizeof(struct nf_conn); 273 + 274 + if (!(ct->features & NF_CT_F_NAT)) 275 + return NULL; 276 + 277 + offset = ALIGN(offset, __alignof__(struct nf_conn_nat)); 278 + return (struct nf_conn_nat *) ((void *)ct + offset); 279 + } 280 + 281 + static inline struct nf_conn_help *nfct_help(const struct nf_conn *ct) 282 + { 283 + unsigned int offset = sizeof(struct nf_conn); 284 + 285 + if (!(ct->features & NF_CT_F_HELP)) 286 + return NULL; 287 + if (ct->features & NF_CT_F_NAT) { 288 + offset = ALIGN(offset, __alignof__(struct nf_conn_nat)); 289 + offset += sizeof(struct nf_conn_nat); 290 + } 291 + 292 + offset = ALIGN(offset, __alignof__(struct nf_conn_help)); 293 + return (struct nf_conn_help *) ((void *)ct + offset); 294 + } 295 + #else /* No NAT */ 269 296 static inline struct nf_conn_help *nfct_help(const struct nf_conn *ct) 270 297 { 271 298 unsigned int offset = sizeof(struct nf_conn); ··· 303 276 offset = ALIGN(offset, __alignof__(struct nf_conn_help)); 304 277 return (struct nf_conn_help *) ((void *)ct + offset); 305 278 } 306 - 279 + #endif /* CONFIG_NF_NAT_NEEDED */ 307 280 #endif /* __KERNEL__ */ 308 281 #endif /* _NF_CONNTRACK_H */
+1 -1
include/net/netfilter/nf_conntrack_expect.h
··· 43 43 #ifdef CONFIG_NF_NAT_NEEDED 44 44 /* This is the original per-proto part, used to map the 45 45 * expected connection the way the recipient expects. */ 46 - union nf_conntrack_manip_proto saved_proto; 46 + union nf_conntrack_man_proto saved_proto; 47 47 /* Direction relative to the master connection. */ 48 48 enum ip_conntrack_dir dir; 49 49 #endif
+77
include/net/netfilter/nf_nat.h
··· 1 + #ifndef _NF_NAT_H 2 + #define _NF_NAT_H 3 + #include <linux/netfilter_ipv4.h> 4 + #include <net/netfilter/nf_conntrack_tuple.h> 5 + 6 + #define NF_NAT_MAPPING_TYPE_MAX_NAMELEN 16 7 + 8 + enum nf_nat_manip_type 9 + { 10 + IP_NAT_MANIP_SRC, 11 + IP_NAT_MANIP_DST 12 + }; 13 + 14 + /* SRC manip occurs POST_ROUTING or LOCAL_IN */ 15 + #define HOOK2MANIP(hooknum) ((hooknum) != NF_IP_POST_ROUTING && (hooknum) != NF_IP_LOCAL_IN) 16 + 17 + #define IP_NAT_RANGE_MAP_IPS 1 18 + #define IP_NAT_RANGE_PROTO_SPECIFIED 2 19 + 20 + /* NAT sequence number modifications */ 21 + struct nf_nat_seq { 22 + /* position of the last TCP sequence number modification (if any) */ 23 + u_int32_t correction_pos; 24 + 25 + /* sequence number offset before and after last modification */ 26 + int16_t offset_before, offset_after; 27 + }; 28 + 29 + /* Single range specification. */ 30 + struct nf_nat_range 31 + { 32 + /* Set to OR of flags above. */ 33 + unsigned int flags; 34 + 35 + /* Inclusive: network order. */ 36 + __be32 min_ip, max_ip; 37 + 38 + /* Inclusive: network order */ 39 + union nf_conntrack_man_proto min, max; 40 + }; 41 + 42 + /* For backwards compat: don't use in modern code. */ 43 + struct nf_nat_multi_range_compat 44 + { 45 + unsigned int rangesize; /* Must be 1. */ 46 + 47 + /* hangs off end. */ 48 + struct nf_nat_range range[1]; 49 + }; 50 + 51 + #ifdef __KERNEL__ 52 + #include <linux/list.h> 53 + 54 + /* The structure embedded in the conntrack structure. */ 55 + struct nf_nat_info 56 + { 57 + struct list_head bysource; 58 + struct nf_nat_seq seq[IP_CT_DIR_MAX]; 59 + }; 60 + 61 + struct nf_conn; 62 + 63 + /* Set up the info structure to map into this range. */ 64 + extern unsigned int nf_nat_setup_info(struct nf_conn *ct, 65 + const struct nf_nat_range *range, 66 + unsigned int hooknum); 67 + 68 + /* Is this tuple already taken? (not by us)*/ 69 + extern int nf_nat_used_tuple(const struct nf_conntrack_tuple *tuple, 70 + const struct nf_conn *ignored_conntrack); 71 + 72 + extern int nf_nat_module_is_loaded; 73 + 74 + #else /* !__KERNEL__: iptables wants this to compile. */ 75 + #define nf_nat_multi_range nf_nat_multi_range_compat 76 + #endif /*__KERNEL__*/ 77 + #endif
+27
include/net/netfilter/nf_nat_core.h
··· 1 + #ifndef _NF_NAT_CORE_H 2 + #define _NF_NAT_CORE_H 3 + #include <linux/list.h> 4 + #include <net/netfilter/nf_conntrack.h> 5 + 6 + /* This header used to share core functionality between the standalone 7 + NAT module, and the compatibility layer's use of NAT for masquerading. */ 8 + 9 + extern unsigned int nf_nat_packet(struct nf_conn *ct, 10 + enum ip_conntrack_info ctinfo, 11 + unsigned int hooknum, 12 + struct sk_buff **pskb); 13 + 14 + extern int nf_nat_icmp_reply_translation(struct nf_conn *ct, 15 + enum ip_conntrack_info ctinfo, 16 + unsigned int hooknum, 17 + struct sk_buff **pskb); 18 + 19 + static inline int nf_nat_initialized(struct nf_conn *ct, 20 + enum nf_nat_manip_type manip) 21 + { 22 + if (manip == IP_NAT_MANIP_SRC) 23 + return test_bit(IPS_SRC_NAT_DONE_BIT, &ct->status); 24 + else 25 + return test_bit(IPS_DST_NAT_DONE_BIT, &ct->status); 26 + } 27 + #endif /* _NF_NAT_CORE_H */
+32
include/net/netfilter/nf_nat_helper.h
··· 1 + #ifndef _NF_NAT_HELPER_H 2 + #define _NF_NAT_HELPER_H 3 + /* NAT protocol helper routines. */ 4 + 5 + #include <net/netfilter/nf_conntrack.h> 6 + 7 + struct sk_buff; 8 + 9 + /* These return true or false. */ 10 + extern int nf_nat_mangle_tcp_packet(struct sk_buff **skb, 11 + struct nf_conn *ct, 12 + enum ip_conntrack_info ctinfo, 13 + unsigned int match_offset, 14 + unsigned int match_len, 15 + const char *rep_buffer, 16 + unsigned int rep_len); 17 + extern int nf_nat_mangle_udp_packet(struct sk_buff **skb, 18 + struct nf_conn *ct, 19 + enum ip_conntrack_info ctinfo, 20 + unsigned int match_offset, 21 + unsigned int match_len, 22 + const char *rep_buffer, 23 + unsigned int rep_len); 24 + extern int nf_nat_seq_adjust(struct sk_buff **pskb, 25 + struct nf_conn *ct, 26 + enum ip_conntrack_info ctinfo); 27 + 28 + /* Setup NAT on this expected conntrack so it follows master, but goes 29 + * to port ct->master->saved_proto. */ 30 + extern void nf_nat_follow_master(struct nf_conn *ct, 31 + struct nf_conntrack_expect *this); 32 + #endif
+70
include/net/netfilter/nf_nat_protocol.h
··· 1 + /* Header for use in defining a given protocol. */ 2 + #ifndef _NF_NAT_PROTOCOL_H 3 + #define _NF_NAT_PROTOCOL_H 4 + #include <net/netfilter/nf_nat.h> 5 + #include <linux/netfilter/nfnetlink_conntrack.h> 6 + 7 + struct nf_nat_range; 8 + 9 + struct nf_nat_protocol 10 + { 11 + /* Protocol name */ 12 + const char *name; 13 + 14 + /* Protocol number. */ 15 + unsigned int protonum; 16 + 17 + struct module *me; 18 + 19 + /* Translate a packet to the target according to manip type. 20 + Return true if succeeded. */ 21 + int (*manip_pkt)(struct sk_buff **pskb, 22 + unsigned int iphdroff, 23 + const struct nf_conntrack_tuple *tuple, 24 + enum nf_nat_manip_type maniptype); 25 + 26 + /* Is the manipable part of the tuple between min and max incl? */ 27 + int (*in_range)(const struct nf_conntrack_tuple *tuple, 28 + enum nf_nat_manip_type maniptype, 29 + const union nf_conntrack_man_proto *min, 30 + const union nf_conntrack_man_proto *max); 31 + 32 + /* Alter the per-proto part of the tuple (depending on 33 + maniptype), to give a unique tuple in the given range if 34 + possible; return false if not. Per-protocol part of tuple 35 + is initialized to the incoming packet. */ 36 + int (*unique_tuple)(struct nf_conntrack_tuple *tuple, 37 + const struct nf_nat_range *range, 38 + enum nf_nat_manip_type maniptype, 39 + const struct nf_conn *ct); 40 + 41 + int (*range_to_nfattr)(struct sk_buff *skb, 42 + const struct nf_nat_range *range); 43 + 44 + int (*nfattr_to_range)(struct nfattr *tb[], 45 + struct nf_nat_range *range); 46 + }; 47 + 48 + /* Protocol registration. */ 49 + extern int nf_nat_protocol_register(struct nf_nat_protocol *proto); 50 + extern void nf_nat_protocol_unregister(struct nf_nat_protocol *proto); 51 + 52 + extern struct nf_nat_protocol *nf_nat_proto_find_get(u_int8_t protocol); 53 + extern void nf_nat_proto_put(struct nf_nat_protocol *proto); 54 + 55 + /* Built-in protocols. */ 56 + extern struct nf_nat_protocol nf_nat_protocol_tcp; 57 + extern struct nf_nat_protocol nf_nat_protocol_udp; 58 + extern struct nf_nat_protocol nf_nat_protocol_icmp; 59 + extern struct nf_nat_protocol nf_nat_unknown_protocol; 60 + 61 + extern int init_protocols(void) __init; 62 + extern void cleanup_protocols(void); 63 + extern struct nf_nat_protocol *find_nat_proto(u_int16_t protonum); 64 + 65 + extern int nf_nat_port_range_to_nfattr(struct sk_buff *skb, 66 + const struct nf_nat_range *range); 67 + extern int nf_nat_port_nfattr_to_range(struct nfattr *tb[], 68 + struct nf_nat_range *range); 69 + 70 + #endif /*_NF_NAT_PROTO_H*/
+35
include/net/netfilter/nf_nat_rule.h
··· 1 + #ifndef _NF_NAT_RULE_H 2 + #define _NF_NAT_RULE_H 3 + #include <net/netfilter/nf_conntrack.h> 4 + #include <net/netfilter/nf_nat.h> 5 + #include <linux/netfilter_ipv4/ip_tables.h> 6 + 7 + /* Compatibility definitions for ipt_FOO modules */ 8 + #define ip_nat_range nf_nat_range 9 + #define ip_conntrack_tuple nf_conntrack_tuple 10 + #define ip_conntrack_get nf_ct_get 11 + #define ip_conntrack nf_conn 12 + #define ip_nat_setup_info nf_nat_setup_info 13 + #define ip_nat_multi_range_compat nf_nat_multi_range_compat 14 + #define ip_ct_iterate_cleanup nf_ct_iterate_cleanup 15 + #define IP_NF_ASSERT NF_CT_ASSERT 16 + 17 + extern int nf_nat_rule_init(void) __init; 18 + extern void nf_nat_rule_cleanup(void); 19 + extern int nf_nat_rule_find(struct sk_buff **pskb, 20 + unsigned int hooknum, 21 + const struct net_device *in, 22 + const struct net_device *out, 23 + struct nf_conn *ct, 24 + struct nf_nat_info *info); 25 + 26 + extern unsigned int 27 + alloc_null_binding(struct nf_conn *ct, 28 + struct nf_nat_info *info, 29 + unsigned int hooknum); 30 + 31 + extern unsigned int 32 + alloc_null_binding_confirmed(struct nf_conn *ct, 33 + struct nf_nat_info *info, 34 + unsigned int hooknum); 35 + #endif /* _NF_NAT_RULE_H */
+23 -7
net/ipv4/netfilter/Kconfig
··· 6 6 depends on INET && NETFILTER 7 7 8 8 config NF_CONNTRACK_IPV4 9 - tristate "IPv4 support for new connection tracking (EXPERIMENTAL)" 9 + tristate "IPv4 support for new connection tracking (required for NAT) (EXPERIMENTAL)" 10 10 depends on EXPERIMENTAL && NF_CONNTRACK 11 11 ---help--- 12 12 Connection tracking keeps a record of what packets have passed ··· 387 387 388 388 To compile it as a module, choose M here. If unsure, say N. 389 389 390 - # NAT + specific targets 390 + # NAT + specific targets: ip_conntrack 391 391 config IP_NF_NAT 392 392 tristate "Full NAT" 393 393 depends on IP_NF_IPTABLES && IP_NF_CONNTRACK ··· 398 398 399 399 To compile it as a module, choose M here. If unsure, say N. 400 400 401 + # NAT + specific targets: nf_conntrack 402 + config NF_NAT 403 + tristate "Full NAT" 404 + depends on IP_NF_IPTABLES && NF_CONNTRACK 405 + help 406 + The Full NAT option allows masquerading, port forwarding and other 407 + forms of full Network Address Port Translation. It is controlled by 408 + the `nat' table in iptables: see the man page for iptables(8). 409 + 410 + To compile it as a module, choose M here. If unsure, say N. 411 + 401 412 config IP_NF_NAT_NEEDED 402 413 bool 403 - depends on IP_NF_NAT != n 414 + depends on IP_NF_NAT 415 + default y 416 + 417 + config NF_NAT_NEEDED 418 + bool 419 + depends on NF_NAT 404 420 default y 405 421 406 422 config IP_NF_TARGET_MASQUERADE 407 423 tristate "MASQUERADE target support" 408 - depends on IP_NF_NAT 424 + depends on (NF_NAT || IP_NF_NAT) 409 425 help 410 426 Masquerading is a special case of NAT: all outgoing connections are 411 427 changed to seem to come from a particular interface's address, and ··· 433 417 434 418 config IP_NF_TARGET_REDIRECT 435 419 tristate "REDIRECT target support" 436 - depends on IP_NF_NAT 420 + depends on (NF_NAT || IP_NF_NAT) 437 421 help 438 422 REDIRECT is a special case of NAT: all incoming connections are 439 423 mapped onto the incoming interface's address, causing the packets to ··· 444 428 445 429 config IP_NF_TARGET_NETMAP 446 430 tristate "NETMAP target support" 447 - depends on IP_NF_NAT 431 + depends on (NF_NAT || IP_NF_NAT) 448 432 help 449 433 NETMAP is an implementation of static 1:1 NAT mapping of network 450 434 addresses. It maps the network address part, while keeping the host ··· 455 439 456 440 config IP_NF_TARGET_SAME 457 441 tristate "SAME target support" 458 - depends on IP_NF_NAT 442 + depends on (NF_NAT || IP_NF_NAT) 459 443 help 460 444 This option adds a `SAME' target, which works like the standard SNAT 461 445 target, but attempts to give clients the same IP for all connections.
+7
net/ipv4/netfilter/Makefile
··· 5 5 # objects for the standalone - connection tracking / NAT 6 6 ip_conntrack-objs := ip_conntrack_standalone.o ip_conntrack_core.o ip_conntrack_proto_generic.o ip_conntrack_proto_tcp.o ip_conntrack_proto_udp.o ip_conntrack_proto_icmp.o 7 7 ip_nat-objs := ip_nat_core.o ip_nat_helper.o ip_nat_proto_unknown.o ip_nat_proto_tcp.o ip_nat_proto_udp.o ip_nat_proto_icmp.o 8 + nf_nat-objs := nf_nat_core.o nf_nat_helper.o nf_nat_proto_unknown.o nf_nat_proto_tcp.o nf_nat_proto_udp.o nf_nat_proto_icmp.o 9 + ifneq ($(CONFIG_NF_NAT),) 10 + iptable_nat-objs := nf_nat_rule.o nf_nat_standalone.o 11 + else 8 12 iptable_nat-objs := ip_nat_rule.o ip_nat_standalone.o 13 + endif 9 14 10 15 ip_conntrack_pptp-objs := ip_conntrack_helper_pptp.o ip_conntrack_proto_gre.o 11 16 ip_nat_pptp-objs := ip_nat_helper_pptp.o ip_nat_proto_gre.o ··· 21 16 # connection tracking 22 17 obj-$(CONFIG_IP_NF_CONNTRACK) += ip_conntrack.o 23 18 obj-$(CONFIG_IP_NF_NAT) += ip_nat.o 19 + obj-$(CONFIG_NF_NAT) += nf_nat.o 24 20 25 21 # conntrack netlink interface 26 22 obj-$(CONFIG_IP_NF_CONNTRACK_NETLINK) += ip_conntrack_netlink.o ··· 56 50 obj-$(CONFIG_IP_NF_FILTER) += iptable_filter.o 57 51 obj-$(CONFIG_IP_NF_MANGLE) += iptable_mangle.o 58 52 obj-$(CONFIG_IP_NF_NAT) += iptable_nat.o 53 + obj-$(CONFIG_NF_NAT) += iptable_nat.o 59 54 obj-$(CONFIG_IP_NF_RAW) += iptable_raw.o 60 55 61 56 # matches
-6
net/ipv4/netfilter/ip_nat_standalone.c
··· 44 44 #define DEBUGP(format, args...) 45 45 #endif 46 46 47 - #define HOOKNAME(hooknum) ((hooknum) == NF_IP_POST_ROUTING ? "POST_ROUTING" \ 48 - : ((hooknum) == NF_IP_PRE_ROUTING ? "PRE_ROUTING" \ 49 - : ((hooknum) == NF_IP_LOCAL_OUT ? "LOCAL_OUT" \ 50 - : ((hooknum) == NF_IP_LOCAL_IN ? "LOCAL_IN" \ 51 - : "*ERROR*"))) 52 - 53 47 #ifdef CONFIG_XFRM 54 48 static void nat_decode_session(struct sk_buff *skb, struct flowi *fl) 55 49 {
+27 -2
net/ipv4/netfilter/ipt_MASQUERADE.c
··· 2 2 (depending on route). */ 3 3 4 4 /* (C) 1999-2001 Paul `Rusty' Russell 5 - * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org> 5 + * (C) 2002-2006 Netfilter Core Team <coreteam@netfilter.org> 6 6 * 7 7 * This program is free software; you can redistribute it and/or modify 8 8 * it under the terms of the GNU General Public License version 2 as ··· 20 20 #include <net/checksum.h> 21 21 #include <net/route.h> 22 22 #include <linux/netfilter_ipv4.h> 23 + #ifdef CONFIG_NF_NAT_NEEDED 24 + #include <net/netfilter/nf_nat_rule.h> 25 + #else 23 26 #include <linux/netfilter_ipv4/ip_nat_rule.h> 27 + #endif 24 28 #include <linux/netfilter_ipv4/ip_tables.h> 25 29 26 30 MODULE_LICENSE("GPL"); ··· 69 65 const struct xt_target *target, 70 66 const void *targinfo) 71 67 { 68 + #ifdef CONFIG_NF_NAT_NEEDED 69 + struct nf_conn_nat *nat; 70 + #endif 72 71 struct ip_conntrack *ct; 73 72 enum ip_conntrack_info ctinfo; 74 - const struct ip_nat_multi_range_compat *mr; 75 73 struct ip_nat_range newrange; 74 + const struct ip_nat_multi_range_compat *mr; 76 75 struct rtable *rt; 77 76 __be32 newsrc; 78 77 79 78 IP_NF_ASSERT(hooknum == NF_IP_POST_ROUTING); 80 79 81 80 ct = ip_conntrack_get(*pskb, &ctinfo); 81 + #ifdef CONFIG_NF_NAT_NEEDED 82 + nat = nfct_nat(ct); 83 + #endif 82 84 IP_NF_ASSERT(ct && (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED 83 85 || ctinfo == IP_CT_RELATED + IP_CT_IS_REPLY)); 84 86 85 87 /* Source address is 0.0.0.0 - locally generated packet that is 86 88 * probably not supposed to be masqueraded. 87 89 */ 90 + #ifdef CONFIG_NF_NAT_NEEDED 91 + if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip == 0) 92 + #else 88 93 if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip == 0) 94 + #endif 89 95 return NF_ACCEPT; 90 96 91 97 mr = targinfo; ··· 107 93 } 108 94 109 95 write_lock_bh(&masq_lock); 96 + #ifdef CONFIG_NF_NAT_NEEDED 97 + nat->masq_index = out->ifindex; 98 + #else 110 99 ct->nat.masq_index = out->ifindex; 100 + #endif 111 101 write_unlock_bh(&masq_lock); 112 102 113 103 /* Transfer from original range. */ ··· 127 109 static inline int 128 110 device_cmp(struct ip_conntrack *i, void *ifindex) 129 111 { 112 + #ifdef CONFIG_NF_NAT_NEEDED 113 + struct nf_conn_nat *nat = nfct_nat(i); 114 + #endif 130 115 int ret; 131 116 132 117 read_lock_bh(&masq_lock); 118 + #ifdef CONFIG_NF_NAT_NEEDED 119 + ret = (nat->masq_index == (int)(long)ifindex); 120 + #else 133 121 ret = (i->nat.masq_index == (int)(long)ifindex); 122 + #endif 134 123 read_unlock_bh(&masq_lock); 135 124 136 125 return ret;
+4
net/ipv4/netfilter/ipt_NETMAP.c
··· 15 15 #include <linux/netdevice.h> 16 16 #include <linux/netfilter.h> 17 17 #include <linux/netfilter_ipv4.h> 18 + #ifdef CONFIG_NF_NAT_NEEDED 19 + #include <net/netfilter/nf_nat_rule.h> 20 + #else 18 21 #include <linux/netfilter_ipv4/ip_nat_rule.h> 22 + #endif 19 23 20 24 #define MODULENAME "NETMAP" 21 25 MODULE_LICENSE("GPL");
+5 -1
net/ipv4/netfilter/ipt_REDIRECT.c
··· 1 1 /* Redirect. Simple mapping which alters dst to a local IP address. */ 2 2 /* (C) 1999-2001 Paul `Rusty' Russell 3 - * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org> 3 + * (C) 2002-2006 Netfilter Core Team <coreteam@netfilter.org> 4 4 * 5 5 * This program is free software; you can redistribute it and/or modify 6 6 * it under the terms of the GNU General Public License version 2 as ··· 18 18 #include <net/protocol.h> 19 19 #include <net/checksum.h> 20 20 #include <linux/netfilter_ipv4.h> 21 + #ifdef CONFIG_NF_NAT_NEEDED 22 + #include <net/netfilter/nf_nat_rule.h> 23 + #else 21 24 #include <linux/netfilter_ipv4/ip_nat_rule.h> 25 + #endif 22 26 23 27 MODULE_LICENSE("GPL"); 24 28 MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
+11 -1
net/ipv4/netfilter/ipt_SAME.c
··· 34 34 #include <net/protocol.h> 35 35 #include <net/checksum.h> 36 36 #include <linux/netfilter_ipv4.h> 37 + #ifdef CONFIG_NF_NAT_NEEDED 38 + #include <net/netfilter/nf_nat_rule.h> 39 + #else 37 40 #include <linux/netfilter_ipv4/ip_nat_rule.h> 41 + #endif 38 42 #include <linux/netfilter_ipv4/ipt_SAME.h> 39 43 40 44 MODULE_LICENSE("GPL"); ··· 156 152 Here we calculate the index in same->iparray which 157 153 holds the ipaddress we should use */ 158 154 155 + #ifdef CONFIG_NF_NAT_NEEDED 156 + tmpip = ntohl(t->src.u3.ip); 157 + 158 + if (!(same->info & IPT_SAME_NODST)) 159 + tmpip += ntohl(t->dst.u3.ip); 160 + #else 159 161 tmpip = ntohl(t->src.ip); 160 162 161 163 if (!(same->info & IPT_SAME_NODST)) 162 164 tmpip += ntohl(t->dst.ip); 163 - 165 + #endif 164 166 aindex = tmpip % same->ipnum; 165 167 166 168 new_ip = htonl(same->iparray[aindex]);
+5 -2
net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
··· 111 111 return NF_ACCEPT; 112 112 } 113 113 114 - int nat_module_is_loaded = 0; 114 + int nf_nat_module_is_loaded = 0; 115 115 static u_int32_t ipv4_get_features(const struct nf_conntrack_tuple *tuple) 116 116 { 117 - if (nat_module_is_loaded) 117 + if (nf_nat_module_is_loaded) 118 118 return NF_CT_F_NAT; 119 119 120 120 return NF_CT_F_BASIC; ··· 532 532 module_exit(nf_conntrack_l3proto_ipv4_fini); 533 533 534 534 EXPORT_SYMBOL(nf_ct_ipv4_gather_frags); 535 + #ifdef CONFIG_NF_NAT_NEEDED 536 + EXPORT_SYMBOL(nf_nat_module_is_loaded); 537 + #endif
+647
net/ipv4/netfilter/nf_nat_core.c
··· 1 + /* NAT for netfilter; shared with compatibility layer. */ 2 + 3 + /* (C) 1999-2001 Paul `Rusty' Russell 4 + * (C) 2002-2006 Netfilter Core Team <coreteam@netfilter.org> 5 + * 6 + * This program is free software; you can redistribute it and/or modify 7 + * it under the terms of the GNU General Public License version 2 as 8 + * published by the Free Software Foundation. 9 + */ 10 + 11 + #include <linux/module.h> 12 + #include <linux/types.h> 13 + #include <linux/timer.h> 14 + #include <linux/skbuff.h> 15 + #include <linux/vmalloc.h> 16 + #include <net/checksum.h> 17 + #include <net/icmp.h> 18 + #include <net/ip.h> 19 + #include <net/tcp.h> /* For tcp_prot in getorigdst */ 20 + #include <linux/icmp.h> 21 + #include <linux/udp.h> 22 + #include <linux/jhash.h> 23 + 24 + #include <linux/netfilter_ipv4.h> 25 + #include <net/netfilter/nf_conntrack.h> 26 + #include <net/netfilter/nf_conntrack_core.h> 27 + #include <net/netfilter/nf_nat.h> 28 + #include <net/netfilter/nf_nat_protocol.h> 29 + #include <net/netfilter/nf_nat_core.h> 30 + #include <net/netfilter/nf_nat_helper.h> 31 + #include <net/netfilter/nf_conntrack_helper.h> 32 + #include <net/netfilter/nf_conntrack_l3proto.h> 33 + #include <net/netfilter/nf_conntrack_l4proto.h> 34 + 35 + #if 0 36 + #define DEBUGP printk 37 + #else 38 + #define DEBUGP(format, args...) 39 + #endif 40 + 41 + static DEFINE_RWLOCK(nf_nat_lock); 42 + 43 + static struct nf_conntrack_l3proto *l3proto = NULL; 44 + 45 + /* Calculated at init based on memory size */ 46 + static unsigned int nf_nat_htable_size; 47 + 48 + static struct list_head *bysource; 49 + 50 + #define MAX_IP_NAT_PROTO 256 51 + static struct nf_nat_protocol *nf_nat_protos[MAX_IP_NAT_PROTO]; 52 + 53 + static inline struct nf_nat_protocol * 54 + __nf_nat_proto_find(u_int8_t protonum) 55 + { 56 + return nf_nat_protos[protonum]; 57 + } 58 + 59 + struct nf_nat_protocol * 60 + nf_nat_proto_find_get(u_int8_t protonum) 61 + { 62 + struct nf_nat_protocol *p; 63 + 64 + /* we need to disable preemption to make sure 'p' doesn't get 65 + * removed until we've grabbed the reference */ 66 + preempt_disable(); 67 + p = __nf_nat_proto_find(protonum); 68 + if (!try_module_get(p->me)) 69 + p = &nf_nat_unknown_protocol; 70 + preempt_enable(); 71 + 72 + return p; 73 + } 74 + EXPORT_SYMBOL_GPL(nf_nat_proto_find_get); 75 + 76 + void 77 + nf_nat_proto_put(struct nf_nat_protocol *p) 78 + { 79 + module_put(p->me); 80 + } 81 + EXPORT_SYMBOL_GPL(nf_nat_proto_put); 82 + 83 + /* We keep an extra hash for each conntrack, for fast searching. */ 84 + static inline unsigned int 85 + hash_by_src(const struct nf_conntrack_tuple *tuple) 86 + { 87 + /* Original src, to ensure we map it consistently if poss. */ 88 + return jhash_3words((__force u32)tuple->src.u3.ip, tuple->src.u.all, 89 + tuple->dst.protonum, 0) % nf_nat_htable_size; 90 + } 91 + 92 + /* Noone using conntrack by the time this called. */ 93 + static void nf_nat_cleanup_conntrack(struct nf_conn *conn) 94 + { 95 + struct nf_conn_nat *nat; 96 + if (!(conn->status & IPS_NAT_DONE_MASK)) 97 + return; 98 + 99 + nat = nfct_nat(conn); 100 + write_lock_bh(&nf_nat_lock); 101 + list_del(&nat->info.bysource); 102 + write_unlock_bh(&nf_nat_lock); 103 + } 104 + 105 + /* Is this tuple already taken? (not by us) */ 106 + int 107 + nf_nat_used_tuple(const struct nf_conntrack_tuple *tuple, 108 + const struct nf_conn *ignored_conntrack) 109 + { 110 + /* Conntrack tracking doesn't keep track of outgoing tuples; only 111 + incoming ones. NAT means they don't have a fixed mapping, 112 + so we invert the tuple and look for the incoming reply. 113 + 114 + We could keep a separate hash if this proves too slow. */ 115 + struct nf_conntrack_tuple reply; 116 + 117 + nf_ct_invert_tuplepr(&reply, tuple); 118 + return nf_conntrack_tuple_taken(&reply, ignored_conntrack); 119 + } 120 + EXPORT_SYMBOL(nf_nat_used_tuple); 121 + 122 + /* If we source map this tuple so reply looks like reply_tuple, will 123 + * that meet the constraints of range. */ 124 + static int 125 + in_range(const struct nf_conntrack_tuple *tuple, 126 + const struct nf_nat_range *range) 127 + { 128 + struct nf_nat_protocol *proto; 129 + 130 + proto = __nf_nat_proto_find(tuple->dst.protonum); 131 + /* If we are supposed to map IPs, then we must be in the 132 + range specified, otherwise let this drag us onto a new src IP. */ 133 + if (range->flags & IP_NAT_RANGE_MAP_IPS) { 134 + if (ntohl(tuple->src.u3.ip) < ntohl(range->min_ip) || 135 + ntohl(tuple->src.u3.ip) > ntohl(range->max_ip)) 136 + return 0; 137 + } 138 + 139 + if (!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED) || 140 + proto->in_range(tuple, IP_NAT_MANIP_SRC, 141 + &range->min, &range->max)) 142 + return 1; 143 + 144 + return 0; 145 + } 146 + 147 + static inline int 148 + same_src(const struct nf_conn *ct, 149 + const struct nf_conntrack_tuple *tuple) 150 + { 151 + const struct nf_conntrack_tuple *t; 152 + 153 + t = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple; 154 + return (t->dst.protonum == tuple->dst.protonum && 155 + t->src.u3.ip == tuple->src.u3.ip && 156 + t->src.u.all == tuple->src.u.all); 157 + } 158 + 159 + /* Only called for SRC manip */ 160 + static int 161 + find_appropriate_src(const struct nf_conntrack_tuple *tuple, 162 + struct nf_conntrack_tuple *result, 163 + const struct nf_nat_range *range) 164 + { 165 + unsigned int h = hash_by_src(tuple); 166 + struct nf_conn_nat *nat; 167 + struct nf_conn *ct; 168 + 169 + read_lock_bh(&nf_nat_lock); 170 + list_for_each_entry(nat, &bysource[h], info.bysource) { 171 + ct = (struct nf_conn *)((char *)nat - offsetof(struct nf_conn, data)); 172 + if (same_src(ct, tuple)) { 173 + /* Copy source part from reply tuple. */ 174 + nf_ct_invert_tuplepr(result, 175 + &ct->tuplehash[IP_CT_DIR_REPLY].tuple); 176 + result->dst = tuple->dst; 177 + 178 + if (in_range(result, range)) { 179 + read_unlock_bh(&nf_nat_lock); 180 + return 1; 181 + } 182 + } 183 + } 184 + read_unlock_bh(&nf_nat_lock); 185 + return 0; 186 + } 187 + 188 + /* For [FUTURE] fragmentation handling, we want the least-used 189 + src-ip/dst-ip/proto triple. Fairness doesn't come into it. Thus 190 + if the range specifies 1.2.3.4 ports 10000-10005 and 1.2.3.5 ports 191 + 1-65535, we don't do pro-rata allocation based on ports; we choose 192 + the ip with the lowest src-ip/dst-ip/proto usage. 193 + */ 194 + static void 195 + find_best_ips_proto(struct nf_conntrack_tuple *tuple, 196 + const struct nf_nat_range *range, 197 + const struct nf_conn *ct, 198 + enum nf_nat_manip_type maniptype) 199 + { 200 + __be32 *var_ipp; 201 + /* Host order */ 202 + u_int32_t minip, maxip, j; 203 + 204 + /* No IP mapping? Do nothing. */ 205 + if (!(range->flags & IP_NAT_RANGE_MAP_IPS)) 206 + return; 207 + 208 + if (maniptype == IP_NAT_MANIP_SRC) 209 + var_ipp = &tuple->src.u3.ip; 210 + else 211 + var_ipp = &tuple->dst.u3.ip; 212 + 213 + /* Fast path: only one choice. */ 214 + if (range->min_ip == range->max_ip) { 215 + *var_ipp = range->min_ip; 216 + return; 217 + } 218 + 219 + /* Hashing source and destination IPs gives a fairly even 220 + * spread in practice (if there are a small number of IPs 221 + * involved, there usually aren't that many connections 222 + * anyway). The consistency means that servers see the same 223 + * client coming from the same IP (some Internet Banking sites 224 + * like this), even across reboots. */ 225 + minip = ntohl(range->min_ip); 226 + maxip = ntohl(range->max_ip); 227 + j = jhash_2words((__force u32)tuple->src.u3.ip, 228 + (__force u32)tuple->dst.u3.ip, 0); 229 + *var_ipp = htonl(minip + j % (maxip - minip + 1)); 230 + } 231 + 232 + /* Manipulate the tuple into the range given. For NF_IP_POST_ROUTING, 233 + * we change the source to map into the range. For NF_IP_PRE_ROUTING 234 + * and NF_IP_LOCAL_OUT, we change the destination to map into the 235 + * range. It might not be possible to get a unique tuple, but we try. 236 + * At worst (or if we race), we will end up with a final duplicate in 237 + * __ip_conntrack_confirm and drop the packet. */ 238 + static void 239 + get_unique_tuple(struct nf_conntrack_tuple *tuple, 240 + const struct nf_conntrack_tuple *orig_tuple, 241 + const struct nf_nat_range *range, 242 + struct nf_conn *ct, 243 + enum nf_nat_manip_type maniptype) 244 + { 245 + struct nf_nat_protocol *proto; 246 + 247 + /* 1) If this srcip/proto/src-proto-part is currently mapped, 248 + and that same mapping gives a unique tuple within the given 249 + range, use that. 250 + 251 + This is only required for source (ie. NAT/masq) mappings. 252 + So far, we don't do local source mappings, so multiple 253 + manips not an issue. */ 254 + if (maniptype == IP_NAT_MANIP_SRC) { 255 + if (find_appropriate_src(orig_tuple, tuple, range)) { 256 + DEBUGP("get_unique_tuple: Found current src map\n"); 257 + if (!nf_nat_used_tuple(tuple, ct)) 258 + return; 259 + } 260 + } 261 + 262 + /* 2) Select the least-used IP/proto combination in the given 263 + range. */ 264 + *tuple = *orig_tuple; 265 + find_best_ips_proto(tuple, range, ct, maniptype); 266 + 267 + /* 3) The per-protocol part of the manip is made to map into 268 + the range to make a unique tuple. */ 269 + 270 + proto = nf_nat_proto_find_get(orig_tuple->dst.protonum); 271 + 272 + /* Only bother mapping if it's not already in range and unique */ 273 + if ((!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED) || 274 + proto->in_range(tuple, maniptype, &range->min, &range->max)) && 275 + !nf_nat_used_tuple(tuple, ct)) { 276 + nf_nat_proto_put(proto); 277 + return; 278 + } 279 + 280 + /* Last change: get protocol to try to obtain unique tuple. */ 281 + proto->unique_tuple(tuple, range, maniptype, ct); 282 + 283 + nf_nat_proto_put(proto); 284 + } 285 + 286 + unsigned int 287 + nf_nat_setup_info(struct nf_conn *ct, 288 + const struct nf_nat_range *range, 289 + unsigned int hooknum) 290 + { 291 + struct nf_conntrack_tuple curr_tuple, new_tuple; 292 + struct nf_conn_nat *nat = nfct_nat(ct); 293 + struct nf_nat_info *info = &nat->info; 294 + int have_to_hash = !(ct->status & IPS_NAT_DONE_MASK); 295 + enum nf_nat_manip_type maniptype = HOOK2MANIP(hooknum); 296 + 297 + NF_CT_ASSERT(hooknum == NF_IP_PRE_ROUTING || 298 + hooknum == NF_IP_POST_ROUTING || 299 + hooknum == NF_IP_LOCAL_IN || 300 + hooknum == NF_IP_LOCAL_OUT); 301 + BUG_ON(nf_nat_initialized(ct, maniptype)); 302 + 303 + /* What we've got will look like inverse of reply. Normally 304 + this is what is in the conntrack, except for prior 305 + manipulations (future optimization: if num_manips == 0, 306 + orig_tp = 307 + conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple) */ 308 + nf_ct_invert_tuplepr(&curr_tuple, 309 + &ct->tuplehash[IP_CT_DIR_REPLY].tuple); 310 + 311 + get_unique_tuple(&new_tuple, &curr_tuple, range, ct, maniptype); 312 + 313 + if (!nf_ct_tuple_equal(&new_tuple, &curr_tuple)) { 314 + struct nf_conntrack_tuple reply; 315 + 316 + /* Alter conntrack table so will recognize replies. */ 317 + nf_ct_invert_tuplepr(&reply, &new_tuple); 318 + nf_conntrack_alter_reply(ct, &reply); 319 + 320 + /* Non-atomic: we own this at the moment. */ 321 + if (maniptype == IP_NAT_MANIP_SRC) 322 + ct->status |= IPS_SRC_NAT; 323 + else 324 + ct->status |= IPS_DST_NAT; 325 + } 326 + 327 + /* Place in source hash if this is the first time. */ 328 + if (have_to_hash) { 329 + unsigned int srchash; 330 + 331 + srchash = hash_by_src(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); 332 + write_lock_bh(&nf_nat_lock); 333 + list_add(&info->bysource, &bysource[srchash]); 334 + write_unlock_bh(&nf_nat_lock); 335 + } 336 + 337 + /* It's done. */ 338 + if (maniptype == IP_NAT_MANIP_DST) 339 + set_bit(IPS_DST_NAT_DONE_BIT, &ct->status); 340 + else 341 + set_bit(IPS_SRC_NAT_DONE_BIT, &ct->status); 342 + 343 + return NF_ACCEPT; 344 + } 345 + EXPORT_SYMBOL(nf_nat_setup_info); 346 + 347 + /* Returns true if succeeded. */ 348 + static int 349 + manip_pkt(u_int16_t proto, 350 + struct sk_buff **pskb, 351 + unsigned int iphdroff, 352 + const struct nf_conntrack_tuple *target, 353 + enum nf_nat_manip_type maniptype) 354 + { 355 + struct iphdr *iph; 356 + struct nf_nat_protocol *p; 357 + 358 + if (!skb_make_writable(pskb, iphdroff + sizeof(*iph))) 359 + return 0; 360 + 361 + iph = (void *)(*pskb)->data + iphdroff; 362 + 363 + /* Manipulate protcol part. */ 364 + p = nf_nat_proto_find_get(proto); 365 + if (!p->manip_pkt(pskb, iphdroff, target, maniptype)) { 366 + nf_nat_proto_put(p); 367 + return 0; 368 + } 369 + nf_nat_proto_put(p); 370 + 371 + iph = (void *)(*pskb)->data + iphdroff; 372 + 373 + if (maniptype == IP_NAT_MANIP_SRC) { 374 + nf_csum_replace4(&iph->check, iph->saddr, target->src.u3.ip); 375 + iph->saddr = target->src.u3.ip; 376 + } else { 377 + nf_csum_replace4(&iph->check, iph->daddr, target->dst.u3.ip); 378 + iph->daddr = target->dst.u3.ip; 379 + } 380 + return 1; 381 + } 382 + 383 + /* Do packet manipulations according to nf_nat_setup_info. */ 384 + unsigned int nf_nat_packet(struct nf_conn *ct, 385 + enum ip_conntrack_info ctinfo, 386 + unsigned int hooknum, 387 + struct sk_buff **pskb) 388 + { 389 + enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); 390 + unsigned long statusbit; 391 + enum nf_nat_manip_type mtype = HOOK2MANIP(hooknum); 392 + 393 + if (mtype == IP_NAT_MANIP_SRC) 394 + statusbit = IPS_SRC_NAT; 395 + else 396 + statusbit = IPS_DST_NAT; 397 + 398 + /* Invert if this is reply dir. */ 399 + if (dir == IP_CT_DIR_REPLY) 400 + statusbit ^= IPS_NAT_MASK; 401 + 402 + /* Non-atomic: these bits don't change. */ 403 + if (ct->status & statusbit) { 404 + struct nf_conntrack_tuple target; 405 + 406 + /* We are aiming to look like inverse of other direction. */ 407 + nf_ct_invert_tuplepr(&target, &ct->tuplehash[!dir].tuple); 408 + 409 + if (!manip_pkt(target.dst.protonum, pskb, 0, &target, mtype)) 410 + return NF_DROP; 411 + } 412 + return NF_ACCEPT; 413 + } 414 + EXPORT_SYMBOL_GPL(nf_nat_packet); 415 + 416 + /* Dir is direction ICMP is coming from (opposite to packet it contains) */ 417 + int nf_nat_icmp_reply_translation(struct nf_conn *ct, 418 + enum ip_conntrack_info ctinfo, 419 + unsigned int hooknum, 420 + struct sk_buff **pskb) 421 + { 422 + struct { 423 + struct icmphdr icmp; 424 + struct iphdr ip; 425 + } *inside; 426 + struct nf_conntrack_tuple inner, target; 427 + int hdrlen = (*pskb)->nh.iph->ihl * 4; 428 + enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); 429 + unsigned long statusbit; 430 + enum nf_nat_manip_type manip = HOOK2MANIP(hooknum); 431 + 432 + if (!skb_make_writable(pskb, hdrlen + sizeof(*inside))) 433 + return 0; 434 + 435 + inside = (void *)(*pskb)->data + (*pskb)->nh.iph->ihl*4; 436 + 437 + /* We're actually going to mangle it beyond trivial checksum 438 + adjustment, so make sure the current checksum is correct. */ 439 + if (nf_ip_checksum(*pskb, hooknum, hdrlen, 0)) 440 + return 0; 441 + 442 + /* Must be RELATED */ 443 + NF_CT_ASSERT((*pskb)->nfctinfo == IP_CT_RELATED || 444 + (*pskb)->nfctinfo == IP_CT_RELATED+IP_CT_IS_REPLY); 445 + 446 + /* Redirects on non-null nats must be dropped, else they'll 447 + start talking to each other without our translation, and be 448 + confused... --RR */ 449 + if (inside->icmp.type == ICMP_REDIRECT) { 450 + /* If NAT isn't finished, assume it and drop. */ 451 + if ((ct->status & IPS_NAT_DONE_MASK) != IPS_NAT_DONE_MASK) 452 + return 0; 453 + 454 + if (ct->status & IPS_NAT_MASK) 455 + return 0; 456 + } 457 + 458 + DEBUGP("icmp_reply_translation: translating error %p manp %u dir %s\n", 459 + *pskb, manip, dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY"); 460 + 461 + if (!nf_ct_get_tuple(*pskb, 462 + (*pskb)->nh.iph->ihl*4 + sizeof(struct icmphdr), 463 + (*pskb)->nh.iph->ihl*4 + 464 + sizeof(struct icmphdr) + inside->ip.ihl*4, 465 + (u_int16_t)AF_INET, 466 + inside->ip.protocol, 467 + &inner, 468 + l3proto, 469 + __nf_ct_l4proto_find((u_int16_t)PF_INET, 470 + inside->ip.protocol))) 471 + return 0; 472 + 473 + /* Change inner back to look like incoming packet. We do the 474 + opposite manip on this hook to normal, because it might not 475 + pass all hooks (locally-generated ICMP). Consider incoming 476 + packet: PREROUTING (DST manip), routing produces ICMP, goes 477 + through POSTROUTING (which must correct the DST manip). */ 478 + if (!manip_pkt(inside->ip.protocol, pskb, 479 + (*pskb)->nh.iph->ihl*4 + sizeof(inside->icmp), 480 + &ct->tuplehash[!dir].tuple, 481 + !manip)) 482 + return 0; 483 + 484 + if ((*pskb)->ip_summed != CHECKSUM_PARTIAL) { 485 + /* Reloading "inside" here since manip_pkt inner. */ 486 + inside = (void *)(*pskb)->data + (*pskb)->nh.iph->ihl*4; 487 + inside->icmp.checksum = 0; 488 + inside->icmp.checksum = 489 + csum_fold(skb_checksum(*pskb, hdrlen, 490 + (*pskb)->len - hdrlen, 0)); 491 + } 492 + 493 + /* Change outer to look the reply to an incoming packet 494 + * (proto 0 means don't invert per-proto part). */ 495 + if (manip == IP_NAT_MANIP_SRC) 496 + statusbit = IPS_SRC_NAT; 497 + else 498 + statusbit = IPS_DST_NAT; 499 + 500 + /* Invert if this is reply dir. */ 501 + if (dir == IP_CT_DIR_REPLY) 502 + statusbit ^= IPS_NAT_MASK; 503 + 504 + if (ct->status & statusbit) { 505 + nf_ct_invert_tuplepr(&target, &ct->tuplehash[!dir].tuple); 506 + if (!manip_pkt(0, pskb, 0, &target, manip)) 507 + return 0; 508 + } 509 + 510 + return 1; 511 + } 512 + EXPORT_SYMBOL_GPL(nf_nat_icmp_reply_translation); 513 + 514 + /* Protocol registration. */ 515 + int nf_nat_protocol_register(struct nf_nat_protocol *proto) 516 + { 517 + int ret = 0; 518 + 519 + write_lock_bh(&nf_nat_lock); 520 + if (nf_nat_protos[proto->protonum] != &nf_nat_unknown_protocol) { 521 + ret = -EBUSY; 522 + goto out; 523 + } 524 + nf_nat_protos[proto->protonum] = proto; 525 + out: 526 + write_unlock_bh(&nf_nat_lock); 527 + return ret; 528 + } 529 + EXPORT_SYMBOL(nf_nat_protocol_register); 530 + 531 + /* Noone stores the protocol anywhere; simply delete it. */ 532 + void nf_nat_protocol_unregister(struct nf_nat_protocol *proto) 533 + { 534 + write_lock_bh(&nf_nat_lock); 535 + nf_nat_protos[proto->protonum] = &nf_nat_unknown_protocol; 536 + write_unlock_bh(&nf_nat_lock); 537 + 538 + /* Someone could be still looking at the proto in a bh. */ 539 + synchronize_net(); 540 + } 541 + EXPORT_SYMBOL(nf_nat_protocol_unregister); 542 + 543 + #if defined(CONFIG_IP_NF_CONNTRACK_NETLINK) || \ 544 + defined(CONFIG_IP_NF_CONNTRACK_NETLINK_MODULE) 545 + int 546 + nf_nat_port_range_to_nfattr(struct sk_buff *skb, 547 + const struct nf_nat_range *range) 548 + { 549 + NFA_PUT(skb, CTA_PROTONAT_PORT_MIN, sizeof(__be16), 550 + &range->min.tcp.port); 551 + NFA_PUT(skb, CTA_PROTONAT_PORT_MAX, sizeof(__be16), 552 + &range->max.tcp.port); 553 + 554 + return 0; 555 + 556 + nfattr_failure: 557 + return -1; 558 + } 559 + EXPORT_SYMBOL_GPL(nf_nat_port_nfattr_to_range); 560 + 561 + int 562 + nf_nat_port_nfattr_to_range(struct nfattr *tb[], struct nf_nat_range *range) 563 + { 564 + int ret = 0; 565 + 566 + /* we have to return whether we actually parsed something or not */ 567 + 568 + if (tb[CTA_PROTONAT_PORT_MIN-1]) { 569 + ret = 1; 570 + range->min.tcp.port = 571 + *(__be16 *)NFA_DATA(tb[CTA_PROTONAT_PORT_MIN-1]); 572 + } 573 + 574 + if (!tb[CTA_PROTONAT_PORT_MAX-1]) { 575 + if (ret) 576 + range->max.tcp.port = range->min.tcp.port; 577 + } else { 578 + ret = 1; 579 + range->max.tcp.port = 580 + *(__be16 *)NFA_DATA(tb[CTA_PROTONAT_PORT_MAX-1]); 581 + } 582 + 583 + return ret; 584 + } 585 + EXPORT_SYMBOL_GPL(nf_nat_port_range_to_nfattr); 586 + #endif 587 + 588 + static int __init nf_nat_init(void) 589 + { 590 + size_t i; 591 + 592 + /* Leave them the same for the moment. */ 593 + nf_nat_htable_size = nf_conntrack_htable_size; 594 + 595 + /* One vmalloc for both hash tables */ 596 + bysource = vmalloc(sizeof(struct list_head) * nf_nat_htable_size); 597 + if (!bysource) 598 + return -ENOMEM; 599 + 600 + /* Sew in builtin protocols. */ 601 + write_lock_bh(&nf_nat_lock); 602 + for (i = 0; i < MAX_IP_NAT_PROTO; i++) 603 + nf_nat_protos[i] = &nf_nat_unknown_protocol; 604 + nf_nat_protos[IPPROTO_TCP] = &nf_nat_protocol_tcp; 605 + nf_nat_protos[IPPROTO_UDP] = &nf_nat_protocol_udp; 606 + nf_nat_protos[IPPROTO_ICMP] = &nf_nat_protocol_icmp; 607 + write_unlock_bh(&nf_nat_lock); 608 + 609 + for (i = 0; i < nf_nat_htable_size; i++) { 610 + INIT_LIST_HEAD(&bysource[i]); 611 + } 612 + 613 + /* FIXME: Man, this is a hack. <SIGH> */ 614 + NF_CT_ASSERT(nf_conntrack_destroyed == NULL); 615 + nf_conntrack_destroyed = &nf_nat_cleanup_conntrack; 616 + 617 + /* Initialize fake conntrack so that NAT will skip it */ 618 + nf_conntrack_untracked.status |= IPS_NAT_DONE_MASK; 619 + 620 + l3proto = nf_ct_l3proto_find_get((u_int16_t)AF_INET); 621 + return 0; 622 + } 623 + 624 + /* Clear NAT section of all conntracks, in case we're loaded again. */ 625 + static int clean_nat(struct nf_conn *i, void *data) 626 + { 627 + struct nf_conn_nat *nat = nfct_nat(i); 628 + 629 + if (!nat) 630 + return 0; 631 + memset(nat, 0, sizeof(nat)); 632 + i->status &= ~(IPS_NAT_MASK | IPS_NAT_DONE_MASK | IPS_SEQ_ADJUST); 633 + return 0; 634 + } 635 + 636 + static void __exit nf_nat_cleanup(void) 637 + { 638 + nf_ct_iterate_cleanup(&clean_nat, NULL); 639 + nf_conntrack_destroyed = NULL; 640 + vfree(bysource); 641 + nf_ct_l3proto_put(l3proto); 642 + } 643 + 644 + MODULE_LICENSE("GPL"); 645 + 646 + module_init(nf_nat_init); 647 + module_exit(nf_nat_cleanup);
+433
net/ipv4/netfilter/nf_nat_helper.c
··· 1 + /* ip_nat_helper.c - generic support functions for NAT helpers 2 + * 3 + * (C) 2000-2002 Harald Welte <laforge@netfilter.org> 4 + * (C) 2003-2006 Netfilter Core Team <coreteam@netfilter.org> 5 + * 6 + * This program is free software; you can redistribute it and/or modify 7 + * it under the terms of the GNU General Public License version 2 as 8 + * published by the Free Software Foundation. 9 + */ 10 + #include <linux/module.h> 11 + #include <linux/kmod.h> 12 + #include <linux/types.h> 13 + #include <linux/timer.h> 14 + #include <linux/skbuff.h> 15 + #include <linux/tcp.h> 16 + #include <linux/udp.h> 17 + #include <net/checksum.h> 18 + #include <net/tcp.h> 19 + 20 + #include <linux/netfilter_ipv4.h> 21 + #include <net/netfilter/nf_conntrack.h> 22 + #include <net/netfilter/nf_conntrack_helper.h> 23 + #include <net/netfilter/nf_conntrack_expect.h> 24 + #include <net/netfilter/nf_nat.h> 25 + #include <net/netfilter/nf_nat_protocol.h> 26 + #include <net/netfilter/nf_nat_core.h> 27 + #include <net/netfilter/nf_nat_helper.h> 28 + 29 + #if 0 30 + #define DEBUGP printk 31 + #define DUMP_OFFSET(x) printk("offset_before=%d, offset_after=%d, correction_pos=%u\n", x->offset_before, x->offset_after, x->correction_pos); 32 + #else 33 + #define DEBUGP(format, args...) 34 + #define DUMP_OFFSET(x) 35 + #endif 36 + 37 + static DEFINE_SPINLOCK(nf_nat_seqofs_lock); 38 + 39 + /* Setup TCP sequence correction given this change at this sequence */ 40 + static inline void 41 + adjust_tcp_sequence(u32 seq, 42 + int sizediff, 43 + struct nf_conn *ct, 44 + enum ip_conntrack_info ctinfo) 45 + { 46 + int dir; 47 + struct nf_nat_seq *this_way, *other_way; 48 + struct nf_conn_nat *nat = nfct_nat(ct); 49 + 50 + DEBUGP("nf_nat_resize_packet: old_size = %u, new_size = %u\n", 51 + (*skb)->len, new_size); 52 + 53 + dir = CTINFO2DIR(ctinfo); 54 + 55 + this_way = &nat->info.seq[dir]; 56 + other_way = &nat->info.seq[!dir]; 57 + 58 + DEBUGP("nf_nat_resize_packet: Seq_offset before: "); 59 + DUMP_OFFSET(this_way); 60 + 61 + spin_lock_bh(&nf_nat_seqofs_lock); 62 + 63 + /* SYN adjust. If it's uninitialized, or this is after last 64 + * correction, record it: we don't handle more than one 65 + * adjustment in the window, but do deal with common case of a 66 + * retransmit */ 67 + if (this_way->offset_before == this_way->offset_after || 68 + before(this_way->correction_pos, seq)) { 69 + this_way->correction_pos = seq; 70 + this_way->offset_before = this_way->offset_after; 71 + this_way->offset_after += sizediff; 72 + } 73 + spin_unlock_bh(&nf_nat_seqofs_lock); 74 + 75 + DEBUGP("nf_nat_resize_packet: Seq_offset after: "); 76 + DUMP_OFFSET(this_way); 77 + } 78 + 79 + /* Frobs data inside this packet, which is linear. */ 80 + static void mangle_contents(struct sk_buff *skb, 81 + unsigned int dataoff, 82 + unsigned int match_offset, 83 + unsigned int match_len, 84 + const char *rep_buffer, 85 + unsigned int rep_len) 86 + { 87 + unsigned char *data; 88 + 89 + BUG_ON(skb_is_nonlinear(skb)); 90 + data = (unsigned char *)skb->nh.iph + dataoff; 91 + 92 + /* move post-replacement */ 93 + memmove(data + match_offset + rep_len, 94 + data + match_offset + match_len, 95 + skb->tail - (data + match_offset + match_len)); 96 + 97 + /* insert data from buffer */ 98 + memcpy(data + match_offset, rep_buffer, rep_len); 99 + 100 + /* update skb info */ 101 + if (rep_len > match_len) { 102 + DEBUGP("nf_nat_mangle_packet: Extending packet by " 103 + "%u from %u bytes\n", rep_len - match_len, 104 + skb->len); 105 + skb_put(skb, rep_len - match_len); 106 + } else { 107 + DEBUGP("nf_nat_mangle_packet: Shrinking packet from " 108 + "%u from %u bytes\n", match_len - rep_len, 109 + skb->len); 110 + __skb_trim(skb, skb->len + rep_len - match_len); 111 + } 112 + 113 + /* fix IP hdr checksum information */ 114 + skb->nh.iph->tot_len = htons(skb->len); 115 + ip_send_check(skb->nh.iph); 116 + } 117 + 118 + /* Unusual, but possible case. */ 119 + static int enlarge_skb(struct sk_buff **pskb, unsigned int extra) 120 + { 121 + struct sk_buff *nskb; 122 + 123 + if ((*pskb)->len + extra > 65535) 124 + return 0; 125 + 126 + nskb = skb_copy_expand(*pskb, skb_headroom(*pskb), extra, GFP_ATOMIC); 127 + if (!nskb) 128 + return 0; 129 + 130 + /* Transfer socket to new skb. */ 131 + if ((*pskb)->sk) 132 + skb_set_owner_w(nskb, (*pskb)->sk); 133 + kfree_skb(*pskb); 134 + *pskb = nskb; 135 + return 1; 136 + } 137 + 138 + /* Generic function for mangling variable-length address changes inside 139 + * NATed TCP connections (like the PORT XXX,XXX,XXX,XXX,XXX,XXX 140 + * command in FTP). 141 + * 142 + * Takes care about all the nasty sequence number changes, checksumming, 143 + * skb enlargement, ... 144 + * 145 + * */ 146 + int 147 + nf_nat_mangle_tcp_packet(struct sk_buff **pskb, 148 + struct nf_conn *ct, 149 + enum ip_conntrack_info ctinfo, 150 + unsigned int match_offset, 151 + unsigned int match_len, 152 + const char *rep_buffer, 153 + unsigned int rep_len) 154 + { 155 + struct iphdr *iph; 156 + struct tcphdr *tcph; 157 + int oldlen, datalen; 158 + 159 + if (!skb_make_writable(pskb, (*pskb)->len)) 160 + return 0; 161 + 162 + if (rep_len > match_len && 163 + rep_len - match_len > skb_tailroom(*pskb) && 164 + !enlarge_skb(pskb, rep_len - match_len)) 165 + return 0; 166 + 167 + SKB_LINEAR_ASSERT(*pskb); 168 + 169 + iph = (*pskb)->nh.iph; 170 + tcph = (void *)iph + iph->ihl*4; 171 + 172 + oldlen = (*pskb)->len - iph->ihl*4; 173 + mangle_contents(*pskb, iph->ihl*4 + tcph->doff*4, 174 + match_offset, match_len, rep_buffer, rep_len); 175 + 176 + datalen = (*pskb)->len - iph->ihl*4; 177 + if ((*pskb)->ip_summed != CHECKSUM_PARTIAL) { 178 + tcph->check = 0; 179 + tcph->check = tcp_v4_check(tcph, datalen, 180 + iph->saddr, iph->daddr, 181 + csum_partial((char *)tcph, 182 + datalen, 0)); 183 + } else 184 + nf_proto_csum_replace2(&tcph->check, *pskb, 185 + htons(oldlen), htons(datalen), 1); 186 + 187 + if (rep_len != match_len) { 188 + set_bit(IPS_SEQ_ADJUST_BIT, &ct->status); 189 + adjust_tcp_sequence(ntohl(tcph->seq), 190 + (int)rep_len - (int)match_len, 191 + ct, ctinfo); 192 + /* Tell TCP window tracking about seq change */ 193 + nf_conntrack_tcp_update(*pskb, (*pskb)->nh.iph->ihl*4, 194 + ct, CTINFO2DIR(ctinfo)); 195 + } 196 + return 1; 197 + } 198 + EXPORT_SYMBOL(nf_nat_mangle_tcp_packet); 199 + 200 + /* Generic function for mangling variable-length address changes inside 201 + * NATed UDP connections (like the CONNECT DATA XXXXX MESG XXXXX INDEX XXXXX 202 + * command in the Amanda protocol) 203 + * 204 + * Takes care about all the nasty sequence number changes, checksumming, 205 + * skb enlargement, ... 206 + * 207 + * XXX - This function could be merged with nf_nat_mangle_tcp_packet which 208 + * should be fairly easy to do. 209 + */ 210 + int 211 + nf_nat_mangle_udp_packet(struct sk_buff **pskb, 212 + struct nf_conn *ct, 213 + enum ip_conntrack_info ctinfo, 214 + unsigned int match_offset, 215 + unsigned int match_len, 216 + const char *rep_buffer, 217 + unsigned int rep_len) 218 + { 219 + struct iphdr *iph; 220 + struct udphdr *udph; 221 + int datalen, oldlen; 222 + 223 + /* UDP helpers might accidentally mangle the wrong packet */ 224 + iph = (*pskb)->nh.iph; 225 + if ((*pskb)->len < iph->ihl*4 + sizeof(*udph) + 226 + match_offset + match_len) 227 + return 0; 228 + 229 + if (!skb_make_writable(pskb, (*pskb)->len)) 230 + return 0; 231 + 232 + if (rep_len > match_len && 233 + rep_len - match_len > skb_tailroom(*pskb) && 234 + !enlarge_skb(pskb, rep_len - match_len)) 235 + return 0; 236 + 237 + iph = (*pskb)->nh.iph; 238 + udph = (void *)iph + iph->ihl*4; 239 + 240 + oldlen = (*pskb)->len - iph->ihl*4; 241 + mangle_contents(*pskb, iph->ihl*4 + sizeof(*udph), 242 + match_offset, match_len, rep_buffer, rep_len); 243 + 244 + /* update the length of the UDP packet */ 245 + datalen = (*pskb)->len - iph->ihl*4; 246 + udph->len = htons(datalen); 247 + 248 + /* fix udp checksum if udp checksum was previously calculated */ 249 + if (!udph->check && (*pskb)->ip_summed != CHECKSUM_PARTIAL) 250 + return 1; 251 + 252 + if ((*pskb)->ip_summed != CHECKSUM_PARTIAL) { 253 + udph->check = 0; 254 + udph->check = csum_tcpudp_magic(iph->saddr, iph->daddr, 255 + datalen, IPPROTO_UDP, 256 + csum_partial((char *)udph, 257 + datalen, 0)); 258 + if (!udph->check) 259 + udph->check = CSUM_MANGLED_0; 260 + } else 261 + nf_proto_csum_replace2(&udph->check, *pskb, 262 + htons(oldlen), htons(datalen), 1); 263 + 264 + return 1; 265 + } 266 + EXPORT_SYMBOL(nf_nat_mangle_udp_packet); 267 + 268 + /* Adjust one found SACK option including checksum correction */ 269 + static void 270 + sack_adjust(struct sk_buff *skb, 271 + struct tcphdr *tcph, 272 + unsigned int sackoff, 273 + unsigned int sackend, 274 + struct nf_nat_seq *natseq) 275 + { 276 + while (sackoff < sackend) { 277 + struct tcp_sack_block_wire *sack; 278 + __be32 new_start_seq, new_end_seq; 279 + 280 + sack = (void *)skb->data + sackoff; 281 + if (after(ntohl(sack->start_seq) - natseq->offset_before, 282 + natseq->correction_pos)) 283 + new_start_seq = htonl(ntohl(sack->start_seq) 284 + - natseq->offset_after); 285 + else 286 + new_start_seq = htonl(ntohl(sack->start_seq) 287 + - natseq->offset_before); 288 + 289 + if (after(ntohl(sack->end_seq) - natseq->offset_before, 290 + natseq->correction_pos)) 291 + new_end_seq = htonl(ntohl(sack->end_seq) 292 + - natseq->offset_after); 293 + else 294 + new_end_seq = htonl(ntohl(sack->end_seq) 295 + - natseq->offset_before); 296 + 297 + DEBUGP("sack_adjust: start_seq: %d->%d, end_seq: %d->%d\n", 298 + ntohl(sack->start_seq), new_start_seq, 299 + ntohl(sack->end_seq), new_end_seq); 300 + 301 + nf_proto_csum_replace4(&tcph->check, skb, 302 + sack->start_seq, new_start_seq, 0); 303 + nf_proto_csum_replace4(&tcph->check, skb, 304 + sack->end_seq, new_end_seq, 0); 305 + sack->start_seq = new_start_seq; 306 + sack->end_seq = new_end_seq; 307 + sackoff += sizeof(*sack); 308 + } 309 + } 310 + 311 + /* TCP SACK sequence number adjustment */ 312 + static inline unsigned int 313 + nf_nat_sack_adjust(struct sk_buff **pskb, 314 + struct tcphdr *tcph, 315 + struct nf_conn *ct, 316 + enum ip_conntrack_info ctinfo) 317 + { 318 + unsigned int dir, optoff, optend; 319 + struct nf_conn_nat *nat = nfct_nat(ct); 320 + 321 + optoff = (*pskb)->nh.iph->ihl*4 + sizeof(struct tcphdr); 322 + optend = (*pskb)->nh.iph->ihl*4 + tcph->doff*4; 323 + 324 + if (!skb_make_writable(pskb, optend)) 325 + return 0; 326 + 327 + dir = CTINFO2DIR(ctinfo); 328 + 329 + while (optoff < optend) { 330 + /* Usually: option, length. */ 331 + unsigned char *op = (*pskb)->data + optoff; 332 + 333 + switch (op[0]) { 334 + case TCPOPT_EOL: 335 + return 1; 336 + case TCPOPT_NOP: 337 + optoff++; 338 + continue; 339 + default: 340 + /* no partial options */ 341 + if (optoff + 1 == optend || 342 + optoff + op[1] > optend || 343 + op[1] < 2) 344 + return 0; 345 + if (op[0] == TCPOPT_SACK && 346 + op[1] >= 2+TCPOLEN_SACK_PERBLOCK && 347 + ((op[1] - 2) % TCPOLEN_SACK_PERBLOCK) == 0) 348 + sack_adjust(*pskb, tcph, optoff+2, 349 + optoff+op[1], 350 + &nat->info.seq[!dir]); 351 + optoff += op[1]; 352 + } 353 + } 354 + return 1; 355 + } 356 + 357 + /* TCP sequence number adjustment. Returns 1 on success, 0 on failure */ 358 + int 359 + nf_nat_seq_adjust(struct sk_buff **pskb, 360 + struct nf_conn *ct, 361 + enum ip_conntrack_info ctinfo) 362 + { 363 + struct tcphdr *tcph; 364 + int dir; 365 + __be32 newseq, newack; 366 + struct nf_conn_nat *nat = nfct_nat(ct); 367 + struct nf_nat_seq *this_way, *other_way; 368 + 369 + dir = CTINFO2DIR(ctinfo); 370 + 371 + this_way = &nat->info.seq[dir]; 372 + other_way = &nat->info.seq[!dir]; 373 + 374 + if (!skb_make_writable(pskb, (*pskb)->nh.iph->ihl*4+sizeof(*tcph))) 375 + return 0; 376 + 377 + tcph = (void *)(*pskb)->data + (*pskb)->nh.iph->ihl*4; 378 + if (after(ntohl(tcph->seq), this_way->correction_pos)) 379 + newseq = htonl(ntohl(tcph->seq) + this_way->offset_after); 380 + else 381 + newseq = htonl(ntohl(tcph->seq) + this_way->offset_before); 382 + 383 + if (after(ntohl(tcph->ack_seq) - other_way->offset_before, 384 + other_way->correction_pos)) 385 + newack = htonl(ntohl(tcph->ack_seq) - other_way->offset_after); 386 + else 387 + newack = htonl(ntohl(tcph->ack_seq) - other_way->offset_before); 388 + 389 + nf_proto_csum_replace4(&tcph->check, *pskb, tcph->seq, newseq, 0); 390 + nf_proto_csum_replace4(&tcph->check, *pskb, tcph->ack_seq, newack, 0); 391 + 392 + DEBUGP("Adjusting sequence number from %u->%u, ack from %u->%u\n", 393 + ntohl(tcph->seq), ntohl(newseq), ntohl(tcph->ack_seq), 394 + ntohl(newack)); 395 + 396 + tcph->seq = newseq; 397 + tcph->ack_seq = newack; 398 + 399 + if (!nf_nat_sack_adjust(pskb, tcph, ct, ctinfo)) 400 + return 0; 401 + 402 + nf_conntrack_tcp_update(*pskb, (*pskb)->nh.iph->ihl*4, ct, dir); 403 + 404 + return 1; 405 + } 406 + EXPORT_SYMBOL(nf_nat_seq_adjust); 407 + 408 + /* Setup NAT on this expected conntrack so it follows master. */ 409 + /* If we fail to get a free NAT slot, we'll get dropped on confirm */ 410 + void nf_nat_follow_master(struct nf_conn *ct, 411 + struct nf_conntrack_expect *exp) 412 + { 413 + struct nf_nat_range range; 414 + 415 + /* This must be a fresh one. */ 416 + BUG_ON(ct->status & IPS_NAT_DONE_MASK); 417 + 418 + /* Change src to where master sends to */ 419 + range.flags = IP_NAT_RANGE_MAP_IPS; 420 + range.min_ip = range.max_ip 421 + = ct->master->tuplehash[!exp->dir].tuple.dst.u3.ip; 422 + /* hook doesn't matter, but it has to do source manip */ 423 + nf_nat_setup_info(ct, &range, NF_IP_POST_ROUTING); 424 + 425 + /* For DST manip, map port here to where it's expected. */ 426 + range.flags = (IP_NAT_RANGE_MAP_IPS | IP_NAT_RANGE_PROTO_SPECIFIED); 427 + range.min = range.max = exp->saved_proto; 428 + range.min_ip = range.max_ip 429 + = ct->master->tuplehash[!exp->dir].tuple.src.u3.ip; 430 + /* hook doesn't matter, but it has to do destination manip */ 431 + nf_nat_setup_info(ct, &range, NF_IP_PRE_ROUTING); 432 + } 433 + EXPORT_SYMBOL(nf_nat_follow_master);
+86
net/ipv4/netfilter/nf_nat_proto_icmp.c
··· 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 + #include <linux/types.h> 10 + #include <linux/init.h> 11 + #include <linux/ip.h> 12 + #include <linux/icmp.h> 13 + 14 + #include <linux/netfilter.h> 15 + #include <net/netfilter/nf_nat.h> 16 + #include <net/netfilter/nf_nat_core.h> 17 + #include <net/netfilter/nf_nat_rule.h> 18 + #include <net/netfilter/nf_nat_protocol.h> 19 + 20 + static int 21 + icmp_in_range(const struct nf_conntrack_tuple *tuple, 22 + enum nf_nat_manip_type maniptype, 23 + const union nf_conntrack_man_proto *min, 24 + const union nf_conntrack_man_proto *max) 25 + { 26 + return ntohs(tuple->src.u.icmp.id) >= ntohs(min->icmp.id) && 27 + ntohs(tuple->src.u.icmp.id) <= ntohs(max->icmp.id); 28 + } 29 + 30 + static int 31 + icmp_unique_tuple(struct nf_conntrack_tuple *tuple, 32 + const struct nf_nat_range *range, 33 + enum nf_nat_manip_type maniptype, 34 + const struct nf_conn *ct) 35 + { 36 + static u_int16_t id; 37 + unsigned int range_size; 38 + unsigned int i; 39 + 40 + range_size = ntohs(range->max.icmp.id) - ntohs(range->min.icmp.id) + 1; 41 + /* If no range specified... */ 42 + if (!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED)) 43 + range_size = 0xFFFF; 44 + 45 + for (i = 0; i < range_size; i++, id++) { 46 + tuple->src.u.icmp.id = htons(ntohs(range->min.icmp.id) + 47 + (id % range_size)); 48 + if (!nf_nat_used_tuple(tuple, ct)) 49 + return 1; 50 + } 51 + return 0; 52 + } 53 + 54 + static int 55 + icmp_manip_pkt(struct sk_buff **pskb, 56 + unsigned int iphdroff, 57 + const struct nf_conntrack_tuple *tuple, 58 + enum nf_nat_manip_type maniptype) 59 + { 60 + struct iphdr *iph = (struct iphdr *)((*pskb)->data + iphdroff); 61 + struct icmphdr *hdr; 62 + unsigned int hdroff = iphdroff + iph->ihl*4; 63 + 64 + if (!skb_make_writable(pskb, hdroff + sizeof(*hdr))) 65 + return 0; 66 + 67 + hdr = (struct icmphdr *)((*pskb)->data + hdroff); 68 + nf_proto_csum_replace2(&hdr->checksum, *pskb, 69 + hdr->un.echo.id, tuple->src.u.icmp.id, 0); 70 + hdr->un.echo.id = tuple->src.u.icmp.id; 71 + return 1; 72 + } 73 + 74 + struct nf_nat_protocol nf_nat_protocol_icmp = { 75 + .name = "ICMP", 76 + .protonum = IPPROTO_ICMP, 77 + .me = THIS_MODULE, 78 + .manip_pkt = icmp_manip_pkt, 79 + .in_range = icmp_in_range, 80 + .unique_tuple = icmp_unique_tuple, 81 + #if defined(CONFIG_IP_NF_CONNTRACK_NETLINK) || \ 82 + defined(CONFIG_IP_NF_CONNTRACK_NETLINK_MODULE) 83 + .range_to_nfattr = nf_nat_port_range_to_nfattr, 84 + .nfattr_to_range = nf_nat_port_nfattr_to_range, 85 + #endif 86 + };
+148
net/ipv4/netfilter/nf_nat_proto_tcp.c
··· 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 + #include <linux/types.h> 10 + #include <linux/init.h> 11 + #include <linux/ip.h> 12 + #include <linux/tcp.h> 13 + 14 + #include <linux/netfilter.h> 15 + #include <linux/netfilter/nfnetlink_conntrack.h> 16 + #include <net/netfilter/nf_nat.h> 17 + #include <net/netfilter/nf_nat_rule.h> 18 + #include <net/netfilter/nf_nat_protocol.h> 19 + #include <net/netfilter/nf_nat_core.h> 20 + 21 + static int 22 + tcp_in_range(const struct nf_conntrack_tuple *tuple, 23 + enum nf_nat_manip_type maniptype, 24 + const union nf_conntrack_man_proto *min, 25 + const union nf_conntrack_man_proto *max) 26 + { 27 + __be16 port; 28 + 29 + if (maniptype == IP_NAT_MANIP_SRC) 30 + port = tuple->src.u.tcp.port; 31 + else 32 + port = tuple->dst.u.tcp.port; 33 + 34 + return ntohs(port) >= ntohs(min->tcp.port) && 35 + ntohs(port) <= ntohs(max->tcp.port); 36 + } 37 + 38 + static int 39 + tcp_unique_tuple(struct nf_conntrack_tuple *tuple, 40 + const struct nf_nat_range *range, 41 + enum nf_nat_manip_type maniptype, 42 + const struct nf_conn *ct) 43 + { 44 + static u_int16_t port; 45 + __be16 *portptr; 46 + unsigned int range_size, min, i; 47 + 48 + if (maniptype == IP_NAT_MANIP_SRC) 49 + portptr = &tuple->src.u.tcp.port; 50 + else 51 + portptr = &tuple->dst.u.tcp.port; 52 + 53 + /* If no range specified... */ 54 + if (!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED)) { 55 + /* If it's dst rewrite, can't change port */ 56 + if (maniptype == IP_NAT_MANIP_DST) 57 + return 0; 58 + 59 + /* Map privileged onto privileged. */ 60 + if (ntohs(*portptr) < 1024) { 61 + /* Loose convention: >> 512 is credential passing */ 62 + if (ntohs(*portptr)<512) { 63 + min = 1; 64 + range_size = 511 - min + 1; 65 + } else { 66 + min = 600; 67 + range_size = 1023 - min + 1; 68 + } 69 + } else { 70 + min = 1024; 71 + range_size = 65535 - 1024 + 1; 72 + } 73 + } else { 74 + min = ntohs(range->min.tcp.port); 75 + range_size = ntohs(range->max.tcp.port) - min + 1; 76 + } 77 + 78 + for (i = 0; i < range_size; i++, port++) { 79 + *portptr = htons(min + port % range_size); 80 + if (!nf_nat_used_tuple(tuple, ct)) 81 + return 1; 82 + } 83 + return 0; 84 + } 85 + 86 + static int 87 + tcp_manip_pkt(struct sk_buff **pskb, 88 + unsigned int iphdroff, 89 + const struct nf_conntrack_tuple *tuple, 90 + enum nf_nat_manip_type maniptype) 91 + { 92 + struct iphdr *iph = (struct iphdr *)((*pskb)->data + iphdroff); 93 + struct tcphdr *hdr; 94 + unsigned int hdroff = iphdroff + iph->ihl*4; 95 + __be32 oldip, newip; 96 + __be16 *portptr, newport, oldport; 97 + int hdrsize = 8; /* TCP connection tracking guarantees this much */ 98 + 99 + /* this could be a inner header returned in icmp packet; in such 100 + cases we cannot update the checksum field since it is outside of 101 + the 8 bytes of transport layer headers we are guaranteed */ 102 + if ((*pskb)->len >= hdroff + sizeof(struct tcphdr)) 103 + hdrsize = sizeof(struct tcphdr); 104 + 105 + if (!skb_make_writable(pskb, hdroff + hdrsize)) 106 + return 0; 107 + 108 + iph = (struct iphdr *)((*pskb)->data + iphdroff); 109 + hdr = (struct tcphdr *)((*pskb)->data + hdroff); 110 + 111 + if (maniptype == IP_NAT_MANIP_SRC) { 112 + /* Get rid of src ip and src pt */ 113 + oldip = iph->saddr; 114 + newip = tuple->src.u3.ip; 115 + newport = tuple->src.u.tcp.port; 116 + portptr = &hdr->source; 117 + } else { 118 + /* Get rid of dst ip and dst pt */ 119 + oldip = iph->daddr; 120 + newip = tuple->dst.u3.ip; 121 + newport = tuple->dst.u.tcp.port; 122 + portptr = &hdr->dest; 123 + } 124 + 125 + oldport = *portptr; 126 + *portptr = newport; 127 + 128 + if (hdrsize < sizeof(*hdr)) 129 + return 1; 130 + 131 + nf_proto_csum_replace4(&hdr->check, *pskb, oldip, newip, 1); 132 + nf_proto_csum_replace2(&hdr->check, *pskb, oldport, newport, 0); 133 + return 1; 134 + } 135 + 136 + struct nf_nat_protocol nf_nat_protocol_tcp = { 137 + .name = "TCP", 138 + .protonum = IPPROTO_TCP, 139 + .me = THIS_MODULE, 140 + .manip_pkt = tcp_manip_pkt, 141 + .in_range = tcp_in_range, 142 + .unique_tuple = tcp_unique_tuple, 143 + #if defined(CONFIG_IP_NF_CONNTRACK_NETLINK) || \ 144 + defined(CONFIG_IP_NF_CONNTRACK_NETLINK_MODULE) 145 + .range_to_nfattr = nf_nat_port_range_to_nfattr, 146 + .nfattr_to_range = nf_nat_port_nfattr_to_range, 147 + #endif 148 + };
+138
net/ipv4/netfilter/nf_nat_proto_udp.c
··· 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 + #include <linux/types.h> 10 + #include <linux/init.h> 11 + #include <linux/ip.h> 12 + #include <linux/udp.h> 13 + 14 + #include <linux/netfilter.h> 15 + #include <net/netfilter/nf_nat.h> 16 + #include <net/netfilter/nf_nat_core.h> 17 + #include <net/netfilter/nf_nat_rule.h> 18 + #include <net/netfilter/nf_nat_protocol.h> 19 + 20 + static int 21 + udp_in_range(const struct nf_conntrack_tuple *tuple, 22 + enum nf_nat_manip_type maniptype, 23 + const union nf_conntrack_man_proto *min, 24 + const union nf_conntrack_man_proto *max) 25 + { 26 + __be16 port; 27 + 28 + if (maniptype == IP_NAT_MANIP_SRC) 29 + port = tuple->src.u.udp.port; 30 + else 31 + port = tuple->dst.u.udp.port; 32 + 33 + return ntohs(port) >= ntohs(min->udp.port) && 34 + ntohs(port) <= ntohs(max->udp.port); 35 + } 36 + 37 + static int 38 + udp_unique_tuple(struct nf_conntrack_tuple *tuple, 39 + const struct nf_nat_range *range, 40 + enum nf_nat_manip_type maniptype, 41 + const struct nf_conn *ct) 42 + { 43 + static u_int16_t port; 44 + __be16 *portptr; 45 + unsigned int range_size, min, i; 46 + 47 + if (maniptype == IP_NAT_MANIP_SRC) 48 + portptr = &tuple->src.u.udp.port; 49 + else 50 + portptr = &tuple->dst.u.udp.port; 51 + 52 + /* If no range specified... */ 53 + if (!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED)) { 54 + /* If it's dst rewrite, can't change port */ 55 + if (maniptype == IP_NAT_MANIP_DST) 56 + return 0; 57 + 58 + if (ntohs(*portptr) < 1024) { 59 + /* Loose convention: >> 512 is credential passing */ 60 + if (ntohs(*portptr)<512) { 61 + min = 1; 62 + range_size = 511 - min + 1; 63 + } else { 64 + min = 600; 65 + range_size = 1023 - min + 1; 66 + } 67 + } else { 68 + min = 1024; 69 + range_size = 65535 - 1024 + 1; 70 + } 71 + } else { 72 + min = ntohs(range->min.udp.port); 73 + range_size = ntohs(range->max.udp.port) - min + 1; 74 + } 75 + 76 + for (i = 0; i < range_size; i++, port++) { 77 + *portptr = htons(min + port % range_size); 78 + if (!nf_nat_used_tuple(tuple, ct)) 79 + return 1; 80 + } 81 + return 0; 82 + } 83 + 84 + static int 85 + udp_manip_pkt(struct sk_buff **pskb, 86 + unsigned int iphdroff, 87 + const struct nf_conntrack_tuple *tuple, 88 + enum nf_nat_manip_type maniptype) 89 + { 90 + struct iphdr *iph = (struct iphdr *)((*pskb)->data + iphdroff); 91 + struct udphdr *hdr; 92 + unsigned int hdroff = iphdroff + iph->ihl*4; 93 + __be32 oldip, newip; 94 + __be16 *portptr, newport; 95 + 96 + if (!skb_make_writable(pskb, hdroff + sizeof(*hdr))) 97 + return 0; 98 + 99 + iph = (struct iphdr *)((*pskb)->data + iphdroff); 100 + hdr = (struct udphdr *)((*pskb)->data + hdroff); 101 + 102 + if (maniptype == IP_NAT_MANIP_SRC) { 103 + /* Get rid of src ip and src pt */ 104 + oldip = iph->saddr; 105 + newip = tuple->src.u3.ip; 106 + newport = tuple->src.u.udp.port; 107 + portptr = &hdr->source; 108 + } else { 109 + /* Get rid of dst ip and dst pt */ 110 + oldip = iph->daddr; 111 + newip = tuple->dst.u3.ip; 112 + newport = tuple->dst.u.udp.port; 113 + portptr = &hdr->dest; 114 + } 115 + if (hdr->check || (*pskb)->ip_summed == CHECKSUM_PARTIAL) { 116 + nf_proto_csum_replace4(&hdr->check, *pskb, oldip, newip, 1); 117 + nf_proto_csum_replace2(&hdr->check, *pskb, *portptr, newport, 118 + 0); 119 + if (!hdr->check) 120 + hdr->check = CSUM_MANGLED_0; 121 + } 122 + *portptr = newport; 123 + return 1; 124 + } 125 + 126 + struct nf_nat_protocol nf_nat_protocol_udp = { 127 + .name = "UDP", 128 + .protonum = IPPROTO_UDP, 129 + .me = THIS_MODULE, 130 + .manip_pkt = udp_manip_pkt, 131 + .in_range = udp_in_range, 132 + .unique_tuple = udp_unique_tuple, 133 + #if defined(CONFIG_IP_NF_CONNTRACK_NETLINK) || \ 134 + defined(CONFIG_IP_NF_CONNTRACK_NETLINK_MODULE) 135 + .range_to_nfattr = nf_nat_port_range_to_nfattr, 136 + .nfattr_to_range = nf_nat_port_nfattr_to_range, 137 + #endif 138 + };
+54
net/ipv4/netfilter/nf_nat_proto_unknown.c
··· 1 + /* The "unknown" protocol. This is what is used for protocols we 2 + * don't understand. It's returned by ip_ct_find_proto(). 3 + */ 4 + 5 + /* (C) 1999-2001 Paul `Rusty' Russell 6 + * (C) 2002-2006 Netfilter Core Team <coreteam@netfilter.org> 7 + * 8 + * This program is free software; you can redistribute it and/or modify 9 + * it under the terms of the GNU General Public License version 2 as 10 + * published by the Free Software Foundation. 11 + */ 12 + 13 + #include <linux/types.h> 14 + #include <linux/init.h> 15 + 16 + #include <linux/netfilter.h> 17 + #include <net/netfilter/nf_nat.h> 18 + #include <net/netfilter/nf_nat_rule.h> 19 + #include <net/netfilter/nf_nat_protocol.h> 20 + 21 + static int unknown_in_range(const struct nf_conntrack_tuple *tuple, 22 + enum nf_nat_manip_type manip_type, 23 + const union nf_conntrack_man_proto *min, 24 + const union nf_conntrack_man_proto *max) 25 + { 26 + return 1; 27 + } 28 + 29 + static int unknown_unique_tuple(struct nf_conntrack_tuple *tuple, 30 + const struct nf_nat_range *range, 31 + enum nf_nat_manip_type maniptype, 32 + const struct nf_conn *ct) 33 + { 34 + /* Sorry: we can't help you; if it's not unique, we can't frob 35 + anything. */ 36 + return 0; 37 + } 38 + 39 + static int 40 + unknown_manip_pkt(struct sk_buff **pskb, 41 + unsigned int iphdroff, 42 + const struct nf_conntrack_tuple *tuple, 43 + enum nf_nat_manip_type maniptype) 44 + { 45 + return 1; 46 + } 47 + 48 + struct nf_nat_protocol nf_nat_unknown_protocol = { 49 + .name = "unknown", 50 + /* .me isn't set: getting a ref to this cannot fail. */ 51 + .manip_pkt = unknown_manip_pkt, 52 + .in_range = unknown_in_range, 53 + .unique_tuple = unknown_unique_tuple, 54 + };
+343
net/ipv4/netfilter/nf_nat_rule.c
··· 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 + #include <linux/types.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/kmod.h> 16 + #include <linux/skbuff.h> 17 + #include <linux/proc_fs.h> 18 + #include <net/checksum.h> 19 + #include <net/route.h> 20 + #include <linux/bitops.h> 21 + 22 + #include <linux/netfilter_ipv4/ip_tables.h> 23 + #include <net/netfilter/nf_nat.h> 24 + #include <net/netfilter/nf_nat_core.h> 25 + #include <net/netfilter/nf_nat_rule.h> 26 + 27 + #if 0 28 + #define DEBUGP printk 29 + #else 30 + #define DEBUGP(format, args...) 31 + #endif 32 + 33 + #define NAT_VALID_HOOKS ((1<<NF_IP_PRE_ROUTING) | (1<<NF_IP_POST_ROUTING) | (1<<NF_IP_LOCAL_OUT)) 34 + 35 + static struct 36 + { 37 + struct ipt_replace repl; 38 + struct ipt_standard entries[3]; 39 + struct ipt_error term; 40 + } nat_initial_table __initdata = { 41 + .repl = { 42 + .name = "nat", 43 + .valid_hooks = NAT_VALID_HOOKS, 44 + .num_entries = 4, 45 + .size = sizeof(struct ipt_standard) * 3 + sizeof(struct ipt_error), 46 + .hook_entry = { 47 + [NF_IP_PRE_ROUTING] = 0, 48 + [NF_IP_POST_ROUTING] = sizeof(struct ipt_standard), 49 + [NF_IP_LOCAL_OUT] = sizeof(struct ipt_standard) * 2 }, 50 + .underflow = { 51 + [NF_IP_PRE_ROUTING] = 0, 52 + [NF_IP_POST_ROUTING] = sizeof(struct ipt_standard), 53 + [NF_IP_LOCAL_OUT] = sizeof(struct ipt_standard) * 2 }, 54 + }, 55 + .entries = { 56 + /* PRE_ROUTING */ 57 + { 58 + .entry = { 59 + .target_offset = sizeof(struct ipt_entry), 60 + .next_offset = sizeof(struct ipt_standard), 61 + }, 62 + .target = { 63 + .target = { 64 + .u = { 65 + .target_size = IPT_ALIGN(sizeof(struct ipt_standard_target)), 66 + }, 67 + }, 68 + .verdict = -NF_ACCEPT - 1, 69 + }, 70 + }, 71 + /* POST_ROUTING */ 72 + { 73 + .entry = { 74 + .target_offset = sizeof(struct ipt_entry), 75 + .next_offset = sizeof(struct ipt_standard), 76 + }, 77 + .target = { 78 + .target = { 79 + .u = { 80 + .target_size = IPT_ALIGN(sizeof(struct ipt_standard_target)), 81 + }, 82 + }, 83 + .verdict = -NF_ACCEPT - 1, 84 + }, 85 + }, 86 + /* LOCAL_OUT */ 87 + { 88 + .entry = { 89 + .target_offset = sizeof(struct ipt_entry), 90 + .next_offset = sizeof(struct ipt_standard), 91 + }, 92 + .target = { 93 + .target = { 94 + .u = { 95 + .target_size = IPT_ALIGN(sizeof(struct ipt_standard_target)), 96 + }, 97 + }, 98 + .verdict = -NF_ACCEPT - 1, 99 + }, 100 + }, 101 + }, 102 + /* ERROR */ 103 + .term = { 104 + .entry = { 105 + .target_offset = sizeof(struct ipt_entry), 106 + .next_offset = sizeof(struct ipt_error), 107 + }, 108 + .target = { 109 + .target = { 110 + .u = { 111 + .user = { 112 + .target_size = IPT_ALIGN(sizeof(struct ipt_error_target)), 113 + .name = IPT_ERROR_TARGET, 114 + }, 115 + }, 116 + }, 117 + .errorname = "ERROR", 118 + }, 119 + } 120 + }; 121 + 122 + static struct ipt_table nat_table = { 123 + .name = "nat", 124 + .valid_hooks = NAT_VALID_HOOKS, 125 + .lock = RW_LOCK_UNLOCKED, 126 + .me = THIS_MODULE, 127 + .af = AF_INET, 128 + }; 129 + 130 + /* Source NAT */ 131 + static unsigned int ipt_snat_target(struct sk_buff **pskb, 132 + const struct net_device *in, 133 + const struct net_device *out, 134 + unsigned int hooknum, 135 + const struct xt_target *target, 136 + const void *targinfo) 137 + { 138 + struct nf_conn *ct; 139 + enum ip_conntrack_info ctinfo; 140 + const struct nf_nat_multi_range_compat *mr = targinfo; 141 + 142 + NF_CT_ASSERT(hooknum == NF_IP_POST_ROUTING); 143 + 144 + ct = nf_ct_get(*pskb, &ctinfo); 145 + 146 + /* Connection must be valid and new. */ 147 + NF_CT_ASSERT(ct && (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED || 148 + ctinfo == IP_CT_RELATED + IP_CT_IS_REPLY)); 149 + NF_CT_ASSERT(out); 150 + 151 + return nf_nat_setup_info(ct, &mr->range[0], hooknum); 152 + } 153 + 154 + /* Before 2.6.11 we did implicit source NAT if required. Warn about change. */ 155 + static void warn_if_extra_mangle(__be32 dstip, __be32 srcip) 156 + { 157 + static int warned = 0; 158 + struct flowi fl = { .nl_u = { .ip4_u = { .daddr = dstip } } }; 159 + struct rtable *rt; 160 + 161 + if (ip_route_output_key(&rt, &fl) != 0) 162 + return; 163 + 164 + if (rt->rt_src != srcip && !warned) { 165 + printk("NAT: no longer support implicit source local NAT\n"); 166 + printk("NAT: packet src %u.%u.%u.%u -> dst %u.%u.%u.%u\n", 167 + NIPQUAD(srcip), NIPQUAD(dstip)); 168 + warned = 1; 169 + } 170 + ip_rt_put(rt); 171 + } 172 + 173 + static unsigned int ipt_dnat_target(struct sk_buff **pskb, 174 + const struct net_device *in, 175 + const struct net_device *out, 176 + unsigned int hooknum, 177 + const struct xt_target *target, 178 + const void *targinfo) 179 + { 180 + struct nf_conn *ct; 181 + enum ip_conntrack_info ctinfo; 182 + const struct nf_nat_multi_range_compat *mr = targinfo; 183 + 184 + NF_CT_ASSERT(hooknum == NF_IP_PRE_ROUTING || 185 + hooknum == NF_IP_LOCAL_OUT); 186 + 187 + ct = nf_ct_get(*pskb, &ctinfo); 188 + 189 + /* Connection must be valid and new. */ 190 + NF_CT_ASSERT(ct && (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED)); 191 + 192 + if (hooknum == NF_IP_LOCAL_OUT && 193 + mr->range[0].flags & IP_NAT_RANGE_MAP_IPS) 194 + warn_if_extra_mangle((*pskb)->nh.iph->daddr, 195 + mr->range[0].min_ip); 196 + 197 + return nf_nat_setup_info(ct, &mr->range[0], hooknum); 198 + } 199 + 200 + static int ipt_snat_checkentry(const char *tablename, 201 + const void *entry, 202 + const struct xt_target *target, 203 + void *targinfo, 204 + unsigned int hook_mask) 205 + { 206 + struct nf_nat_multi_range_compat *mr = targinfo; 207 + 208 + /* Must be a valid range */ 209 + if (mr->rangesize != 1) { 210 + printk("SNAT: multiple ranges no longer supported\n"); 211 + return 0; 212 + } 213 + return 1; 214 + } 215 + 216 + static int ipt_dnat_checkentry(const char *tablename, 217 + const void *entry, 218 + const struct xt_target *target, 219 + void *targinfo, 220 + unsigned int hook_mask) 221 + { 222 + struct nf_nat_multi_range_compat *mr = targinfo; 223 + 224 + /* Must be a valid range */ 225 + if (mr->rangesize != 1) { 226 + printk("DNAT: multiple ranges no longer supported\n"); 227 + return 0; 228 + } 229 + return 1; 230 + } 231 + 232 + inline unsigned int 233 + alloc_null_binding(struct nf_conn *ct, 234 + struct nf_nat_info *info, 235 + unsigned int hooknum) 236 + { 237 + /* Force range to this IP; let proto decide mapping for 238 + per-proto parts (hence not IP_NAT_RANGE_PROTO_SPECIFIED). 239 + Use reply in case it's already been mangled (eg local packet). 240 + */ 241 + __be32 ip 242 + = (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC 243 + ? ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3.ip 244 + : ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u3.ip); 245 + struct nf_nat_range range 246 + = { IP_NAT_RANGE_MAP_IPS, ip, ip, { 0 }, { 0 } }; 247 + 248 + DEBUGP("Allocating NULL binding for %p (%u.%u.%u.%u)\n", 249 + ct, NIPQUAD(ip)); 250 + return nf_nat_setup_info(ct, &range, hooknum); 251 + } 252 + 253 + unsigned int 254 + alloc_null_binding_confirmed(struct nf_conn *ct, 255 + struct nf_nat_info *info, 256 + unsigned int hooknum) 257 + { 258 + __be32 ip 259 + = (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC 260 + ? ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3.ip 261 + : ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u3.ip); 262 + u_int16_t all 263 + = (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC 264 + ? ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.all 265 + : ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u.all); 266 + struct nf_nat_range range 267 + = { IP_NAT_RANGE_MAP_IPS, ip, ip, { all }, { all } }; 268 + 269 + DEBUGP("Allocating NULL binding for confirmed %p (%u.%u.%u.%u)\n", 270 + ct, NIPQUAD(ip)); 271 + return nf_nat_setup_info(ct, &range, hooknum); 272 + } 273 + 274 + int nf_nat_rule_find(struct sk_buff **pskb, 275 + unsigned int hooknum, 276 + const struct net_device *in, 277 + const struct net_device *out, 278 + struct nf_conn *ct, 279 + struct nf_nat_info *info) 280 + { 281 + int ret; 282 + 283 + ret = ipt_do_table(pskb, hooknum, in, out, &nat_table); 284 + 285 + if (ret == NF_ACCEPT) { 286 + if (!nf_nat_initialized(ct, HOOK2MANIP(hooknum))) 287 + /* NUL mapping */ 288 + ret = alloc_null_binding(ct, info, hooknum); 289 + } 290 + return ret; 291 + } 292 + 293 + static struct ipt_target ipt_snat_reg = { 294 + .name = "SNAT", 295 + .target = ipt_snat_target, 296 + .targetsize = sizeof(struct nf_nat_multi_range_compat), 297 + .table = "nat", 298 + .hooks = 1 << NF_IP_POST_ROUTING, 299 + .checkentry = ipt_snat_checkentry, 300 + .family = AF_INET, 301 + }; 302 + 303 + static struct xt_target ipt_dnat_reg = { 304 + .name = "DNAT", 305 + .target = ipt_dnat_target, 306 + .targetsize = sizeof(struct nf_nat_multi_range_compat), 307 + .table = "nat", 308 + .hooks = (1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_LOCAL_OUT), 309 + .checkentry = ipt_dnat_checkentry, 310 + .family = AF_INET, 311 + }; 312 + 313 + int __init nf_nat_rule_init(void) 314 + { 315 + int ret; 316 + 317 + ret = ipt_register_table(&nat_table, &nat_initial_table.repl); 318 + if (ret != 0) 319 + return ret; 320 + ret = xt_register_target(&ipt_snat_reg); 321 + if (ret != 0) 322 + goto unregister_table; 323 + 324 + ret = xt_register_target(&ipt_dnat_reg); 325 + if (ret != 0) 326 + goto unregister_snat; 327 + 328 + return ret; 329 + 330 + unregister_snat: 331 + xt_unregister_target(&ipt_snat_reg); 332 + unregister_table: 333 + ipt_unregister_table(&nat_table); 334 + 335 + return ret; 336 + } 337 + 338 + void nf_nat_rule_cleanup(void) 339 + { 340 + xt_unregister_target(&ipt_dnat_reg); 341 + xt_unregister_target(&ipt_snat_reg); 342 + ipt_unregister_table(&nat_table); 343 + }
+406
net/ipv4/netfilter/nf_nat_standalone.c
··· 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/ip.h> 11 + #include <linux/netfilter.h> 12 + #include <linux/netfilter_ipv4.h> 13 + #include <linux/module.h> 14 + #include <linux/skbuff.h> 15 + #include <linux/proc_fs.h> 16 + #include <net/ip.h> 17 + #include <net/checksum.h> 18 + #include <linux/spinlock.h> 19 + 20 + #include <net/netfilter/nf_conntrack.h> 21 + #include <net/netfilter/nf_conntrack_core.h> 22 + #include <net/netfilter/nf_nat.h> 23 + #include <net/netfilter/nf_nat_rule.h> 24 + #include <net/netfilter/nf_nat_protocol.h> 25 + #include <net/netfilter/nf_nat_core.h> 26 + #include <net/netfilter/nf_nat_helper.h> 27 + #include <linux/netfilter_ipv4/ip_tables.h> 28 + 29 + #if 0 30 + #define DEBUGP printk 31 + #else 32 + #define DEBUGP(format, args...) 33 + #endif 34 + 35 + #define HOOKNAME(hooknum) ((hooknum) == NF_IP_POST_ROUTING ? "POST_ROUTING" \ 36 + : ((hooknum) == NF_IP_PRE_ROUTING ? "PRE_ROUTING" \ 37 + : ((hooknum) == NF_IP_LOCAL_OUT ? "LOCAL_OUT" \ 38 + : ((hooknum) == NF_IP_LOCAL_IN ? "LOCAL_IN" \ 39 + : "*ERROR*"))) 40 + 41 + #ifdef CONFIG_XFRM 42 + static void nat_decode_session(struct sk_buff *skb, struct flowi *fl) 43 + { 44 + struct nf_conn *ct; 45 + struct nf_conntrack_tuple *t; 46 + enum ip_conntrack_info ctinfo; 47 + enum ip_conntrack_dir dir; 48 + unsigned long statusbit; 49 + 50 + ct = nf_ct_get(skb, &ctinfo); 51 + if (ct == NULL) 52 + return; 53 + dir = CTINFO2DIR(ctinfo); 54 + t = &ct->tuplehash[dir].tuple; 55 + 56 + if (dir == IP_CT_DIR_ORIGINAL) 57 + statusbit = IPS_DST_NAT; 58 + else 59 + statusbit = IPS_SRC_NAT; 60 + 61 + if (ct->status & statusbit) { 62 + fl->fl4_dst = t->dst.u3.ip; 63 + if (t->dst.protonum == IPPROTO_TCP || 64 + t->dst.protonum == IPPROTO_UDP) 65 + fl->fl_ip_dport = t->dst.u.tcp.port; 66 + } 67 + 68 + statusbit ^= IPS_NAT_MASK; 69 + 70 + if (ct->status & statusbit) { 71 + fl->fl4_src = t->src.u3.ip; 72 + if (t->dst.protonum == IPPROTO_TCP || 73 + t->dst.protonum == IPPROTO_UDP) 74 + fl->fl_ip_sport = t->src.u.tcp.port; 75 + } 76 + } 77 + #endif 78 + 79 + static unsigned int 80 + nf_nat_fn(unsigned int hooknum, 81 + struct sk_buff **pskb, 82 + const struct net_device *in, 83 + const struct net_device *out, 84 + int (*okfn)(struct sk_buff *)) 85 + { 86 + struct nf_conn *ct; 87 + enum ip_conntrack_info ctinfo; 88 + struct nf_conn_nat *nat; 89 + struct nf_nat_info *info; 90 + /* maniptype == SRC for postrouting. */ 91 + enum nf_nat_manip_type maniptype = HOOK2MANIP(hooknum); 92 + 93 + /* We never see fragments: conntrack defrags on pre-routing 94 + and local-out, and nf_nat_out protects post-routing. */ 95 + NF_CT_ASSERT(!((*pskb)->nh.iph->frag_off 96 + & htons(IP_MF|IP_OFFSET))); 97 + 98 + ct = nf_ct_get(*pskb, &ctinfo); 99 + /* Can't track? It's not due to stress, or conntrack would 100 + have dropped it. Hence it's the user's responsibilty to 101 + packet filter it out, or implement conntrack/NAT for that 102 + protocol. 8) --RR */ 103 + if (!ct) { 104 + /* Exception: ICMP redirect to new connection (not in 105 + hash table yet). We must not let this through, in 106 + case we're doing NAT to the same network. */ 107 + if ((*pskb)->nh.iph->protocol == IPPROTO_ICMP) { 108 + struct icmphdr _hdr, *hp; 109 + 110 + hp = skb_header_pointer(*pskb, 111 + (*pskb)->nh.iph->ihl*4, 112 + sizeof(_hdr), &_hdr); 113 + if (hp != NULL && 114 + hp->type == ICMP_REDIRECT) 115 + return NF_DROP; 116 + } 117 + return NF_ACCEPT; 118 + } 119 + 120 + /* Don't try to NAT if this packet is not conntracked */ 121 + if (ct == &nf_conntrack_untracked) 122 + return NF_ACCEPT; 123 + 124 + nat = nfct_nat(ct); 125 + if (!nat) 126 + return NF_DROP; 127 + 128 + switch (ctinfo) { 129 + case IP_CT_RELATED: 130 + case IP_CT_RELATED+IP_CT_IS_REPLY: 131 + if ((*pskb)->nh.iph->protocol == IPPROTO_ICMP) { 132 + if (!nf_nat_icmp_reply_translation(ct, ctinfo, 133 + hooknum, pskb)) 134 + return NF_DROP; 135 + else 136 + return NF_ACCEPT; 137 + } 138 + /* Fall thru... (Only ICMPs can be IP_CT_IS_REPLY) */ 139 + case IP_CT_NEW: 140 + info = &nat->info; 141 + 142 + /* Seen it before? This can happen for loopback, retrans, 143 + or local packets.. */ 144 + if (!nf_nat_initialized(ct, maniptype)) { 145 + unsigned int ret; 146 + 147 + if (unlikely(nf_ct_is_confirmed(ct))) 148 + /* NAT module was loaded late */ 149 + ret = alloc_null_binding_confirmed(ct, info, 150 + hooknum); 151 + else if (hooknum == NF_IP_LOCAL_IN) 152 + /* LOCAL_IN hook doesn't have a chain! */ 153 + ret = alloc_null_binding(ct, info, hooknum); 154 + else 155 + ret = nf_nat_rule_find(pskb, hooknum, in, out, 156 + ct, info); 157 + 158 + if (ret != NF_ACCEPT) { 159 + return ret; 160 + } 161 + } else 162 + DEBUGP("Already setup manip %s for ct %p\n", 163 + maniptype == IP_NAT_MANIP_SRC ? "SRC" : "DST", 164 + ct); 165 + break; 166 + 167 + default: 168 + /* ESTABLISHED */ 169 + NF_CT_ASSERT(ctinfo == IP_CT_ESTABLISHED || 170 + ctinfo == (IP_CT_ESTABLISHED+IP_CT_IS_REPLY)); 171 + info = &nat->info; 172 + } 173 + 174 + NF_CT_ASSERT(info); 175 + return nf_nat_packet(ct, ctinfo, hooknum, pskb); 176 + } 177 + 178 + static unsigned int 179 + nf_nat_in(unsigned int hooknum, 180 + struct sk_buff **pskb, 181 + const struct net_device *in, 182 + const struct net_device *out, 183 + int (*okfn)(struct sk_buff *)) 184 + { 185 + unsigned int ret; 186 + __be32 daddr = (*pskb)->nh.iph->daddr; 187 + 188 + ret = nf_nat_fn(hooknum, pskb, in, out, okfn); 189 + if (ret != NF_DROP && ret != NF_STOLEN && 190 + daddr != (*pskb)->nh.iph->daddr) { 191 + dst_release((*pskb)->dst); 192 + (*pskb)->dst = NULL; 193 + } 194 + return ret; 195 + } 196 + 197 + static unsigned int 198 + nf_nat_out(unsigned int hooknum, 199 + struct sk_buff **pskb, 200 + const struct net_device *in, 201 + const struct net_device *out, 202 + int (*okfn)(struct sk_buff *)) 203 + { 204 + #ifdef CONFIG_XFRM 205 + struct nf_conn *ct; 206 + enum ip_conntrack_info ctinfo; 207 + #endif 208 + unsigned int ret; 209 + 210 + /* root is playing with raw sockets. */ 211 + if ((*pskb)->len < sizeof(struct iphdr) || 212 + (*pskb)->nh.iph->ihl * 4 < sizeof(struct iphdr)) 213 + return NF_ACCEPT; 214 + 215 + ret = nf_nat_fn(hooknum, pskb, in, out, okfn); 216 + #ifdef CONFIG_XFRM 217 + if (ret != NF_DROP && ret != NF_STOLEN && 218 + (ct = nf_ct_get(*pskb, &ctinfo)) != NULL) { 219 + enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); 220 + 221 + if (ct->tuplehash[dir].tuple.src.u3.ip != 222 + ct->tuplehash[!dir].tuple.dst.u3.ip 223 + || ct->tuplehash[dir].tuple.src.u.all != 224 + ct->tuplehash[!dir].tuple.dst.u.all 225 + ) 226 + return ip_xfrm_me_harder(pskb) == 0 ? ret : NF_DROP; 227 + } 228 + #endif 229 + return ret; 230 + } 231 + 232 + static unsigned int 233 + nf_nat_local_fn(unsigned int hooknum, 234 + struct sk_buff **pskb, 235 + const struct net_device *in, 236 + const struct net_device *out, 237 + int (*okfn)(struct sk_buff *)) 238 + { 239 + struct nf_conn *ct; 240 + enum ip_conntrack_info ctinfo; 241 + unsigned int ret; 242 + 243 + /* root is playing with raw sockets. */ 244 + if ((*pskb)->len < sizeof(struct iphdr) || 245 + (*pskb)->nh.iph->ihl * 4 < sizeof(struct iphdr)) 246 + return NF_ACCEPT; 247 + 248 + ret = nf_nat_fn(hooknum, pskb, in, out, okfn); 249 + if (ret != NF_DROP && ret != NF_STOLEN && 250 + (ct = nf_ct_get(*pskb, &ctinfo)) != NULL) { 251 + enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); 252 + 253 + if (ct->tuplehash[dir].tuple.dst.u3.ip != 254 + ct->tuplehash[!dir].tuple.src.u3.ip 255 + #ifdef CONFIG_XFRM 256 + || ct->tuplehash[dir].tuple.dst.u.all != 257 + ct->tuplehash[!dir].tuple.src.u.all 258 + #endif 259 + ) 260 + if (ip_route_me_harder(pskb, RTN_UNSPEC)) 261 + ret = NF_DROP; 262 + } 263 + return ret; 264 + } 265 + 266 + static unsigned int 267 + nf_nat_adjust(unsigned int hooknum, 268 + struct sk_buff **pskb, 269 + const struct net_device *in, 270 + const struct net_device *out, 271 + int (*okfn)(struct sk_buff *)) 272 + { 273 + struct nf_conn *ct; 274 + enum ip_conntrack_info ctinfo; 275 + 276 + ct = nf_ct_get(*pskb, &ctinfo); 277 + if (ct && test_bit(IPS_SEQ_ADJUST_BIT, &ct->status)) { 278 + DEBUGP("nf_nat_standalone: adjusting sequence number\n"); 279 + if (!nf_nat_seq_adjust(pskb, ct, ctinfo)) 280 + return NF_DROP; 281 + } 282 + return NF_ACCEPT; 283 + } 284 + 285 + /* We must be after connection tracking and before packet filtering. */ 286 + 287 + static struct nf_hook_ops nf_nat_ops[] = { 288 + /* Before packet filtering, change destination */ 289 + { 290 + .hook = nf_nat_in, 291 + .owner = THIS_MODULE, 292 + .pf = PF_INET, 293 + .hooknum = NF_IP_PRE_ROUTING, 294 + .priority = NF_IP_PRI_NAT_DST, 295 + }, 296 + /* After packet filtering, change source */ 297 + { 298 + .hook = nf_nat_out, 299 + .owner = THIS_MODULE, 300 + .pf = PF_INET, 301 + .hooknum = NF_IP_POST_ROUTING, 302 + .priority = NF_IP_PRI_NAT_SRC, 303 + }, 304 + /* After conntrack, adjust sequence number */ 305 + { 306 + .hook = nf_nat_adjust, 307 + .owner = THIS_MODULE, 308 + .pf = PF_INET, 309 + .hooknum = NF_IP_POST_ROUTING, 310 + .priority = NF_IP_PRI_NAT_SEQ_ADJUST, 311 + }, 312 + /* Before packet filtering, change destination */ 313 + { 314 + .hook = nf_nat_local_fn, 315 + .owner = THIS_MODULE, 316 + .pf = PF_INET, 317 + .hooknum = NF_IP_LOCAL_OUT, 318 + .priority = NF_IP_PRI_NAT_DST, 319 + }, 320 + /* After packet filtering, change source */ 321 + { 322 + .hook = nf_nat_fn, 323 + .owner = THIS_MODULE, 324 + .pf = PF_INET, 325 + .hooknum = NF_IP_LOCAL_IN, 326 + .priority = NF_IP_PRI_NAT_SRC, 327 + }, 328 + /* After conntrack, adjust sequence number */ 329 + { 330 + .hook = nf_nat_adjust, 331 + .owner = THIS_MODULE, 332 + .pf = PF_INET, 333 + .hooknum = NF_IP_LOCAL_IN, 334 + .priority = NF_IP_PRI_NAT_SEQ_ADJUST, 335 + }, 336 + }; 337 + 338 + static int __init nf_nat_standalone_init(void) 339 + { 340 + int size, ret = 0; 341 + 342 + need_conntrack(); 343 + 344 + size = ALIGN(sizeof(struct nf_conn), __alignof__(struct nf_conn_nat)) + 345 + sizeof(struct nf_conn_nat); 346 + ret = nf_conntrack_register_cache(NF_CT_F_NAT, "nf_nat:base", size); 347 + if (ret < 0) { 348 + printk(KERN_ERR "nf_nat_init: Unable to create slab cache\n"); 349 + return ret; 350 + } 351 + 352 + size = ALIGN(size, __alignof__(struct nf_conn_help)) + 353 + sizeof(struct nf_conn_help); 354 + ret = nf_conntrack_register_cache(NF_CT_F_NAT|NF_CT_F_HELP, 355 + "nf_nat:help", size); 356 + if (ret < 0) { 357 + printk(KERN_ERR "nf_nat_init: Unable to create slab cache\n"); 358 + goto cleanup_register_cache; 359 + } 360 + #ifdef CONFIG_XFRM 361 + BUG_ON(ip_nat_decode_session != NULL); 362 + ip_nat_decode_session = nat_decode_session; 363 + #endif 364 + ret = nf_nat_rule_init(); 365 + if (ret < 0) { 366 + printk("nf_nat_init: can't setup rules.\n"); 367 + goto cleanup_decode_session; 368 + } 369 + ret = nf_register_hooks(nf_nat_ops, ARRAY_SIZE(nf_nat_ops)); 370 + if (ret < 0) { 371 + printk("nf_nat_init: can't register hooks.\n"); 372 + goto cleanup_rule_init; 373 + } 374 + nf_nat_module_is_loaded = 1; 375 + return ret; 376 + 377 + cleanup_rule_init: 378 + nf_nat_rule_cleanup(); 379 + cleanup_decode_session: 380 + #ifdef CONFIG_XFRM 381 + ip_nat_decode_session = NULL; 382 + synchronize_net(); 383 + #endif 384 + nf_conntrack_unregister_cache(NF_CT_F_NAT|NF_CT_F_HELP); 385 + cleanup_register_cache: 386 + nf_conntrack_unregister_cache(NF_CT_F_NAT); 387 + return ret; 388 + } 389 + 390 + static void __exit nf_nat_standalone_fini(void) 391 + { 392 + nf_unregister_hooks(nf_nat_ops, ARRAY_SIZE(nf_nat_ops)); 393 + nf_nat_rule_cleanup(); 394 + nf_nat_module_is_loaded = 0; 395 + #ifdef CONFIG_XFRM 396 + ip_nat_decode_session = NULL; 397 + synchronize_net(); 398 + #endif 399 + /* Conntrack caches are unregistered in nf_conntrack_cleanup */ 400 + } 401 + 402 + module_init(nf_nat_standalone_init); 403 + module_exit(nf_nat_standalone_fini); 404 + 405 + MODULE_LICENSE("GPL"); 406 + MODULE_ALIAS("ip_nat");
+22 -1
net/netfilter/nf_conntrack_core.c
··· 579 579 /* FIXME: protect helper list per RCU */ 580 580 read_lock_bh(&nf_conntrack_lock); 581 581 helper = __nf_ct_helper_find(repl); 582 - if (helper) 582 + /* NAT might want to assign a helper later */ 583 + if (helper || features & NF_CT_F_NAT) 583 584 features |= NF_CT_F_HELP; 584 585 read_unlock_bh(&nf_conntrack_lock); 585 586 ··· 849 848 __nf_ct_l3proto_find(orig->src.l3num), 850 849 __nf_ct_l4proto_find(orig->src.l3num, 851 850 orig->dst.protonum)); 851 + } 852 + 853 + /* Alter reply tuple (maybe alter helper). This is for NAT, and is 854 + implicitly racy: see __nf_conntrack_confirm */ 855 + void nf_conntrack_alter_reply(struct nf_conn *ct, 856 + const struct nf_conntrack_tuple *newreply) 857 + { 858 + struct nf_conn_help *help = nfct_help(ct); 859 + 860 + write_lock_bh(&nf_conntrack_lock); 861 + /* Should be unconfirmed, so not in hash table yet */ 862 + NF_CT_ASSERT(!nf_ct_is_confirmed(ct)); 863 + 864 + DEBUGP("Altering reply tuple of %p to ", ct); 865 + NF_CT_DUMP_TUPLE(newreply); 866 + 867 + ct->tuplehash[IP_CT_DIR_REPLY].tuple = *newreply; 868 + if (!ct->master && help && help->expecting == 0) 869 + help->helper = __nf_ct_helper_find(newreply); 870 + write_unlock_bh(&nf_conntrack_lock); 852 871 } 853 872 854 873 /* Refresh conntrack for this many jiffies and do accounting if do_acct is 1 */
+25 -21
net/netfilter/nf_conntrack_netlink.c
··· 39 39 #include <net/netfilter/nf_conntrack_helper.h> 40 40 #include <net/netfilter/nf_conntrack_l3proto.h> 41 41 #include <net/netfilter/nf_conntrack_l4proto.h> 42 - #include <linux/netfilter_ipv4/ip_nat_protocol.h> 42 + #include <net/netfilter/nf_conntrack_tuple.h> 43 + #ifdef CONFIG_NF_NAT_NEEDED 44 + #include <net/netfilter/nf_nat_core.h> 45 + #include <net/netfilter/nf_nat_protocol.h> 46 + #endif 43 47 44 48 #include <linux/netfilter/nfnetlink.h> 45 49 #include <linux/netfilter/nfnetlink_conntrack.h> ··· 434 430 restart: 435 431 list_for_each_prev(i, &nf_conntrack_hash[cb->args[0]]) { 436 432 h = (struct nf_conntrack_tuple_hash *) i; 437 - if (DIRECTION(h) != IP_CT_DIR_ORIGINAL) 433 + if (NF_CT_DIRECTION(h) != IP_CT_DIR_ORIGINAL) 438 434 continue; 439 435 ct = nf_ct_tuplehash_to_ctrack(h); 440 436 /* Dump entries of a given L3 protocol number. ··· 560 556 return 0; 561 557 } 562 558 563 - #ifdef CONFIG_IP_NF_NAT_NEEDED 559 + #ifdef CONFIG_NF_NAT_NEEDED 564 560 static const size_t cta_min_protonat[CTA_PROTONAT_MAX] = { 565 561 [CTA_PROTONAT_PORT_MIN-1] = sizeof(u_int16_t), 566 562 [CTA_PROTONAT_PORT_MAX-1] = sizeof(u_int16_t), 567 563 }; 568 564 569 - static int ctnetlink_parse_nat_proto(struct nfattr *attr, 565 + static int nfnetlink_parse_nat_proto(struct nfattr *attr, 570 566 const struct nf_conn *ct, 571 - struct ip_nat_range *range) 567 + struct nf_nat_range *range) 572 568 { 573 569 struct nfattr *tb[CTA_PROTONAT_MAX]; 574 - struct ip_nat_protocol *npt; 570 + struct nf_nat_protocol *npt; 575 571 576 572 nfattr_parse_nested(tb, CTA_PROTONAT_MAX, attr); 577 573 578 574 if (nfattr_bad_size(tb, CTA_PROTONAT_MAX, cta_min_protonat)) 579 575 return -EINVAL; 580 576 581 - npt = ip_nat_proto_find_get(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum); 577 + npt = nf_nat_proto_find_get(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum); 582 578 583 579 if (!npt->nfattr_to_range) { 584 - ip_nat_proto_put(npt); 580 + nf_nat_proto_put(npt); 585 581 return 0; 586 582 } 587 583 ··· 589 585 if (npt->nfattr_to_range(tb, range) > 0) 590 586 range->flags |= IP_NAT_RANGE_PROTO_SPECIFIED; 591 587 592 - ip_nat_proto_put(npt); 588 + nf_nat_proto_put(npt); 593 589 594 590 return 0; 595 591 } ··· 600 596 }; 601 597 602 598 static inline int 603 - ctnetlink_parse_nat(struct nfattr *nat, 604 - const struct nf_conn *ct, struct ip_nat_range *range) 599 + nfnetlink_parse_nat(struct nfattr *nat, 600 + const struct nf_conn *ct, struct nf_nat_range *range) 605 601 { 606 602 struct nfattr *tb[CTA_NAT_MAX]; 607 603 int err; ··· 627 623 if (!tb[CTA_NAT_PROTO-1]) 628 624 return 0; 629 625 630 - err = ctnetlink_parse_nat_proto(tb[CTA_NAT_PROTO-1], ct, range); 626 + err = nfnetlink_parse_nat_proto(tb[CTA_NAT_PROTO-1], ct, range); 631 627 if (err < 0) 632 628 return err; 633 629 ··· 802 798 return -EINVAL; 803 799 804 800 if (cda[CTA_NAT_SRC-1] || cda[CTA_NAT_DST-1]) { 805 - #ifndef CONFIG_IP_NF_NAT_NEEDED 801 + #ifndef CONFIG_NF_NAT_NEEDED 806 802 return -EINVAL; 807 803 #else 808 - struct ip_nat_range range; 804 + struct nf_nat_range range; 809 805 810 806 if (cda[CTA_NAT_DST-1]) { 811 - if (ctnetlink_parse_nat(cda[CTA_NAT_DST-1], ct, 807 + if (nfnetlink_parse_nat(cda[CTA_NAT_DST-1], ct, 812 808 &range) < 0) 813 809 return -EINVAL; 814 - if (ip_nat_initialized(ct, 810 + if (nf_nat_initialized(ct, 815 811 HOOK2MANIP(NF_IP_PRE_ROUTING))) 816 812 return -EEXIST; 817 - ip_nat_setup_info(ct, &range, hooknum); 813 + nf_nat_setup_info(ct, &range, NF_IP_PRE_ROUTING); 818 814 } 819 815 if (cda[CTA_NAT_SRC-1]) { 820 - if (ctnetlink_parse_nat(cda[CTA_NAT_SRC-1], ct, 816 + if (nfnetlink_parse_nat(cda[CTA_NAT_SRC-1], ct, 821 817 &range) < 0) 822 818 return -EINVAL; 823 - if (ip_nat_initialized(ct, 819 + if (nf_nat_initialized(ct, 824 820 HOOK2MANIP(NF_IP_POST_ROUTING))) 825 821 return -EEXIST; 826 - ip_nat_setup_info(ct, &range, hooknum); 822 + nf_nat_setup_info(ct, &range, NF_IP_POST_ROUTING); 827 823 } 828 824 #endif 829 825 } 830 826 831 827 /* Be careful here, modifying NAT bits can screw up things, 832 828 * so don't let users modify them directly if they don't pass 833 - * ip_nat_range. */ 829 + * nf_nat_range. */ 834 830 ct->status |= status & ~(IPS_NAT_DONE_MASK | IPS_NAT_MASK); 835 831 return 0; 836 832 }
+1 -1
net/netfilter/nf_conntrack_proto_tcp.c
··· 730 730 return res; 731 731 } 732 732 733 - #ifdef CONFIG_IP_NF_NAT_NEEDED 733 + #ifdef CONFIG_NF_NAT_NEEDED 734 734 /* Update sender->td_end after NAT successfully mangled the packet */ 735 735 /* Caller must linearize skb at tcp header. */ 736 736 void nf_conntrack_tcp_update(struct sk_buff *skb,
+4 -1
net/netfilter/nf_conntrack_standalone.c
··· 530 530 EXPORT_SYMBOL(nf_conntrack_hash); 531 531 EXPORT_SYMBOL(nf_conntrack_untracked); 532 532 EXPORT_SYMBOL_GPL(nf_conntrack_find_get); 533 - #ifdef CONFIG_IP_NF_NAT_NEEDED 533 + #ifdef CONFIG_NF_NAT_NEEDED 534 534 EXPORT_SYMBOL(nf_conntrack_tcp_update); 535 + EXPORT_SYMBOL(nf_conntrack_register_cache); 536 + EXPORT_SYMBOL(nf_conntrack_unregister_cache); 537 + EXPORT_SYMBOL(nf_conntrack_alter_reply); 535 538 #endif 536 539 EXPORT_SYMBOL(__nf_conntrack_confirm); 537 540 EXPORT_SYMBOL(nf_ct_get_tuple);