diff -ruN iptables-1.2.orig/extensions/.PSD-test iptables-1.2/extensions/.PSD-test
--- iptables-1.2.orig/extensions/.PSD-test	Thu Jan  1 01:00:00 1970
+++ iptables-1.2/extensions/.PSD-test	Thu Feb  8 16:21:02 2001
@@ -0,0 +1,3 @@
+#! /bin/sh
+# True if PSD is applied.
+[ -f $KERNEL_DIR/include/linux/netfilter_ipv4/ipt_PSD.h ] && echo PSD
diff -ruN iptables-1.2.orig/extensions/libipt_PSD.c iptables-1.2/extensions/libipt_PSD.c
--- iptables-1.2.orig/extensions/libipt_PSD.c	Thu Jan  1 01:00:00 1970
+++ iptables-1.2/extensions/libipt_PSD.c	Thu Feb  8 16:21:02 2001
@@ -0,0 +1,314 @@
+/* 
+  Shared library add-on to iptables to add PSD support 
+   
+  Copyright (C) 2000,2001 astaro AG
+
+  This file is distributed under the terms of the GNU General Public
+  License (GPL). Copies of the GPL can be obtained from:
+     ftp://prep.ai.mit.edu/pub/gnu/GPL
+
+  2000-05-04 Markus Hennig <hennig@astaro.de> : initial
+  2000-08-18 Dennis Koslowski <koslowski@astaro.de> : first release
+  2000-12-01 Dennis Koslowski <koslowski@astaro.de> : UDP scans detection added
+*/
+
+#include <stdio.h>
+#include <netdb.h>
+#include <string.h>
+#include <stdlib.h>
+#include <syslog.h>
+#include <getopt.h>
+#include <iptables.h>
+#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter_ipv4/ipt_PSD.h>
+
+
+/* Function which prints out usage message. */
+static void
+help(void)
+{
+	printf(
+"PSD v%s options:\n"
+" --PSD-log-prefix       prefix      Log messages prefix.\n\n"
+" --PSD-loglevel         level       Level of logging (numeric or see syslog.conf) \n\n"
+" --PSD-weight-threshold threshhold  Portscan detection weight threshold\n\n"
+" --PSD-delay-threshold  delay       Portscan detection delay threshold\n\n"
+" --PSD-lo-ports-weight  lo          Privileged ports weight\n\n"
+" --PSD-hi-ports-weight  hi          High ports weight\n\n",
+NETFILTER_VERSION);
+}
+
+#define LOG_DEFAULT_LEVEL LOG_WARNING
+
+static struct option opts[] = {
+	{ "PSD-log-level", 1, 0, '!' },
+	{ "PSD-log-prefix", 1, 0, '#' },
+	{ "PSD-weight-threshold", 1, 0, '1' },
+	{ "PSD-delay-threshold", 1, 0, '2' },
+	{ "PSD-lo-ports-weight", 1, 0, '3' },
+	{ "PSD-hi-ports-weight", 1, 0, '4' },
+	{ 0 }
+};
+
+/* Initialize the target. */
+static void
+init(struct ipt_entry_target *t, unsigned int *nfcache)
+{
+	struct ipt_psd_info *psdinfo = (struct ipt_psd_info *)t->data;
+
+	psdinfo->level = LOG_DEFAULT_LEVEL;
+	psdinfo->weight_threshold = SCAN_WEIGHT_THRESHOLD;  
+	psdinfo->delay_threshold = SCAN_DELAY_THRESHOLD;
+	psdinfo->lo_ports_weight = PORT_WEIGHT_PRIV;
+	psdinfo->hi_ports_weight = PORT_WEIGHT_HIGH;
+	strcpy(psdinfo->prefix, LOG_PREFIX);
+	/* Can't cache this */
+	*nfcache |= NFC_UNKNOWN;
+}
+
+
+typedef struct _code {
+	char	*c_name;
+	int	c_val;
+} CODE;
+
+CODE prioritynames[] =
+  {
+    { "alert", LOG_ALERT },
+    { "crit", LOG_CRIT },
+    { "debug", LOG_DEBUG },
+    { "emerg", LOG_EMERG },
+    { "err", LOG_ERR },
+    { "error", LOG_ERR },		/* DEPRECATED */
+    { "info", LOG_INFO },
+    { "notice", LOG_NOTICE },
+    { "panic", LOG_EMERG },		/* DEPRECATED */
+    { "warn", LOG_WARNING },		/* DEPRECATED */
+    { "warning", LOG_WARNING },
+    { NULL, -1 }
+  };
+
+
+static u_int8_t
+parse_level(const char *level)
+{
+        int lev;
+
+        lev = string_to_number(level, 0, 7);
+
+        if (lev == -1) {
+
+                unsigned int i = 0;
+
+                for (i = 0;
+		     prioritynames[i].c_name;
+                     i++) {
+
+			if (strncasecmp(level, prioritynames[i].c_name,
+                                        strlen(level)) == 0) {
+                                if (lev != -1)
+                                        exit_error(PARAMETER_PROBLEM,
+                                                   "log-level `%s' ambiguous",
+                                                   level);
+                                lev = prioritynames[i].c_val;
+				break;
+                        }
+                }
+                if (lev == -1)
+                        exit_error(PARAMETER_PROBLEM,
+                                   "log-level `%s' unknown", level);
+        }
+
+        return (u_int8_t)lev;
+}
+
+
+
+#define IPT_PSD_OPT_LEVEL 0x01
+#define IPT_PSD_OPT_PREFIX 0x02
+#define IPT_PSD_OPT_CTRESH 0x04
+#define IPT_PSD_OPT_DTRESH 0x08
+#define IPT_PSD_OPT_LPWEIGHT 0x10
+#define IPT_PSD_OPT_HPWEIGHT 0x20
+
+/* Function which parses command options; returns true if it
+   ate an option */
+static int
+parse(int c, char **argv, int invert, unsigned int *flags,
+      const struct ipt_entry *entry,
+      struct ipt_entry_target **target)
+{
+	struct ipt_psd_info *psdinfo = (struct ipt_psd_info *)(*target)->data;
+	int num;
+
+	switch (c) {
+	case '!':
+		if (*flags & IPT_PSD_OPT_LEVEL)
+			exit_error(PARAMETER_PROBLEM,
+				   "Can't specify --PSD-log-level twice");
+
+		if (check_inverse(optarg, &invert))
+			exit_error(PARAMETER_PROBLEM,
+				   "Unexpected `!' after --PSD-log-level");
+
+		psdinfo->level = parse_level(optarg);
+		*flags |= IPT_PSD_OPT_LEVEL;
+		break;
+
+	case '#':
+		if (*flags & IPT_PSD_OPT_PREFIX)
+			exit_error(PARAMETER_PROBLEM,
+				   "Can't specify --PSD-log-prefix twice");
+
+		if (check_inverse(optarg, &invert))
+			exit_error(PARAMETER_PROBLEM,
+				   "Unexpected `!' after --PSD-log-prefix");
+
+		if (strlen(optarg) > sizeof(psdinfo->prefix) - 1)
+			exit_error(PARAMETER_PROBLEM,
+				   "Maximum prefix length %u for --PSD-log-prefix",
+				   sizeof(psdinfo->prefix) - 1);
+
+		strcpy(psdinfo->prefix, optarg);
+		*flags |= IPT_PSD_OPT_PREFIX;
+		break;
+
+	/* PSD-weight-threshold */
+	case '1':
+		if (*flags & IPT_PSD_OPT_CTRESH)
+			exit_error(PARAMETER_PROBLEM,
+				   "Can't specify --PSD-weight-threshold "
+				   "twice");
+                num = string_to_number(optarg, 0, 10000);
+                if (num <= 0)
+                        exit_error(PARAMETER_PROBLEM,
+                                   "bad --PSD-weight-threshold `%s'", optarg);
+		psdinfo->weight_threshold = num;
+		*flags |= IPT_PSD_OPT_CTRESH;
+		break;
+
+	/* PSD-delay-threshold */
+	case '2':
+		if (*flags & IPT_PSD_OPT_DTRESH)
+			exit_error(PARAMETER_PROBLEM,
+				   "Can't specify --PSD-delay-threshold twice");
+                num = string_to_number(optarg, 0, 10000);
+                if (num <= 0)
+                        exit_error(PARAMETER_PROBLEM,
+                                   "bad --PSD-delay-threshold `%s'", optarg);
+		psdinfo->delay_threshold = num;
+		*flags |= IPT_PSD_OPT_DTRESH;
+		break;
+
+	/* PSD-lo-ports-weight */
+	case '3':
+		if (*flags & IPT_PSD_OPT_LPWEIGHT)
+			exit_error(PARAMETER_PROBLEM,
+				   "Can't specify --PSD-lo-ports-weight twice");
+                num = string_to_number(optarg, 0, 10000);
+                if (num <= 0)
+                        exit_error(PARAMETER_PROBLEM,
+                                   "bad --PSD-lo-ports-weight `%s'", optarg);
+		psdinfo->lo_ports_weight = num;
+		*flags |= IPT_PSD_OPT_LPWEIGHT;
+		break;
+
+	/* PSD-hi-ports-weight */
+	case '4':
+		if (*flags & IPT_PSD_OPT_HPWEIGHT)
+			exit_error(PARAMETER_PROBLEM,
+				   "Can't specify --PSD-hi-ports-weight twice");
+                num = string_to_number(optarg, 0, 10000);
+                if (num <= 0)
+                        exit_error(PARAMETER_PROBLEM,
+                                   "bad --PSD-hi-ports-weight `%s'", optarg);
+		psdinfo->hi_ports_weight = num;
+		*flags |= IPT_PSD_OPT_HPWEIGHT;
+		break;
+
+	default:
+		return 0;
+	}
+
+	return 1;
+}
+
+/* Final check; nothing. */
+static void final_check(unsigned int flags)
+{
+}
+
+/* Prints out the targinfo. */
+static void
+print(const struct ipt_ip *ip,
+      const struct ipt_entry_target *target,
+      int numeric)
+{
+	const struct ipt_psd_info *psdinfo
+		= (const struct ipt_psd_info *)target->data;
+	unsigned int i = 0;
+
+	printf("PSD ");
+	printf("weight-threshold: %u ",psdinfo->weight_threshold);
+	printf("delay-threshold: %u ",psdinfo->delay_threshold);
+	printf("lo-ports-weight: %u ",psdinfo->lo_ports_weight);
+	printf("hi-ports-weight: %u ",psdinfo->hi_ports_weight);
+
+	if (numeric) {
+	  printf("level: %u ",psdinfo->level);
+	} else {
+	  for (i = 0; i < sizeof(prioritynames) / sizeof(CODE);
+                     i++) {
+                        if (psdinfo->level == prioritynames[i].c_val) {
+                                printf("level: %s ", prioritynames[i].c_name);
+                                break;
+                        }
+                }
+           if (i == sizeof(prioritynames) / sizeof(CODE))
+                        printf("UNKNOWN level: %u ", psdinfo->level);
+	}
+
+	if (strcmp(psdinfo->prefix, "") != 0)
+		printf("prefix `%s' ", psdinfo->prefix);
+}
+
+/* Saves the union ipt_targinfo in parsable form to stdout. */
+static void
+save(const struct ipt_ip *ip, const struct ipt_entry_target *target)
+{
+	const struct ipt_psd_info *psdinfo
+		= (const struct ipt_psd_info *)target->data;
+
+	if (strcmp(psdinfo->prefix, "") != 0)
+		printf("--PSD-log-prefix %s ", psdinfo->prefix);
+
+	
+	if (psdinfo->level != LOG_DEFAULT_LEVEL)
+		printf("--PSD-log-level %u ", psdinfo->level);
+
+	printf("--PSD-weight-threshold %u ", psdinfo->weight_threshold);
+	printf("--PSD-delay-threshold %u ", psdinfo->delay_threshold);
+}
+
+struct iptables_target psd
+= { NULL,
+    "PSD",
+    NETFILTER_VERSION,
+    IPT_ALIGN(sizeof(struct ipt_psd_info)),
+    IPT_ALIGN(sizeof(struct ipt_psd_info)),
+    &help,
+    &init,
+    &parse,
+    &final_check,
+    &print,
+    &save,
+    opts
+};
+
+void _init(void)
+{
+	register_target(&psd);
+}
+
+
+
Binary files iptables-1.2.orig/extensions/libipt_ah.so and iptables-1.2/extensions/libipt_ah.so differ
Binary files iptables-1.2.orig/extensions/libipt_esp.so and iptables-1.2/extensions/libipt_esp.so differ
diff -ruN iptables-1.2.orig/patch-o-matic/PSD.patch iptables-1.2/patch-o-matic/PSD.patch
--- iptables-1.2.orig/patch-o-matic/PSD.patch	Thu Jan  1 01:00:00 1970
+++ iptables-1.2/patch-o-matic/PSD.patch	Mon Feb 12 12:33:36 2001
@@ -0,0 +1,533 @@
+--- /dev/null	Mon Nov 13 17:38:28 2000
++++ linux/include/linux/netfilter_ipv4/ipt_PSD.h	Thu Feb  8 16:41:19 2001
+@@ -0,0 +1,54 @@
++#ifndef _IPT_PSD_H
++#define _IPT_PSD_H
++
++#include <linux/param.h>
++#include <linux/types.h>
++
++/*
++ * High port numbers have a lower weight to reduce the frequency of false
++ * positives, such as from passive mode FTP transfers.
++ */
++#define PORT_WEIGHT_PRIV		3
++#define PORT_WEIGHT_HIGH		1
++
++/*
++ * Port scan detection thresholds: at least COUNT ports need to be scanned
++ * from the same source, with no longer than DELAY ticks between ports.
++ */
++#define SCAN_MIN_COUNT			7
++#define SCAN_MAX_COUNT			(SCAN_MIN_COUNT * PORT_WEIGHT_PRIV)
++#define SCAN_WEIGHT_THRESHOLD		SCAN_MAX_COUNT
++#define SCAN_DELAY_THRESHOLD		(HZ * 3)
++
++/*
++ * Keep track of up to LIST_SIZE source addresses, using a hash table of
++ * HASH_SIZE entries for faster lookups, but limiting hash collisions to
++ * HASH_MAX source addresses per the same hash value.
++ */
++#define LIST_SIZE			0x100
++#define HASH_LOG			9
++#define HASH_SIZE			(1 << HASH_LOG)
++#define HASH_MAX			0x10
++
++/*
++ * Log flood detection thresholds: temporarily stop logging if more than
++ * COUNT port scans are detected with no longer than DELAY between them.
++ */
++#define LOG_COUNT_THRESHOLD		5
++#define LOG_DELAY_THRESHOLD		(HZ * 20)
++
++/*
++ * Default log prefix
++ */
++#define LOG_PREFIX "PORTSCAN: "
++
++struct ipt_psd_info {
++	unsigned char level;
++        unsigned int  weight_threshold;
++	unsigned int  delay_threshold;
++	unsigned short lo_ports_weight;
++	unsigned short hi_ports_weight;
++	char          prefix[30];
++};
++
++#endif /*_IPT_PSD_H*/
+--- /dev/null	Mon Nov 13 17:38:28 2000
++++ linux/net/ipv4/netfilter/ipt_PSD.c	Mon Feb 12 11:54:47 2001
+@@ -0,0 +1,473 @@
++/*
++  This is a module which is used for PSD (portscan detection)
++  Derived from scanlogd v2.1 written by Solar Designer <solar@false.com>
++  and LOG target module.
++
++  Copyright (C) 2000,2001 astaro AG
++
++  This file is distributed under the terms of the GNU General Public
++  License (GPL). Copies of the GPL can be obtained from:
++     ftp://prep.ai.mit.edu/pub/gnu/GPL
++
++  2000-05-04 Markus Hennig <hennig@astaro.de> : initial
++  2000-08-18 Dennis Koslowski <koslowski@astaro.de> : first release
++  2000-12-01 Dennis Koslowski <koslowski@astaro.de> : UDP scans detection added
++  2001-01-02 Dennis Koslowski <koslowski@astaro.de> : output modified
++  2001-02-08 Dennis Koslowski <koslowski@astaro.de> : bugfixes & hash locking (thanks to Jan Rekorajski)
++*/
++
++#include <linux/module.h>
++#include <linux/skbuff.h>
++#include <linux/ip.h>
++#include <net/tcp.h>
++#include <linux/spinlock.h>
++#include <linux/netfilter_ipv4/ip_tables.h>
++#include <linux/netfilter_ipv4/ipt_PSD.h>
++
++#if 0
++#define DEBUGP printk
++#else
++#define DEBUGP(format, args...)
++#endif
++
++#define HF_DADDR_CHANGING   0x01
++#define HF_SPORT_CHANGING   0x02
++#define HF_TOS_CHANGING	    0x04
++#define HF_TTL_CHANGING	    0x08
++            
++/*
++ * Information we keep per each target port
++ */
++struct port {
++	u_int16_t number;      /* port number */ 
++	u_int8_t proto;        /* protocol number */
++	u_int8_t and_flags;    /* tcp ANDed flags */
++	u_int8_t or_flags;     /* tcp ORed flags */
++};
++
++/*
++ * Information we keep per each source address.
++ */
++struct host {
++	struct host *next;		/* Next entry with the same hash */
++	clock_t timestamp;		/* Last update time */
++	struct in_addr src_addr;	/* Source address */
++	struct in_addr dest_addr;	/* Destination address */
++	unsigned short src_port;	/* Source port */
++	int count;			/* Number of ports in the list */
++	int weight;			/* Total weight of ports in the list */
++	struct port ports[SCAN_MAX_COUNT - 1];	/* List of ports */
++	unsigned char tos;		/* TOS */
++	unsigned char ttl;		/* TTL */
++	unsigned char flags;		/* HF_ flags bitmask */
++};
++
++/*
++ * State information.
++ */
++static struct {
++	spinlock_t  lock;               /* Hashtable and printk lock */
++	struct host list[LIST_SIZE];	/* List of source addresses */
++	struct host *hash[HASH_SIZE];	/* Hash: pointers into the list */
++	int index;			/* Oldest entry to be replaced */
++} state;
++
++/*
++ * Convert an IP address into a hash table index.
++ */
++static inline int hashfunc(struct in_addr addr)
++{
++	unsigned int value;
++	int hash;
++	
++	value = addr.s_addr;
++	hash = 0;
++	do {
++		hash ^= value;
++	} while ((value >>= HASH_LOG));
++	
++	return hash & (HASH_SIZE - 1);
++}
++
++/*
++ * Log this port scan.
++ */
++static inline void do_log(struct host *info, const struct ipt_psd_info *psdinfo)
++{
++	int limit;
++	int index;
++	unsigned char mask, bit;
++	int and_bit, or_bit;
++	char flags_str[9];
++	
++
++	limit = info->count;
++	
++	/* Source address and port number, if fixed */
++	printk("%sPortscan detected from %u.%u.%u.%u", psdinfo->prefix, NIPQUAD(info->src_addr));
++	
++	if (!(info->flags & HF_SPORT_CHANGING)) {
++		printk(":%u",(unsigned int)ntohs(info->src_port));
++	}
++	
++	/* Destination address */
++	printk(" to %u.%u.%u.%u", NIPQUAD(info->dest_addr));
++	if (info->flags & HF_DADDR_CHANGING) {
++		printk(" and others");
++	}
++	
++	/* TOS, if fixed */
++	if (!(info->flags & HF_TOS_CHANGING)) {
++		printk(", TOS %02x", (unsigned int)info->tos);
++	}
++	
++	/* TTL, if fixed */
++	if (!(info->flags & HF_TTL_CHANGING)) {
++		printk(", TTL %u", (unsigned int)info->ttl);
++	}
++	
++	/* Scanned port numbers */
++	printk(", scanned ports:\n");
++	for (index = 0; index < limit; index++) {
++		
++		printk("%s%5u, ",
++		       psdinfo->prefix, 
++		       (unsigned int)ntohs(info->ports[index].number));
++		
++		switch (info->ports[index].proto) {
++
++		case IPPROTO_TCP:
++			for (bit = 0; bit < 8; bit++) {
++				mask = 1 << bit;
++				and_bit = info->ports[index].and_flags & mask;
++				or_bit = info->ports[index].or_flags & mask;
++				
++				if (and_bit == or_bit) {
++					
++					if (and_bit)
++						flags_str[bit] = "FSRPAUXY"[bit];
++					else
++						flags_str[bit] = "fsrpauxy"[bit];
++				} else {
++					flags_str[bit] = '?';
++				} 
++			}
++			flags_str[8] = 0x0;
++			printk("TCP with flags %s\n", flags_str);
++			break;
++
++		case IPPROTO_UDP:
++			printk("UDP\n");
++			break;
++
++		default:
++			printk("invalid protocol code\n");
++			break;
++		}
++	}
++	
++	/* Done */
++	printk("%sProbably more ports were scanned\n",psdinfo->prefix);
++}
++
++/*
++ * Log this port scan unless we're being flooded.
++ */
++static inline void safe_log(struct host *info, const struct ipt_psd_info *psdinfo)
++{
++	static clock_t last = 0;
++	static int count = 0;
++	clock_t now;
++	char level_string[4] = "<0>";
++
++	now = info->timestamp;
++	if (now - last > LOG_DELAY_THRESHOLD || now < last) count = 0;
++	if (++count <= LOG_COUNT_THRESHOLD + 1) last = now;
++
++	level_string[1] += (psdinfo->level % 8);
++
++	printk(level_string);
++
++	if (count <= LOG_COUNT_THRESHOLD) {
++		do_log(info,psdinfo);
++	} else if (count == LOG_COUNT_THRESHOLD + 1) {
++		printk("%sMore possible port scans follow\n",psdinfo->prefix);
++	}
++}
++
++static unsigned int
++ipt_psd_target(struct sk_buff **pskb,
++	       unsigned int hooknum,
++	       const struct net_device *in,
++	       const struct net_device *out,
++	       const void *targinfo, void *userinfo)
++{
++	struct iphdr *ip_hdr;
++	struct tcphdr *tcp_hdr;
++	struct in_addr addr;
++	u_int16_t src_port,dest_port;
++  	u_int8_t tcp_flags, proto;
++	clock_t now;
++	struct host *curr, *last, **head;
++	int hash, index, count;
++	int psd_verdict = IPT_CONTINUE;
++
++	/* Parameters from userspace */
++	const struct ipt_psd_info *psdinfo = targinfo;
++
++	/* IP header */
++	ip_hdr = (*pskb)->nh.iph;
++
++	/* Sanity check */
++	if (ntohs(ip_hdr->frag_off) & IP_OFFSET) {
++		DEBUGP("PSD: sanity check failed\n");
++		goto go_home;
++	}
++
++	/* TCP or UDP ? */
++	proto = ip_hdr->protocol;
++
++	if (proto != IPPROTO_TCP && proto != IPPROTO_UDP) {
++		DEBUGP("PSD: protocol not supported\n");
++		goto go_home;
++	}
++
++	/* Get the source address, source & destination ports, and TCP flags */
++
++	addr.s_addr = ip_hdr->saddr;
++
++	tcp_hdr = (struct tcphdr*)((u_int32_t *)ip_hdr + ip_hdr->ihl);
++
++	/* Yep, itīs dirty */
++	src_port = tcp_hdr->source;
++	dest_port = tcp_hdr->dest;
++
++	if (proto == IPPROTO_TCP) {
++		tcp_flags = *((u_int8_t*)tcp_hdr + 13);
++	}
++	else {
++		tcp_flags = 0x00;
++	}
++
++	/* We're using IP address 0.0.0.0 for a special purpose here, so don't let
++	 * them spoof us. */
++	if (!addr.s_addr) {
++		DEBUGP("PSD: spoofed source address (0.0.0.0)\n");
++		goto go_home;
++	}
++
++	/* Use jiffies here not to depend on someone setting the time while we're
++	 * running; we need to be careful with possible return value overflows. */
++	now = jiffies;
++
++	count = 0;
++	last = NULL;
++
++	/* Do locking  */
++	spin_lock_bh(&state.lock);
++
++	/* Do we know this source address already? */
++	if ((curr = *(head = &state.hash[hash = hashfunc(addr)])))
++		do {
++			if (curr->src_addr.s_addr == addr.s_addr) break;
++			count++;
++			if (curr->next) last = curr;
++		} while ((curr = curr->next));
++	
++	if (curr) {
++
++		/* We know this address, and the entry isn't too old. Update it. */
++		if (now - curr->timestamp <= (psdinfo->delay_threshold*HZ)/100 &&
++		    time_after_eq(now, curr->timestamp)) {
++			
++			/* Just update the appropriate list entry if we've seen this port already */
++			for (index = 0; index < curr->count; index++) {
++				if (curr->ports[index].number == dest_port) {
++					curr->ports[index].proto = proto;
++					curr->ports[index].and_flags &= tcp_flags;
++					curr->ports[index].or_flags |= tcp_flags;
++					goto unlock_and_go;
++				}
++			}
++			
++			/* TCP/ACK and/or TCP/RST to a new port? This could be an outgoing connection. */
++			if (proto == IPPROTO_TCP && (tcp_hdr->ack || tcp_hdr->rst))
++				goto unlock_and_go;
++			
++			/* Packet to a new port, and not TCP/ACK: update the timestamp */
++			curr->timestamp = now;
++			
++			/* Logged this scan already? Then drop the packet. */
++			if (curr->weight >= psdinfo->weight_threshold) {
++				psd_verdict = NF_DROP;
++				goto unlock_and_go;
++			}
++			
++			/* Specify if destination address, source port, TOS or TTL are not fixed */
++			if (curr->dest_addr.s_addr != ip_hdr->daddr)
++				curr->flags |= HF_DADDR_CHANGING;
++			if (curr->src_port != src_port)
++				curr->flags |= HF_SPORT_CHANGING;
++			if (curr->tos != ip_hdr->tos)
++				curr->flags |= HF_TOS_CHANGING;
++			if (curr->ttl != ip_hdr->ttl)
++				curr->flags |= HF_TTL_CHANGING;
++			
++			/* Update the total weight */
++			curr->weight += (ntohs(dest_port) < 1024) ?
++				psdinfo->lo_ports_weight : psdinfo->hi_ports_weight;
++			
++			/* Got enough destination ports to decide that this is a scan? */
++			/* Then log it and drop the packet. */
++			if (curr->weight >= psdinfo->weight_threshold) {
++				safe_log(curr,psdinfo);
++				psd_verdict = NF_DROP;
++				goto unlock_and_go;
++			}
++			
++			/* Remember the new port */
++			if (curr->count < SCAN_MAX_COUNT) {
++				curr->ports[curr->count].number = dest_port;
++				curr->ports[curr->count].proto = proto;
++				curr->ports[curr->count].and_flags = tcp_flags;
++				curr->ports[curr->count].or_flags = tcp_flags;
++				curr->count++;
++			}
++
++			goto unlock_and_go;
++		}
++	
++		/* We know this address, but the entry is outdated. Mark it unused, and
++		 * remove from the hash table. We'll allocate a new entry instead since
++		 * this one might get re-used too soon. */
++		curr->src_addr.s_addr = 0;
++		if (last)
++			last->next = last->next->next;
++		else if (*head)
++			*head = (*head)->next;
++		last = NULL;
++	}
++
++	/* We don't need an ACK from a new source address */
++	if (proto == IPPROTO_TCP && tcp_hdr->ack) 
++		goto unlock_and_go;
++
++	/* Got too many source addresses with the same hash value? Then remove the
++	 * oldest one from the hash table, so that they can't take too much of our
++	 * CPU time even with carefully chosen spoofed IP addresses. */
++	if (count >= HASH_MAX && last) last->next = NULL;
++
++	/* We're going to re-use the oldest list entry, so remove it from the hash
++	 * table first (if it is really already in use, and isn't removed from the
++	 * hash table already because of the HASH_MAX check above). */
++	
++	/* First, find it */
++	if (state.list[state.index].src_addr.s_addr)
++		head = &state.hash[hashfunc(state.list[state.index].src_addr)];
++	else
++		head = &last;
++
++	last = NULL;
++	
++	if ((curr = *head))
++		do {
++			if (curr == &state.list[state.index]) break;
++			last = curr;
++		} while ((curr = curr->next));
++	
++	/* Then, remove it */
++	if (curr) {
++		if (last)
++			last->next = last->next->next;
++		else if (*head)
++			*head = (*head)->next;
++	}
++
++	/* Get our list entry */
++	curr = &state.list[state.index++];
++	if (state.index >= LIST_SIZE) state.index = 0;
++
++	/* Link it into the hash table */
++	head = &state.hash[hash];
++	curr->next = *head;
++	*head = curr;
++
++	/* And fill in the fields */
++	curr->timestamp = now;
++	curr->src_addr = addr;
++	curr->dest_addr.s_addr = ip_hdr->daddr;
++	curr->src_port = src_port;
++	curr->count = 1;
++	curr->weight = (ntohs(dest_port) < 1024) ?
++		psdinfo->lo_ports_weight : psdinfo->hi_ports_weight;
++	curr->ports[0].number = dest_port;
++	curr->ports[0].proto = proto;
++	curr->ports[0].and_flags = tcp_flags;
++	curr->ports[0].or_flags = tcp_flags;
++	curr->tos = ip_hdr->tos;
++	curr->ttl = ip_hdr->ttl;
++
++ unlock_and_go:
++	spin_unlock_bh(&state.lock);
++
++ go_home:
++	return psd_verdict;
++}
++
++static int ipt_psd_checkentry(const char *tablename,
++			      const struct ipt_entry *e,
++			      void *targinfo,
++			      unsigned int targinfosize,
++			      unsigned int hook_mask)
++{
++	const struct ipt_psd_info *psdinfo = targinfo;
++
++	if (targinfosize != IPT_ALIGN(sizeof(struct ipt_psd_info))) {
++		DEBUGP("PSD: targinfosize %u != %u\n",
++		       targinfosize,
++		       IPT_ALIGN(sizeof(struct ipt_psd_info)));
++		return 0;
++	}
++
++	if (psdinfo->level >= 8) {
++		DEBUGP("PSD: level %u >= 8\n", psdinfo->level);
++		return 0;
++	}
++
++	if (psdinfo->prefix[sizeof(psdinfo->prefix) - 1] != '\0') {
++		DEBUGP("PSD: prefix term %i\n",
++		       psdinfo->prefix[sizeof(psdinfo->prefix) - 1]);
++		return 0;
++	}
++
++	return 1;
++}
++
++static struct ipt_target ipt_psd_reg = { 
++	{NULL, NULL},
++	"PSD",
++	ipt_psd_target,
++	ipt_psd_checkentry,
++	NULL,
++	THIS_MODULE };
++
++static int __init init(void)
++{
++	if (ipt_register_target(&ipt_psd_reg))
++		return -EINVAL;
++
++	memset(&state, 0, sizeof(state));
++	spin_lock_init(&state.lock);
++
++	printk("netfilter PSD loaded - (c) astaro AG\n");
++	return 0;
++}
++
++static void __exit fini(void)
++{
++	ipt_unregister_target(&ipt_psd_reg);
++	printk("netfilter PSD unloaded - (c) astaro AG\n");
++}
++
++module_init(init);
++module_exit(fini);
diff -ruN iptables-1.2.orig/patch-o-matic/PSD.patch.config.in iptables-1.2/patch-o-matic/PSD.patch.config.in
--- iptables-1.2.orig/patch-o-matic/PSD.patch.config.in	Thu Jan  1 01:00:00 1970
+++ iptables-1.2/patch-o-matic/PSD.patch.config.in	Thu Feb  8 16:21:02 2001
@@ -0,0 +1,4 @@
+  dep_tristate '  LOG target support' CONFIG_IP_NF_TARGET_LOG $CONFIG_IP_NF_IPTABLES
+  if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+    dep_tristate '  PSD target support (EXPERIMENTAL)' CONFIG_IP_NF_TARGET_PSD $CONFIG_IP_NF_IPTABLES
+  fi
diff -ruN iptables-1.2.orig/patch-o-matic/PSD.patch.configure.help iptables-1.2/patch-o-matic/PSD.patch.configure.help
--- iptables-1.2.orig/patch-o-matic/PSD.patch.configure.help	Thu Jan  1 01:00:00 1970
+++ iptables-1.2/patch-o-matic/PSD.patch.configure.help	Thu Feb  8 16:21:02 2001
@@ -0,0 +1,10 @@
+CONFIG_IP_NF_TARGET_LOG
+PSD target support
+CONFIG_IP_NF_TARGET_PSD
+  This option adds a `PSD' target, which allows you to create rules in
+  any iptables table wich will detect TCP and UDP port scans and log
+  they to the syslog.
+ 
+  If you want to compile it as a module, say M here and read
+  Documentation/modules.txt.  If unsure, say `N'.
+
diff -ruN iptables-1.2.orig/patch-o-matic/PSD.patch.help iptables-1.2/patch-o-matic/PSD.patch.help
--- iptables-1.2.orig/patch-o-matic/PSD.patch.help	Thu Jan  1 01:00:00 1970
+++ iptables-1.2/patch-o-matic/PSD.patch.help	Thu Feb  8 16:21:02 2001
@@ -0,0 +1,41 @@
+Author: Dennis Koslowski <koslowski@astaro.de>
+Status: Experimental
+
+This option adds CONFIG_IP_NF_TARGET_PSD, which supplies portscan
+detection tagret (PSD). This target will attempt to detect TCP and UDP
+port scans and log they to the syslog. This target was derived from
+Solar Designerīs scanlogd.
+
+Suppported options are:
+
+--PSD-log-level <level>
+
+  Level of logging (numeric or see syslog.conf(5))
+
+--PSD-log-prefix <prefix> 
+
+  Prefix log messages with the specified prefix; up to 29 letters
+  long, and useful for distinguishing messages in the logs.
+
+--PSD-weight-threshold <threshold>
+
+  Total weight of the latest TCP/UDP packets with different
+  destination ports coming from the same host to be treated as port
+  scan sequence.
+
+--PSD-delay-threshold <delay>
+
+  Delay (in hundredths of second) for the packets with different
+  destination ports coming from the same host to be treated as
+  a possible port scan subsequence.
+
+--PSD-lo-ports-weight <weight>
+
+  Weight of the packet with privileged (<=1024) destination port.
+
+--PSD-hi-ports-weight <weight>
+
+  Weight of the packet with non-priviliged destination port.
+
+
+
diff -ruN iptables-1.2.orig/patch-o-matic/PSD.patch.makefile iptables-1.2/patch-o-matic/PSD.patch.makefile
--- iptables-1.2.orig/patch-o-matic/PSD.patch.makefile	Thu Jan  1 01:00:00 1970
+++ iptables-1.2/patch-o-matic/PSD.patch.makefile	Thu Feb  8 16:21:02 2001
@@ -0,0 +1,4 @@
+obj-$(CONFIG_IP_NF_TARGET_LOG) += ipt_LOG.o
+
+obj-$(CONFIG_IP_NF_TARGET_PSD) += ipt_PSD.o
+
