patch-2.3.99-pre7 linux/net/ipv4/netfilter/ip_conntrack_proto_tcp.c

Next file: linux/net/ipv4/netfilter/ip_conntrack_standalone.c
Previous file: linux/net/ipv4/netfilter/ip_conntrack_core.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.3.99-pre6/linux/net/ipv4/netfilter/ip_conntrack_proto_tcp.c linux/net/ipv4/netfilter/ip_conntrack_proto_tcp.c
@@ -23,6 +23,10 @@
 /* FIXME: Examine ipfilter's timeouts and conntrack transitions more
    closely.  They're more complex. --RR */
 
+/* We steal a bit to indicate no reply yet (can't use status, because
+   it's set before we get into packet handling). */
+#define TCP_REPLY_BIT 0x1000
+
 /* Actually, I believe that neither ipmasq (where this code is stolen
    from) nor ipfilter do it exactly right.  A new conntrack machine taking
    into account packet loss (which creates uncertainty as to exactly
@@ -141,7 +145,7 @@
 	enum tcp_conntrack state;
 
 	READ_LOCK(&tcp_lock);
-	state = conntrack->proto.tcp_state;
+	state = (conntrack->proto.tcp_state & ~TCP_REPLY_BIT);
 	READ_UNLOCK(&tcp_lock);
 
 	return sprintf(buffer, "%s ", tcp_conntrack_names[state]);
@@ -161,7 +165,7 @@
 		      struct iphdr *iph, size_t len,
 		      enum ip_conntrack_info ctinfo)
 {
-	enum tcp_conntrack newconntrack;
+	enum tcp_conntrack newconntrack, oldtcpstate;
 	struct tcphdr *tcph = (struct tcphdr *)((u_int32_t *)iph + iph->ihl);
 
 	/* We're guaranteed to have the base header, but maybe not the
@@ -172,10 +176,11 @@
 	}
 
 	WRITE_LOCK(&tcp_lock);
+	oldtcpstate = conntrack->proto.tcp_state;
 	newconntrack
 		= tcp_conntracks
 		[CTINFO2DIR(ctinfo)]
-		[get_conntrack_index(tcph)][conntrack->proto.tcp_state];
+		[get_conntrack_index(tcph)][oldtcpstate & ~TCP_REPLY_BIT];
 
 	/* Invalid */
 	if (newconntrack == TCP_CONNTRACK_MAX) {
@@ -187,9 +192,22 @@
 	}
 
 	conntrack->proto.tcp_state = newconntrack;
+	if ((oldtcpstate & TCP_REPLY_BIT)
+	    || ctinfo >= IP_CT_IS_REPLY)
+		conntrack->proto.tcp_state |= TCP_REPLY_BIT;
+
 	WRITE_UNLOCK(&tcp_lock);
 
-	ip_ct_refresh(conntrack, tcp_timeouts[conntrack->proto.tcp_state]);
+	/* If only reply is a RST, we can consider ourselves not to
+	   have an established connection: this is a fairly common
+	   problem case, so we can delete the conntrack
+	   immediately.  --RR */
+	if (!(oldtcpstate & TCP_REPLY_BIT) && tcph->rst) {
+		if (del_timer(&conntrack->timeout))
+			conntrack->timeout.function((unsigned long)conntrack);
+	} else 
+		ip_ct_refresh(conntrack, tcp_timeouts[newconntrack]);
+
 	return NF_ACCEPT;
 }
 

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)