diff -urP linux/Documentation/Configure.help linux/Documentation/Configure.help
--- linux/Documentation/Configure.help	Sun Dec 10 19:49:41 2000
+++ linux/Documentation/Configure.help	Fri Dec 15 12:19:01 2000
@@ -1279,6 +1279,32 @@
   
   If unsure, say Y.
 
+IP: TCP stack options
+CONFIG_NET_STEALTH
+  If you say Y here, note that these options are now enabled by
+  default; you can disable them by executing the commands
+
+    echo 0 >/proc/sys/net/ipv4/tcp_ignore_ack
+    echo 0 >/proc/sys/net/ipv4/tcp_ignore_bogus
+    echo 0 >/proc/sys/net/ipv4/tcp_ignore_synfin
+
+  at boot time after the proc filesystem has been mounted.
+ 
+  If you say M here, a module will be built that when inserted will
+  deny the same packets as above. Due to the nightmare of adding
+  sysctl to a module, all module based sysctl options are in
+  /proc/net instead of /proc/sys/net/ipv4 for now.
+
+  If security is more important, say Y or M.
+
+Log all droped packets
+CONFIG_NET_STEALTH_LOG
+  This turns on a logging facility that logs all tcp packets with
+  bad flags.  If you said Y to "TCP stack options", say Y.
+  
+  note, if you said M to TCP stack options, these will be set Y by
+  default.
+
 Sun floppy controller support
 CONFIG_BLK_DEV_SUNFD
   This is support for floppy drives on Sun SPARC workstations. Say Y
diff -urP linux/Makefile linux/Makefile
--- linux/Makefile	Sun Dec 10 19:49:41 2000
+++ linux/Makefile	Fri Dec 15 12:19:17 2000
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 2
 SUBLEVEL = 18
-EXTRAVERSION =
+EXTRAVERSION = -stealth
 
 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
 
diff -urP linux/arch/alpha/defconfig linux/arch/alpha/defconfig
--- linux/arch/alpha/defconfig	Tue Jan  4 13:12:10 2000
+++ linux/arch/alpha/defconfig	Fri Dec 15 12:19:01 2000
@@ -102,6 +102,8 @@
 # CONFIG_NET_IPGRE is not set
 # CONFIG_IP_ALIAS is not set
 # CONFIG_SYN_COOKIES is not set
+CONFIG_NET_STEALTH=y
+CONFIG_NET_STEALTH_LOG=y  
 
 #
 # (it is safe to leave these untouched)
diff -urP linux/arch/arm/defconfig linux/arch/arm/defconfig
--- linux/arch/arm/defconfig	Sun Dec 10 19:49:41 2000
+++ linux/arch/arm/defconfig	Fri Dec 15 12:19:01 2000
@@ -250,6 +250,8 @@
 # CONFIG_NET_IPGRE is not set
 CONFIG_IP_ALIAS=y
 # CONFIG_SYN_COOKIES is not set
+CONFIG_NET_STEALTH=y
+CONFIG_NET_STEALTH_LOG=y
 
 #
 # (it is safe to leave these untouched)
diff -urP linux/arch/i386/defconfig linux/arch/i386/defconfig
--- linux/arch/i386/defconfig	Sun Dec 10 19:49:41 2000
+++ linux/arch/i386/defconfig	Fri Dec 15 12:19:01 2000
@@ -119,6 +119,8 @@
 # CONFIG_NET_IPGRE is not set
 # CONFIG_IP_ALIAS is not set
 # CONFIG_SYN_COOKIES is not set
+CONFIG_NET_STEALTH=y
+CONFIG_NET_STEALTH_LOG=y
 
 #
 # (it is safe to leave these untouched)
diff -urP linux/arch/m68k/defconfig linux/arch/m68k/defconfig
--- linux/arch/m68k/defconfig	Thu Feb 25 13:46:46 1999
+++ linux/arch/m68k/defconfig	Fri Dec 15 12:19:01 2000
@@ -89,6 +89,8 @@
 # CONFIG_NET_IPGRE is not set
 # CONFIG_IP_ALIAS is not set
 # CONFIG_SYN_COOKIES is not set
