diff -ur --exclude='*.o' linux-2.4.24/include/linux/sysctl.h linux-2.4.24-new/include/linux/sysctl.h
--- linux-2.4.24/include/linux/sysctl.h	Fri Nov 28 13:26:21 2003
+++ linux-2.4.24-new/include/linux/sysctl.h	Tue Feb  3 17:14:56 2004
@@ -311,6 +311,9 @@
 	NET_TCP_FRTO=92,
 	NET_TCP_LOW_LATENCY=93,
 	NET_IPV4_IPFRAG_SECRET_INTERVAL=94,
+	NET_TCP_OPTACK_ENABLED=95,
+	NET_TCP_OPTACK_MIN=96,
+	NET_TCP_OPTACK_MAX=97
 };
 
 enum {
diff -ur --exclude='*.o' linux-2.4.24/include/net/sock.h linux-2.4.24-new/include/net/sock.h
--- linux-2.4.24/include/net/sock.h	Fri Nov 28 13:26:21 2003
+++ linux-2.4.24-new/include/net/sock.h	Mon Feb  2 16:31:16 2004
@@ -37,6 +37,7 @@
 #include <linux/timer.h>
 #include <linux/cache.h>
 #include <linux/in.h>		/* struct sockaddr_in */
+#include <linux/random.h>
 
 #if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
 #include <linux/in6.h>		/* struct sockaddr_in6 */
@@ -109,6 +110,8 @@
 #include <asm/atomic.h>
 #include <net/dst.h>
 
+#define OPTACK_MODE_COUNTDOWN         0
+#define OPTACK_MODE_SKIP              1
 
 /* The AF_UNIX specific socket options */
 struct unix_opt {
@@ -432,6 +435,10 @@
 	__u32                   frto_highmark; /* snd_nxt when RTO occurred */
 
 	unsigned long last_synq_overflow; 
+
+       __u32 optack_data;
+       char optack_mode;
+
 };
 
  	
diff -ur --exclude='*.o' linux-2.4.24/include/net/tcp.h linux-2.4.24-new/include/net/tcp.h
--- linux-2.4.24/include/net/tcp.h	Fri Nov 28 13:26:21 2003
+++ linux-2.4.24-new/include/net/tcp.h	Tue Feb  3 18:06:42 2004
@@ -463,6 +463,9 @@
 extern int sysctl_tcp_tw_reuse;
 extern int sysctl_tcp_frto;
 extern int sysctl_tcp_low_latency;
+extern int sysctl_tcp_optack_enabled;
+extern int sysctl_tcp_optack_min;
+extern int sysctl_tcp_optack_max;
 
 extern atomic_t tcp_memory_allocated;
 extern atomic_t tcp_sockets_allocated;
@@ -1863,4 +1866,7 @@
 	TCP_ADD_STATS_USER(TcpMaxConn, -1);
 }
 
+__u32 optack_init_cntr(void);
+__inline__ void update_send_head(struct sock *sk, struct tcp_opt *tp, struct sk_buff *skb);
+
 #endif	/* _TCP_H */
diff -ur --exclude='*.o' linux-2.4.24/net/ipv4/sysctl_net_ipv4.c linux-2.4.24-new/net/ipv4/sysctl_net_ipv4.c
--- linux-2.4.24/net/ipv4/sysctl_net_ipv4.c	Fri Jun 13 10:51:39 2003
+++ linux-2.4.24-new/net/ipv4/sysctl_net_ipv4.c	Tue Feb  3 17:21:09 2004
@@ -229,6 +229,12 @@
 	{NET_IPV4_IPFRAG_SECRET_INTERVAL, "ipfrag_secret_interval",
 	 &sysctl_ipfrag_secret_interval, sizeof(int), 0644, NULL, &proc_dointvec_jiffies, 
 	 &sysctl_jiffies},
+	{NET_TCP_OPTACK_ENABLED, "tcp_optack_enabled",
+	 &sysctl_tcp_optack_enabled, sizeof(int), 0644, NULL, &proc_dointvec},
+	{NET_TCP_OPTACK_MIN, "tcp_optack_min",
+	 &sysctl_tcp_optack_min, sizeof(int), 0644, NULL, &proc_dointvec},
+	{NET_TCP_OPTACK_MAX, "tcp_optack_max",
+	 &sysctl_tcp_optack_max, sizeof(int), 0644, NULL, &proc_dointvec},
 	{0}
 };
 
