diff -Naur linux-2.6.18.1/include/linux/netfilter_ipv4/ip_tproxy.h linux-2.6.18.1_new/include/linux/netfilter_ipv4/ip_tproxy.h --- linux-2.6.18.1/include/linux/netfilter_ipv4/ip_tproxy.h 2007-09-25 20:18:22.000000000 +0530 +++ linux-2.6.18.1_new/include/linux/netfilter_ipv4/ip_tproxy.h 2007-09-25 20:15:04.000000000 +0530 @@ -74,5 +74,60 @@ } v; }; +#ifdef __KERNEL__ +struct ip_tproxy_sockref; + +struct ip_tproxy_hash +{ + struct list_head list; + struct ip_tproxy_sockref *sockref; +}; + +struct ip_tproxy_sockref +{ + int flags; + atomic_t references; + + u8 proto; + + /* foreign address associated with a local socket */ + u32 faddr; + u16 fport; + + /* local socket address */ + u32 laddr; + u16 lport; + + /* remote addresses, needed for datagram protocols when the peer + * sends the packet triggering the NAT translation. (as there might + * be multiple sockrefs on the same foreign address). + */ + u32 raddr; + u16 rport; + + /* hash chains indexed by local and foreign addresses */ + struct ip_tproxy_hash bylocal, byforeign; + + /* lock protecting access to related list */ + spinlock_t relatedlock; + /* number of related connections */ + atomic_t related; + /* list of related connections */ + struct list_head relatedct; + + /* socket which we were assigned to */ + struct sock *assigned_to; + + /* How many sockets use this sockref? Used for mark-only sockrefs, + * which can be shared between multiple sockets bound to the same local + * address */ + atomic_t socket_count; + + /* when was this entry inserted in hash */ + struct timespec tv_hashed; +}; +#endif //__KERNEL__ + + #endif diff -Naur linux-2.6.18.1/net/ipv4/netfilter/ip_tables.c linux-2.6.18.1_new/net/ipv4/netfilter/ip_tables.c --- linux-2.6.18.1/net/ipv4/netfilter/ip_tables.c 2006-10-14 09:04:03.000000000 +0530 +++ linux-2.6.18.1_new/net/ipv4/netfilter/ip_tables.c 2007-09-25 20:16:17.000000000 +0530 @@ -33,6 +33,9 @@ #include #include +#include +#include + MODULE_LICENSE("GPL"); MODULE_AUTHOR("Netfilter Core Team "); MODULE_DESCRIPTION("IPv4 packet filter"); @@ -47,12 +50,16 @@ #define dprintf(format, args...) #endif + +DEFINE_RWLOCK(ip_conntrack_lock); + #ifdef DEBUG_IP_FIREWALL_USER #define duprintf(format, args...) printk(format , ## args) #else #define duprintf(format, args...) #endif +#if 0 #ifdef CONFIG_NETFILTER_DEBUG #define IP_NF_ASSERT(x) \ do { \ @@ -63,6 +70,7 @@ #else #define IP_NF_ASSERT(x) #endif +#endif // #if 0 #if 0 /* All the better to debug you with... */ @@ -70,6 +78,7 @@ #define inline #endif + /* We keep a set of rules for each CPU, so we can avoid write-locking them in the softirq when updating the counters and therefore @@ -85,7 +94,7 @@ const char *indev, const char *outdev, const struct ipt_ip *ipinfo, - int isfrag) + int isfrag, char TproxyBitSet, u32 tproxyFaddr) { size_t i; unsigned long ret; @@ -108,7 +117,13 @@ NIPQUAD(ipinfo->dmsk.s_addr), NIPQUAD(ipinfo->dst.s_addr), ipinfo->invflags & IPT_INV_DSTIP ? " (INV)" : ""); - return 0; + if (TproxyBitSet && ((tproxyFaddr == ipinfo->src.s_addr) || + ((tproxyFaddr & ipinfo->smsk.s_addr) == ipinfo->src.s_addr))) + { + // Do nothing + } + else + return 0; } /* Look for ifname matches; this should unroll nicely. */ @@ -232,11 +247,53 @@ struct ipt_entry *e, *back; struct xt_table_info *private; + struct ip_conntrack *ct; + enum ip_conntrack_info ctinfo; + + char TproxyBitSet; + u32 tproxyFaddr; + /* Initialization */ ip = (*pskb)->nh.iph; datalen = (*pskb)->len - ip->ihl * 4; indev = in ? in->name : nulldevname; outdev = out ? out->name : nulldevname; + + read_lock_bh(&ip_conntrack_lock); + TproxyBitSet = 0; + tproxyFaddr = 0; + if (NF_IP_POST_ROUTING == hook) + { + ct = ip_conntrack_get (*pskb, &ctinfo); + + if (ct) + { + if (test_bit (IPS_TPROXY_BIT, &ct->status)) + { + TproxyBitSet = 1; + + if (ct->tproxy.sockref) + { + struct ip_tproxy_sockref* sr = (struct ip_tproxy_sockref *)ct->tproxy.sockref; + tproxyFaddr = sr->faddr; + + } + else + { + TproxyBitSet = 0; + tproxyFaddr = 0; + } + } + else + { + TproxyBitSet = 0; + tproxyFaddr = 0; + } + } + } + read_unlock_bh(&ip_conntrack_lock); + + /* We handle fragments by dealing with the first fragment as * if it was a normal packet. All other fragments are treated * normally, except that they will NEVER match rules that ask @@ -257,7 +314,8 @@ do { IP_NF_ASSERT(e); IP_NF_ASSERT(back); - if (ip_packet_match(ip, indev, outdev, &e->ip, offset)) { + if (ip_packet_match(ip, indev, outdev, &e->ip, offset, + TproxyBitSet, tproxyFaddr)) { struct ipt_entry_target *t; if (IPT_MATCH_ITERATE(e, do_match, diff -Naur linux-2.6.18.1/net/ipv4/netfilter/iptable_tproxy.c linux-2.6.18.1_new/net/ipv4/netfilter/iptable_tproxy.c --- linux-2.6.18.1/net/ipv4/netfilter/iptable_tproxy.c 2007-09-25 20:18:27.000000000 +0530 +++ linux-2.6.18.1_new/net/ipv4/netfilter/iptable_tproxy.c 2007-09-25 20:15:04.000000000 +0530 @@ -45,7 +45,7 @@ #include -#define TPROXY_VALID_HOOKS ((1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_LOCAL_OUT)) +#define TPROXY_VALID_HOOKS ((1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_LOCAL_OUT)) #if 0 #define DEBUGP printk @@ -147,6 +147,7 @@ #define TF_STATE_MASK 0xffff0000 +#if 0 struct ip_tproxy_sockref; struct ip_tproxy_hash @@ -198,6 +199,7 @@ /* when was this entry inserted in hash */ struct timespec tv_hashed; }; +#endif static int hashsize = 0; module_param(hashsize, uint, 0600); @@ -724,6 +726,11 @@ hooknum, sr->laddr, sr->lport, newip, newport); } else { + if (test_bit(IPS_SRC_NAT_DONE_BIT, &ct->status)) + { + test_and_clear_bit(IPS_SRC_NAT_DONE_BIT, &ct->status); + } + /* we store a reference to the sockref in the conntrack */ if (!test_and_set_bit(IPS_TPROXY_BIT, &ct->status)) { if (flags & TN_STOREREF) { @@ -828,6 +835,7 @@ enum ip_conntrack_info ctinfo; unsigned int verdict = NF_ACCEPT; + ct = ip_conntrack_get(*pskb, &ctinfo); if (ct && ctinfo == IP_CT_NEW) { @@ -869,6 +877,7 @@ sr = ip_tproxy_sockref_find_foreign(iph->daddr, tports[1], iph->protocol, iph->saddr, tports[0]); + if (sr && sr->flags & TF_ORPHAN) { /* This sockref is orphaned, the listening socket is already unassigned, * so it should not be used for setting up NAT for a new connection. */ @@ -891,6 +900,7 @@ if ((sr->flags & TF_MARK_ONLY) == 0) sr = NULL; } + } else if (hooknum == NF_IP_POST_ROUTING) { @@ -906,6 +916,7 @@ /* source address is interesting */ + sr = ip_tproxy_sockref_find_local(iph->saddr, tports[0], iph->protocol, 1, iph->daddr, tports[1]); if (sr && (sr->flags & (TF_CONNECT|TF_MARK_ONLY)) == 0) { @@ -984,9 +995,9 @@ /* there was no matching sockref, so we consult the * TPROXY table */ - ui.changed = 0; verdict = ipt_do_table(pskb, hooknum, in, out, &tproxy_table, &ui); + if (ui.changed && verdict == NF_ACCEPT) { struct ip_tproxy_sockref sr; u32 laddr; @@ -1016,7 +1027,6 @@ } } } - return verdict; }