+CONFIG_NET_STEALTH=y
+CONFIG_NET_STEALTH_LOG=y  
 
 #
 # (it is safe to leave these untouched)
diff -urP linux/arch/mips/defconfig linux/arch/mips/defconfig
--- linux/arch/mips/defconfig	Mon Aug  9 15:04:38 1999
+++ linux/arch/mips/defconfig	Fri Dec 15 12:19:01 2000
@@ -101,6 +101,8 @@
 # CONFIG_NET_IPGRE is not set
 # CONFIG_IP_ALIAS is not set
 # CONFIG_SYN_COOKIES is not set
+CONFIG_NET_STEALTH=y
+CONFIG_NET_STEALTH_LOG=y
 
 #
 # (it is safe to leave these untouched)
diff -urP linux/arch/sparc/defconfig linux/arch/sparc/defconfig
--- linux/arch/sparc/defconfig	Sun Dec 10 19:49:41 2000
+++ linux/arch/sparc/defconfig	Fri Dec 15 12:19:01 2000
@@ -116,6 +116,8 @@
 # CONFIG_NET_IPGRE is not set
 # CONFIG_IP_ALIAS is not set
 # CONFIG_SYN_COOKIES is not set
+CONFIG_NET_STEALTH=y
+CONFIG_NET_STEALTH_LOG=y
 
 #
 # (it is safe to leave these untouched)
diff -urP linux/arch/sparc64/defconfig linux/arch/sparc64/defconfig
--- linux/arch/sparc64/defconfig	Sun Dec 10 19:49:41 2000
+++ linux/arch/sparc64/defconfig	Fri Dec 15 12:19:01 2000
@@ -144,6 +144,8 @@
 # CONFIG_NET_IPGRE is not set
 # CONFIG_IP_ALIAS is not set
 # CONFIG_SYN_COOKIES is not set
+CONFIG_NET_STEALTH=y
+CONFIG_NET_STEALTH_LOG=y  
 
 #
 # (it is safe to leave these untouched)
diff -urP linux/include/linux/sysctl.h linux/include/linux/sysctl.h
--- linux/include/linux/sysctl.h	Sun Dec 10 19:49:44 2000
+++ linux/include/linux/sysctl.h	Fri Dec 15 12:19:01 2000
@@ -231,7 +231,11 @@
 	NET_IPV4_ICMP_IGNORE_BOGUS_ERROR_RESPONSES=64,
 	NET_IPV4_IGMP_MAX_MEMBERSHIPS=65,
 	NET_IPV4_ALWAYS_DEFRAG=67,