diff -ur --exclude='*.o' linux-2.4.24/net/ipv4/tcp.c linux-2.4.24-new/net/ipv4/tcp.c
--- linux-2.4.24/net/ipv4/tcp.c	Mon Aug 25 07:44:44 2003
+++ linux-2.4.24-new/net/ipv4/tcp.c	Tue Feb  3 18:07:04 2004
@@ -274,6 +274,10 @@
 int sysctl_tcp_wmem[3] = { 4*1024, 16*1024, 128*1024 };
 int sysctl_tcp_rmem[3] = { 4*1024, 87380, 87380*2 };
 
+int sysctl_tcp_optack_enabled = 1; /* Optack fix enabled by default */
+int sysctl_tcp_optack_min = 100;
+int sysctl_tcp_optack_max = 200;
+
 atomic_t tcp_memory_allocated;	/* Current allocated memory. */
 atomic_t tcp_sockets_allocated;	/* Current number of TCP sockets. */
 
@@ -2646,3 +2650,15 @@
 	(void) tcp_mib_init();
 	tcpdiag_init();
 }
+
+/* Return a random value between <sysctl_tcp_optack_min> and 
+ * <sysctl_tcp_optack_max>, inclusive.  Used for initializing 
+ * the countdown timer for optack attack detection.
+ */
+__u32 optack_init_cntr(void)
+{
+	__u32 bytes;
+	
+	get_random_bytes(&bytes, 4);
+	return sysctl_tcp_optack_min + (bytes % (sysctl_tcp_optack_max - sysctl_tcp_optack_min + 1));
+}
diff -ur --exclude='*.o' linux-2.4.24/net/ipv4/tcp_input.c linux-2.4.24-new/net/ipv4/tcp_input.c
--- linux-2.4.24/net/ipv4/tcp_input.c	Fri Nov 28 13:26:21 2003
+++ linux-2.4.24-new/net/ipv4/tcp_input.c	Tue Feb  3 18:10:04 2004
@@ -2026,6 +2026,30 @@
 	u32 prior_in_flight;
 	int prior_packets;
 
+	if(!sysctl_tcp_optack_enabled) 
+		goto normal_tcp;
+
+	if (tp->optack_mode == OPTACK_MODE_COUNTDOWN) {
+		if (tp->optack_data > 0)
+			tp->optack_data--;
+		else if(tp->send_head != NULL) { /* Skip next segment */
+			tp->optack_data = tp->snd_nxt;
+			update_send_head(sk, tp, tp->send_head);
+			tp->optack_mode = OPTACK_MODE_SKIP;
+		}
+	} else if (tp->optack_mode == OPTACK_MODE_SKIP) {
+		if (ack > tp->optack_data) { /* Got malicious ACK */
+			printk(KERN_CRIT "Optack attack detected..."
+					"sending RST\n");
+			tcp_send_active_reset(sk, GFP_ATOMIC);
+			tcp_done(sk);
+			return 0;
+		} else if (ack == tp->optack_data) { /* Passed test, reset counter */
+			tp->optack_mode = OPTACK_MODE_COUNTDOWN;
+			tp->optack_data = optack_init_cntr();
+		}
+	}
+ normal_tcp:
 	/* If the ack is newer than sent or older than previous acks
 	 * then we can probably ignore it.
 	 */
@@ -3919,6 +3941,9 @@
 
 				tp->snd_una = TCP_SKB_CB(skb)->ack_seq;
 				tp->snd_wnd = ntohs(th->window) << tp->snd_wscale;
+				tp->optack_data = optack_init_cntr();
+				tp->optack_mode = OPTACK_MODE_COUNTDOWN;
+
 				tcp_init_wl(tp, TCP_SKB_CB(skb)->ack_seq, TCP_SKB_CB(skb)->seq);
 
 				/* tcp_ack considers this ACK as duplicate
diff -ur --exclude='*.o' linux-2.4.24/net/ipv4/tcp_output.c linux-2.4.24-new/net/ipv4/tcp_output.c
--- linux-2.4.24/net/ipv4/tcp_output.c	Fri Nov 28 13:26:21 2003
+++ linux-2.4.24-new/net/ipv4/tcp_output.c	Mon Feb  2 13:37:50 2004
@@ -44,7 +44,7 @@
 /* People can turn this off for buggy TCP's found in printers etc. */
 int sysctl_tcp_retrans_collapse = 1;
 
-static __inline__
+__inline__
 void update_send_head(struct sock *sk, struct tcp_opt *tp, struct sk_buff *skb)
 {
 	tp->send_head = skb->next;
@@ -1201,6 +1201,9 @@
 	tp->rcv_wup = 0;
 	tp->copied_seq = 0;
 
+	tp->optack_mode = OPTACK_MODE_COUNTDOWN;
+	tp->optack_data = optack_init_cntr();
+
 	tp->rto = TCP_TIMEOUT_INIT;
 	tp->retransmits = 0;
 	tcp_clear_retrans(tp);