-	NET_IPV4_IP_MASQ_UDP_DLOOSE=68
+        NET_IPV4_IP_MASQ_UDP_DLOOSE=68,
+        NET_TCP_STACK_SYNFIN=69,
+        NET_TCP_STACK_BOGUS=70,
+        NET_TCP_STACK_ACK=71
+
 };
 
 enum {
diff -urP linux/net/ipv4/Config.in linux/net/ipv4/Config.in
--- linux/net/ipv4/Config.in	Sun Dec 10 19:49:44 2000
+++ linux/net/ipv4/Config.in	Fri Dec 15 12:19:01 2000
@@ -74,6 +74,10 @@
   fi
 fi
 bool 'IP: TCP syncookie support (not enabled per default)' CONFIG_SYN_COOKIES
+tristate 'IP: TCP stack options (not enabled per default)' CONFIG_NET_STEALTH
+if [ "$CONFIG_NET_STEALTH" = "y" ]; then
+    bool 'Log all droped packets' CONFIG_NET_STEALTH_LOG
+fi
 comment '(it is safe to leave these untouched)'
 #bool 'IP: PC/TCP compatibility mode' CONFIG_INET_PCTCP
 tristate 'IP: Reverse ARP' CONFIG_INET_RARP
diff -urP linux/net/ipv4/Makefile linux/net/ipv4/Makefile
--- linux/net/ipv4/Makefile	Mon Jan  4 18:31:35 1999
+++ linux/net/ipv4/Makefile	Fri Dec 15 12:19:01 2000
@@ -58,6 +58,10 @@
   MX_OBJS += ip_gre.o
   endif
 endif
+ 
+ifeq ($(CONFIG_NET_STEALTH),m)
+M_OBJS += stealth.o
+endif
 
 ifeq ($(CONFIG_IP_MASQUERADE),y)
 IPV4X_OBJS += ip_masq.o ip_masq_app.o 
diff -urP linux/net/ipv4/stealth.c linux/net/ipv4/stealth.c
--- linux/net/ipv4/stealth.c	Wed Dec 31 19:00:00 1969
+++ linux/net/ipv4/stealth.c	Fri Dec 15 12:19:01 2000
@@ -0,0 +1,264 @@
+/*  Stealth module by Derek Callaway <super@innu.org> -- S@IRC
+ *  Original patch by Sean Trifero <sean@innu.org> -- solar@IRC 
+ *  $Id: stealth.c,v 1.3 2000/03/22 15:04:44 super Exp $
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/proc_fs.h>
+#include <linux/netdevice.h>
+#include <linux/skbuff.h>
+#include <linux/firewall.h>
+#include <linux/ip_fw.h>
+#include <asm/uaccess.h>
+#ifdef __SMP__
+#define SLOT_NUMBER() (cpu_number_map[smp_processor_id()]*2 + !in_interrupt())
+#else
+#define SLOT_NUMBER() (!in_interrupt())
+#endif
+#define STEALTH_INPUT_CHAIN stealth_chains
+#define STEALTH_FORWARD_CHAIN (stealth_chains->next)
+#define STEALTH_OUTPUT_CHAIN (stealth_chains->next->next)
+
+/* kernel space variables */
+static char kmsg[3][3] = { "1\n\0", "1\n\0", "1\n\0" };
+static char *tcp_ignore_ack = kmsg[0];
+static char *tcp_ignore_bogus = kmsg[1];
+static char *tcp_ignore_synfin = kmsg[2];
+
+/* structures from linux/net/ipv4/ip_fw.c */
+
+/* Head of linked list of fw rules */
+struct ip_counters
+{
+  __u64 pcnt, bcnt;            /* Packet and byte counters */
+};
+
+struct ip_reent
+{
+  struct ip_chain *prevchain;  /* Pointer to referencing chain */
+  struct ip_fwkernel *prevrule;        /* Pointer to referencing rule */
+  struct ip_counters counters;
+};
+
+struct ip_chain
+{
+  ip_chainlabel label;         /* Defines the label for each block */
+  struct ip_chain *next;       /* Pointer to next block */
+  struct ip_fwkernel *chain;   /* Pointer to first rule in block */
+  __u32 refcount;              /* Number of refernces to block */
+  int policy;                  /* Default rule for chain.  Only *
+                                * used in built in chains */
+  struct ip_reent reent[0];    /* Actually several of these */
+};
+
+static struct ip_chain *stealth_chains;
+
+int stealth_check (struct iphdr *, const char *, __u16 *, struct ip_chain *,
+                  struct sk_buff *, unsigned int, int);
+
+int
+stealth_input_check (struct firewall_ops *this, int pf, struct device *dev,
+                    void *phdr, void *arg, struct sk_buff **pskb)
+{
+  return (stealth_check (phdr, dev->name,
+                        arg, STEALTH_INPUT_CHAIN, *pskb, SLOT_NUMBER (), 0));
+}
+
+int
+stealth_output_check (struct firewall_ops *this, int pf, struct device *dev,
+                     void *phdr, void *arg, struct sk_buff **pksb)
+{
+  return (FW_SKIP);
+}
+
+int
+stealth_forward_check (struct firewall_ops *this, int pf, struct device *dev,
+                      void *phdr, void *arg, struct sk_buff **pksb)
+{
+  return (FW_SKIP);
+}
+
+struct firewall_ops ipfw_ops = {
+  NULL,
+  stealth_output_check,
+  stealth_input_check,
+  stealth_forward_check,
+  PF_INET,
+  31337                                /* This priority should be adequate. */
+};
+
+int
+stealth_check (struct iphdr *ip,
+              const char *rif,
+              __u16 * redirport,
+              struct ip_chain *chain,
+              struct sk_buff *skb, unsigned int slot, int testing)
+{
+  struct tcphdr *tcp;
+  if (ip->protocol != IPPROTO_TCP)
+    {
+      /* Not a TCP packet, don't worry about it. */
+      return (FW_SKIP);
+    }
+  tcp = (struct tcphdr *) ((__u32 *) ip + ip->ihl);
+  /* Check for those nasty unused bit fields. */
+  if ((*tcp_ignore_bogus != '0') && (tcp->res1))
+    {
+      /* I know goto statement should be avoided but I
+       * seriously doubt that this will evolve into
+       * spaghetti code. Furthermore, these jumps are
+       * extremely localized. */
+      goto tcp_bad_flags;
+    }
+  switch (tcp->fin)
+    {
+    case 0:
+      goto done;
+    default:
+      if (((*tcp_ignore_synfin != '0') && (tcp->syn))
+         || ((*tcp_ignore_ack != '0') && (tcp->psh) && (tcp->urg)))
+       {
+         goto tcp_bad_flags;
+       }
+    }
+  if ((*tcp_ignore_bogus != '0') && (!(tcp->ack || tcp->syn || tcp->rst)))
+    {
+      goto tcp_bad_flags;
+    }
+  goto done;
+tcp_bad_flags:
+#ifdef CONFIG_TCPIP_STACK_LOG
+  printk (KERN_INFO
+         "Packet log: badflag DENY %s PROTO=TCP %d.%d.%d.%d:%d "
+         "%d.%d.%d.%d:%d L=%hu:%u:%u S=0x%2.2hX I=%hu:%u:%u "
+         "T=%hu %c%c%c%c%c%c%c%c\n",
+         skb->dev->name, NIPQUAD (skb->nh.iph->saddr),
+         ntohs (skb->h.th->source), NIPQUAD (skb->nh.iph->daddr),
+         ntohs (skb->h.th->dest), ntohs (skb->nh.iph->tot_len), skb->len,
+         skb->len - skb->h.th->doff * 4, skb->nh.iph->tos,
+         ntohs (skb->nh.iph->id), ntohl (skb->h.th->seq),
+         ntohl (skb->h.th->ack_seq), skb->nh.iph->ttl,
+         skb->h.th->res1 ? '1' : '.', skb->h.th->res2 ? '2' : '.',
+         skb->h.th->ack ? 'A' : '.', skb->h.th->syn ? 'S' : '.',
+         skb->h.th->fin ? 'F' : '.', skb->h.th->rst ? 'R' : '.',
+         skb->h.th->psh ? 'P' : '.', skb->h.th->urg ? 'U' : '.');
+}
+#endif
+/* FW_BLOCK acts like ipchains -j DENY */
+return (FW_BLOCK);
+done:
+/* FW_SKIP allows the next chain to evaluate the traffic. */
+return (FW_SKIP);
+}
+
+static ssize_t
+module_output (struct file *file, char *buf, size_t len, loff_t * offset)
+{
+  static unsigned short done = 0;
+  unsigned short x = 0;
+  /* user land storage */
+  char umsg[2] = { 0 };
+  switch (file->f_dentry->d_name.name[11])
+    {
+    case 'a':
+      x = 0;
+      break;
+    case 'b':
+      x = 1;
+      break;
+    case 's':
+      x = 2;
+    }
+  if (done)
+    return (done = 0);
+  umsg[0] = kmsg[x][0], umsg[1] = '\n';
+  put_user (umsg[0], buf);
+  put_user (umsg[1], buf + 1);
+  put_user (umsg[2], buf + 2);
+  return (done = 2);
+}
+
+static ssize_t
+module_input (struct file *file, const char *buf, size_t length,
+             loff_t * offset)
+{
+  unsigned short x = 0;
+  switch (file->f_dentry->d_name.name[11])
+    {
+    case 'a':
+      x = 0;
+      break;
+    case 'b':
+      x = 1;
+      break;
+    case 's':
+      x = 2;
+    }
+  get_user (kmsg[x][0], buf);
+  kmsg[x][1] = 0;
+  return (2);
+}
+
+static int
+module_permission (struct inode *inode, int op)
+{
+  if (op == 4 || (op == 2 && current->euid == 0))
+    return (0);
+  return (-EACCES);
+}
+
+int
+module_open (struct inode *inode, struct file *file)
+{
+  MOD_INC_USE_COUNT;
+  return (0);
+}
+
+int
+module_close (struct inode *inode, struct file *file)
+{
+  MOD_DEC_USE_COUNT;
+  return (0);
+}
+
+/* <linux/fs.h> */
+
+static struct file_operations fops =
+  { NULL, module_output, module_input, NULL, NULL, NULL, NULL, module_open,
+    NULL, module_close };
+static struct inode_operations iops =
+  { &fops, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+    NULL, NULL, NULL, NULL, module_permission };
+
+/* <linux/proc_fs.h> */
+
+static struct proc_dir_entry bogus =
+  { 0, 16, "tcp_ignore_bogus", S_IFREG | S_IRUGO | S_IWUSR, 1, 0, 0, 0, &iops,
+    NULL };
+static struct proc_dir_entry synfin =
+  { 0, 17, "tcp_ignore_synfin", S_IFREG | S_IRUGO | S_IWUSR, 1, 0, 0, 0,
+    &iops, NULL };
+static struct proc_dir_entry ack =
+  { 0, 14, "tcp_ignore_ack", S_IFREG | S_IRUGO | S_IWUSR, 1, 0, 0, 0, &iops,
+    NULL };
+
+int
+init_module (void)
+{
+  proc_net_register (&bogus);
+  proc_net_register (&synfin);
+  proc_net_register (&ack);
+  register_firewall (PF_INET, &ipfw_ops);
+  return (0);
+}
+
+void
+cleanup_module (void)
+{
+  proc_net_unregister (bogus.low_ino);
+  proc_net_unregister (synfin.low_ino);
+  proc_net_unregister (ack.low_ino);
+  unregister_firewall (PF_INET, &ipfw_ops);
+}
diff -urP linux/net/ipv4/sysctl_net_ipv4.c linux/net/ipv4/sysctl_net_ipv4.c
--- linux/net/ipv4/sysctl_net_ipv4.c	Sun Dec 10 19:49:44 2000
+++ linux/net/ipv4/sysctl_net_ipv4.c	Fri Dec 15 12:19:01 2000
@@ -51,6 +51,9 @@
 extern int sysctl_tcp_rfc1337;
 extern int sysctl_tcp_syn_taildrop; 
 extern int sysctl_max_syn_backlog; 
+extern int sysctl_tcp_ignore_synfin;
+extern int sysctl_tcp_ignore_bogus;
+extern int sysctl_tcp_ignore_ack;
 
 /* From icmp.c */
 extern int sysctl_icmp_destunreach_time;
@@ -165,6 +168,14 @@
 #ifdef CONFIG_SYN_COOKIES
 	{NET_TCP_SYNCOOKIES, "tcp_syncookies",
 	 &sysctl_tcp_syncookies, sizeof(int), 0644, NULL, &proc_dointvec},
+#endif
+#ifdef CONFIG_NET_STEALTH
+         {NET_TCP_STACK_SYNFIN, "tcp_ignore_synfin",
+          &sysctl_tcp_ignore_synfin, sizeof(int), 0644, NULL, &proc_dointvec},
+         {NET_TCP_STACK_BOGUS,  "tcp_ignore_bogus",
+          &sysctl_tcp_ignore_bogus, sizeof(int), 0644, NULL, &proc_dointvec},
+         {NET_TCP_STACK_ACK, "tcp_ignore_ack",
+          &sysctl_tcp_ignore_ack, sizeof(int), 0644, NULL, &proc_dointvec},
 #endif
 	{NET_TCP_STDURG, "tcp_stdurg", &sysctl_tcp_stdurg,
 	 sizeof(int), 0644, NULL, &proc_dointvec},
diff -urP linux/net/ipv4/tcp_input.c linux/net/ipv4/tcp_input.c
--- linux/net/ipv4/tcp_input.c	Sun Dec 10 19:49:44 2000
+++ linux/net/ipv4/tcp_input.c	Fri Dec 15 12:19:01 2000
@@ -65,11 +65,21 @@
 #include <linux/ipsec.h>
 
 #ifdef CONFIG_SYSCTL
-#define SYNC_INIT 0 /* let the user enable it */
+#define SYNC_INIT 0 /* let the user enable this */
 #else
 #define SYNC_INIT 1
 #endif
 
+#ifdef CONFIG_NET_STEALTH
+#define TCP_SYNFIN 1
+#define TCP_BOGUS 1 
+#define TCP_ACK 1
+#else
+#define TCP_SYNFIN 0
+#define TCP_BOGUS 0 
+#define TCP_ACK 0  
+#endif
+
 extern int sysctl_tcp_fin_timeout;
 
 /* These are on by default so the code paths get tested.
@@ -80,6 +90,10 @@
 int sysctl_tcp_sack = 1;
 
 int sysctl_tcp_syncookies = SYNC_INIT; 
+int sysctl_tcp_ignore_synfin = TCP_SYNFIN;
+int sysctl_tcp_ignore_bogus = TCP_BOGUS;  
+int sysctl_tcp_ignore_ack = TCP_ACK;
+
 int sysctl_tcp_stdurg;
 int sysctl_tcp_rfc1337;
 
diff -urP linux/net/ipv4/tcp_ipv4.c linux/net/ipv4/tcp_ipv4.c
--- linux/net/ipv4/tcp_ipv4.c	Sun Dec 10 19:49:44 2000
+++ linux/net/ipv4/tcp_ipv4.c	Fri Dec 15 12:19:01 2000
@@ -67,6 +67,9 @@
 extern int sysctl_tcp_window_scaling;
 extern int sysctl_tcp_sack;
 extern int sysctl_tcp_syncookies;
+extern int sysctl_tcp_ignore_synfin;
+extern int sysctl_tcp_ignore_bogus; 
+extern int sysctl_tcp_ignore_ack;   
 extern int sysctl_ip_dynaddr;
 extern __u32 sysctl_wmem_max;
 extern __u32 sysctl_rmem_max;
@@ -1745,6 +1748,21 @@
 	   len < (th->doff * 4))
 		goto bad_packet;
 
+       if(sysctl_tcp_ignore_synfin) {
+          if(th->fin && th->syn)
+               goto tcp_bad_flags;
+        }
+         
+        if(sysctl_tcp_ignore_bogus) {
+          if(!(th->ack || th->syn || th->rst) || th->res1)
+               goto tcp_bad_flags;
+       }
+
+       if(sysctl_tcp_ignore_ack) {
+          if(th->fin && th->psh && th->urg)
+               goto tcp_bad_flags;
+       }
+
 #ifdef CONFIG_IP_TRANSPARENT_PROXY
 	if (IPCB(skb)->redirport)
 		sk = tcp_v4_proxy_lookup(th->dest, skb->nh.iph->saddr, th->source,
@@ -1778,6 +1796,32 @@
 
 	__skb_queue_tail(&sk->back_log, skb);
 	return 0;
+
+#ifdef CONFIG_NET_STEALTH_LOG
+tcp_bad_flags:
+       printk(KERN_INFO
+               "Packet log: badflag DENY %s PROTO=TCP %d.%d.%d.%d:%d "
+               "%d.%d.%d.%d:%d L=%hu:%u:%u S=0x%2.2hX I=%hu:%u:%u "
+               "T=%hu %c%c%c%c%c%c%c%c\n",
+               skb->dev->name, NIPQUAD(skb->nh.iph->saddr), ntohs(th->source),
+               NIPQUAD(skb->nh.iph->daddr), ntohs(th->dest),
+               ntohs(skb->nh.iph->tot_len), skb->len, skb->len - th->doff*4,
+               skb->nh.iph->tos, ntohs(skb->nh.iph->id), ntohl(th->seq),
+               ntohl(th->ack_seq), skb->nh.iph->ttl,
+               th->res1 ? '1' : '.',
+               th->res2 ? '2' : '.',
+               th->ack ? 'A' : '.',
+               th->syn ? 'S' : '.',
+               th->fin ? 'F' : '.',
+               th->rst ? 'R' : '.',
+               th->psh ? 'P' : '.',
+               th->urg ? 'U' : '.' );
+       goto bad_packet;
+
+#else
+tcp_bad_flags:
+       goto bad_packet;
+#endif
 
 no_tcp_socket:
 	tcp_v4_send_reset(skb);
