OSF split from linux into linux-2.4 and linux-2.6

Evgeniy Polyakov johnpol@2ka.mipt.ru
Sun, 18 Jul 2004 00:25:35 +0400


This is a multi-part message in MIME format.

--Multipart=_Sun__18_Jul_2004_00_25_35_+0400_u9MvSL1Iq.o/BSMm
Content-Type: text/plain; charset=US-ASCII
Content-Transfer-Encoding: 7bit

Please review and comment.
Just creating 2 new directories insted of one and update osf to be
compiled in 2.6.

Please review and comment.

	Evgeniy Polyakov ( s0mbre )

Only failure makes us experts. -- Theo de Raadt

--Multipart=_Sun__18_Jul_2004_00_25_35_+0400_u9MvSL1Iq.o/BSMm
Content-Type: text/plain;
 name="osf.diff"
Content-Disposition: attachment;
 filename="osf.diff"
Content-Transfer-Encoding: 7bit

diff -Nru ./patch-o-matic-ng/osf.old/linux/CVS/Entries ./patch-o-matic-ng/osf/linux/CVS/Entries
--- ./patch-o-matic-ng/osf.old/linux/CVS/Entries	2004-07-18 00:07:11.000000000 +0400
+++ ./patch-o-matic-ng/osf/linux/CVS/Entries	1970-01-01 03:00:00.000000000 +0300
@@ -1,3 +0,0 @@
-D/include////
-D/net////
-D/Documentation////
diff -Nru ./patch-o-matic-ng/osf.old/linux/CVS/Repository ./patch-o-matic-ng/osf/linux/CVS/Repository
--- ./patch-o-matic-ng/osf.old/linux/CVS/Repository	2004-07-18 00:07:11.000000000 +0400
+++ ./patch-o-matic-ng/osf/linux/CVS/Repository	1970-01-01 03:00:00.000000000 +0300
@@ -1 +0,0 @@
-patch-o-matic-ng/osf/linux
diff -Nru ./patch-o-matic-ng/osf.old/linux/CVS/Root ./patch-o-matic-ng/osf/linux/CVS/Root
--- ./patch-o-matic-ng/osf.old/linux/CVS/Root	2004-07-18 00:07:11.000000000 +0400
+++ ./patch-o-matic-ng/osf/linux/CVS/Root	1970-01-01 03:00:00.000000000 +0300
@@ -1 +0,0 @@
-:pserver:cvs:cvs@pserver.netfilter.org:/cvspublic
diff -Nru ./patch-o-matic-ng/osf.old/linux/Documentation/Configure.help.ladd ./patch-o-matic-ng/osf/linux/Documentation/Configure.help.ladd
--- ./patch-o-matic-ng/osf.old/linux/Documentation/Configure.help.ladd	2004-07-18 00:07:12.000000000 +0400
+++ ./patch-o-matic-ng/osf/linux/Documentation/Configure.help.ladd	1970-01-01 03:00:00.000000000 +0300
@@ -1,20 +0,0 @@
-CONFIG_IP_NF_MATCH_TOS
-OSF match support
-CONFIG_IP_NF_MATCH_OSF
-
-  The idea of passive OS fingerprint matching exists for quite a long time,
-  but was created as extension fo OpenBSD pf only some weeks ago.
-  Original idea was lurked in some OpenBSD mailing list (thanks
-  grange@open...) and than adopted for Linux netfilter in form of this code.
-
-  Original table was created by Michal Zalewski <lcamtuf@coredump.cx> for
-  his excellent p0f and than changed a bit for more convenience.
-
-  This module compares some data(WS, MSS, options and it's order, ttl,
-  df and others) from first SYN packet (actually from packets with SYN
-  bit set) with hardcoded in fingers[] table ones.
-
-  If you say Y here, try iptables -m osf --help for more information.
- 
-  If you want to compile it as a module, say M here and read
-  Documentation/modules.txt.  If unsure, say `N'.
diff -Nru ./patch-o-matic-ng/osf.old/linux/Documentation/CVS/Entries ./patch-o-matic-ng/osf/linux/Documentation/CVS/Entries
--- ./patch-o-matic-ng/osf.old/linux/Documentation/CVS/Entries	2004-07-18 00:07:11.000000000 +0400
+++ ./patch-o-matic-ng/osf/linux/Documentation/CVS/Entries	1970-01-01 03:00:00.000000000 +0300
@@ -1,2 +0,0 @@
-/Configure.help.ladd/1.1/Fri Mar  5 09:30:27 2004//
-D
diff -Nru ./patch-o-matic-ng/osf.old/linux/Documentation/CVS/Repository ./patch-o-matic-ng/osf/linux/Documentation/CVS/Repository
--- ./patch-o-matic-ng/osf.old/linux/Documentation/CVS/Repository	2004-07-18 00:07:11.000000000 +0400
+++ ./patch-o-matic-ng/osf/linux/Documentation/CVS/Repository	1970-01-01 03:00:00.000000000 +0300
@@ -1 +0,0 @@
-patch-o-matic-ng/osf/linux/Documentation
diff -Nru ./patch-o-matic-ng/osf.old/linux/Documentation/CVS/Root ./patch-o-matic-ng/osf/linux/Documentation/CVS/Root
--- ./patch-o-matic-ng/osf.old/linux/Documentation/CVS/Root	2004-07-18 00:07:11.000000000 +0400
+++ ./patch-o-matic-ng/osf/linux/Documentation/CVS/Root	1970-01-01 03:00:00.000000000 +0300
@@ -1 +0,0 @@
-:pserver:cvs:cvs@pserver.netfilter.org:/cvspublic
diff -Nru ./patch-o-matic-ng/osf.old/linux/include/CVS/Entries ./patch-o-matic-ng/osf/linux/include/CVS/Entries
--- ./patch-o-matic-ng/osf.old/linux/include/CVS/Entries	2004-07-18 00:07:11.000000000 +0400
+++ ./patch-o-matic-ng/osf/linux/include/CVS/Entries	1970-01-01 03:00:00.000000000 +0300
@@ -1 +0,0 @@
-D/linux////
diff -Nru ./patch-o-matic-ng/osf.old/linux/include/CVS/Repository ./patch-o-matic-ng/osf/linux/include/CVS/Repository
--- ./patch-o-matic-ng/osf.old/linux/include/CVS/Repository	2004-07-18 00:07:11.000000000 +0400
+++ ./patch-o-matic-ng/osf/linux/include/CVS/Repository	1970-01-01 03:00:00.000000000 +0300
@@ -1 +0,0 @@
-patch-o-matic-ng/osf/linux/include
diff -Nru ./patch-o-matic-ng/osf.old/linux/include/CVS/Root ./patch-o-matic-ng/osf/linux/include/CVS/Root
--- ./patch-o-matic-ng/osf.old/linux/include/CVS/Root	2004-07-18 00:07:11.000000000 +0400
+++ ./patch-o-matic-ng/osf/linux/include/CVS/Root	1970-01-01 03:00:00.000000000 +0300
@@ -1 +0,0 @@
-:pserver:cvs:cvs@pserver.netfilter.org:/cvspublic
diff -Nru ./patch-o-matic-ng/osf.old/linux/include/linux/CVS/Entries ./patch-o-matic-ng/osf/linux/include/linux/CVS/Entries
--- ./patch-o-matic-ng/osf.old/linux/include/linux/CVS/Entries	2004-07-18 00:07:11.000000000 +0400
+++ ./patch-o-matic-ng/osf/linux/include/linux/CVS/Entries	1970-01-01 03:00:00.000000000 +0300
@@ -1 +0,0 @@
-D/netfilter_ipv4////
diff -Nru ./patch-o-matic-ng/osf.old/linux/include/linux/CVS/Repository ./patch-o-matic-ng/osf/linux/include/linux/CVS/Repository
--- ./patch-o-matic-ng/osf.old/linux/include/linux/CVS/Repository	2004-07-18 00:07:11.000000000 +0400
+++ ./patch-o-matic-ng/osf/linux/include/linux/CVS/Repository	1970-01-01 03:00:00.000000000 +0300
@@ -1 +0,0 @@
-patch-o-matic-ng/osf/linux/include/linux
diff -Nru ./patch-o-matic-ng/osf.old/linux/include/linux/CVS/Root ./patch-o-matic-ng/osf/linux/include/linux/CVS/Root
--- ./patch-o-matic-ng/osf.old/linux/include/linux/CVS/Root	2004-07-18 00:07:11.000000000 +0400
+++ ./patch-o-matic-ng/osf/linux/include/linux/CVS/Root	1970-01-01 03:00:00.000000000 +0300
@@ -1 +0,0 @@
-:pserver:cvs:cvs@pserver.netfilter.org:/cvspublic
diff -Nru ./patch-o-matic-ng/osf.old/linux/include/linux/netfilter_ipv4/CVS/Entries ./patch-o-matic-ng/osf/linux/include/linux/netfilter_ipv4/CVS/Entries
--- ./patch-o-matic-ng/osf.old/linux/include/linux/netfilter_ipv4/CVS/Entries	2004-07-18 00:07:11.000000000 +0400
+++ ./patch-o-matic-ng/osf/linux/include/linux/netfilter_ipv4/CVS/Entries	1970-01-01 03:00:00.000000000 +0300
@@ -1,2 +0,0 @@
-/ipt_osf.h/1.2/Sat Mar  6 10:30:56 2004//
-D
diff -Nru ./patch-o-matic-ng/osf.old/linux/include/linux/netfilter_ipv4/CVS/Repository ./patch-o-matic-ng/osf/linux/include/linux/netfilter_ipv4/CVS/Repository
--- ./patch-o-matic-ng/osf.old/linux/include/linux/netfilter_ipv4/CVS/Repository	2004-07-18 00:07:11.000000000 +0400
+++ ./patch-o-matic-ng/osf/linux/include/linux/netfilter_ipv4/CVS/Repository	1970-01-01 03:00:00.000000000 +0300
@@ -1 +0,0 @@
-patch-o-matic-ng/osf/linux/include/linux/netfilter_ipv4
diff -Nru ./patch-o-matic-ng/osf.old/linux/include/linux/netfilter_ipv4/CVS/Root ./patch-o-matic-ng/osf/linux/include/linux/netfilter_ipv4/CVS/Root
--- ./patch-o-matic-ng/osf.old/linux/include/linux/netfilter_ipv4/CVS/Root	2004-07-18 00:07:11.000000000 +0400
+++ ./patch-o-matic-ng/osf/linux/include/linux/netfilter_ipv4/CVS/Root	1970-01-01 03:00:00.000000000 +0300
@@ -1 +0,0 @@
-:pserver:cvs:cvs@pserver.netfilter.org:/cvspublic
diff -Nru ./patch-o-matic-ng/osf.old/linux/include/linux/netfilter_ipv4/ipt_osf.h ./patch-o-matic-ng/osf/linux/include/linux/netfilter_ipv4/ipt_osf.h
--- ./patch-o-matic-ng/osf.old/linux/include/linux/netfilter_ipv4/ipt_osf.h	2004-07-18 00:07:11.000000000 +0400
+++ ./patch-o-matic-ng/osf/linux/include/linux/netfilter_ipv4/ipt_osf.h	1970-01-01 03:00:00.000000000 +0300
@@ -1,148 +0,0 @@
-/*
- * ipt_osf.h
- *
- * Copyright (c) 2003 Evgeniy Polyakov <johnpol@2ka.mipt.ru>
- *
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifndef _IPT_OSF_H
-#define _IPT_OSF_H
-
-#define MAXGENRELEN		32
-#define MAXDETLEN		64
-
-#define IPT_OSF_GENRE		1
-#define	IPT_OSF_SMART		2
-#define IPT_OSF_LOG		4
-#define IPT_OSF_NETLINK		8
-
-#define IPT_OSF_LOGLEVEL_ALL	0
-#define IPT_OSF_LOGLEVEL_FIRST	1
-
-#include <linux/list.h>
-
-#ifndef __KERNEL__
-#include <netinet/ip.h>
-#include <netinet/tcp.h>
-
-struct list_head
-{
-	struct list_head *prev, *next;
-};
-#endif
-
-struct ipt_osf_info
-{
-	char 			genre[MAXGENRELEN];
-	int			len;
-	unsigned long		flags;
-	int			loglevel;
-	int			invert; /* UNSUPPORTED */
-};
-
-struct osf_wc
-{
-	char			wc;
-	unsigned long		val;
-};
-
-/* This struct represents IANA options
- * http://www.iana.org/assignments/tcp-parameters
- */
-struct osf_opt
-{
-	unsigned char		kind;
-	unsigned char		length;
-	struct osf_wc		wc;
-};
-
-struct osf_finger
-{
-	struct list_head	flist;
-	struct osf_wc		wss;
-	unsigned char		ttl;
-	unsigned char		df;
-	unsigned long		ss;
-	unsigned char		genre[MAXGENRELEN];
-	unsigned char		version[MAXGENRELEN], subtype[MAXGENRELEN];
-	
-	/* Not needed, but for consistency with original table from Michal Zalewski */
-	unsigned char		details[MAXDETLEN]; 
-
-	int 			opt_num;
-	struct osf_opt		opt[MAX_IPOPTLEN]; /* In case it is all NOP or EOL */
-
-};
-
-struct ipt_osf_nlmsg
-{
-	struct osf_finger	f;
-	struct iphdr 		ip;
-	struct tcphdr 		tcp;
-};
-
-#ifdef __KERNEL__
-
-/* Defines for IANA option kinds */
-
-#define OSFOPT_EOL		0	/* End of options */
-#define OSFOPT_NOP		1	/* NOP */
-#define OSFOPT_MSS		2	/* Maximum segment size */
-#define OSFOPT_WSO		3	/* Window scale option */
-#define OSFOPT_SACKP		4	/* SACK permitted */
-#define OSFOPT_SACK		5	/* SACK */
-#define OSFOPT_ECHO		6	
-#define OSFOPT_ECHOREPLY	7
-#define OSFOPT_TS		8	/* Timestamp option */
-#define OSFOPT_POCP		9	/* Partial Order Connection Permitted */
-#define OSFOPT_POSP		10	/* Partial Order Service Profile */
-/* Others are not used in current OSF */
-
-static struct osf_opt IANA_opts[] = 
-{
-	{0, 1,},
-	{1, 1,},
-	{2, 4,},
-	{3, 3,},
-	{4, 2,},
-	{5, 1 ,}, /* SACK length is not defined */
-	{6, 6,},
-	{7, 6,},
-	{8, 10,},
-	{9, 2,},
-	{10, 3,},
-	{11, 1,}, /* CC: Suppose 1 */
-	{12, 1,}, /* the same */
-	{13, 1,}, /* and here too */
-	{14, 3,},
-	{15, 1,}, /* TCP Alternate Checksum Data. Length is not defined */
-	{16, 1,},
-	{17, 1,},
-	{18, 3,},
-	{19, 18,},
-	{20, 1,},
-	{21, 1,},
-	{22, 1,},
-	{23, 1,},
-	{24, 1,},
-	{25, 1,},
-	{26, 1,},
-};
-
-#endif /* __KERNEL__ */
-
-#endif /* _IPT_OSF_H */
diff -Nru ./patch-o-matic-ng/osf.old/linux/net/CVS/Entries ./patch-o-matic-ng/osf/linux/net/CVS/Entries
--- ./patch-o-matic-ng/osf.old/linux/net/CVS/Entries	2004-07-18 00:07:11.000000000 +0400
+++ ./patch-o-matic-ng/osf/linux/net/CVS/Entries	1970-01-01 03:00:00.000000000 +0300
@@ -1 +0,0 @@
-D/ipv4////
diff -Nru ./patch-o-matic-ng/osf.old/linux/net/CVS/Repository ./patch-o-matic-ng/osf/linux/net/CVS/Repository
--- ./patch-o-matic-ng/osf.old/linux/net/CVS/Repository	2004-07-18 00:07:11.000000000 +0400
+++ ./patch-o-matic-ng/osf/linux/net/CVS/Repository	1970-01-01 03:00:00.000000000 +0300
@@ -1 +0,0 @@
-patch-o-matic-ng/osf/linux/net
diff -Nru ./patch-o-matic-ng/osf.old/linux/net/CVS/Root ./patch-o-matic-ng/osf/linux/net/CVS/Root
--- ./patch-o-matic-ng/osf.old/linux/net/CVS/Root	2004-07-18 00:07:11.000000000 +0400
+++ ./patch-o-matic-ng/osf/linux/net/CVS/Root	1970-01-01 03:00:00.000000000 +0300
@@ -1 +0,0 @@
-:pserver:cvs:cvs@pserver.netfilter.org:/cvspublic
diff -Nru ./patch-o-matic-ng/osf.old/linux/net/ipv4/CVS/Entries ./patch-o-matic-ng/osf/linux/net/ipv4/CVS/Entries
--- ./patch-o-matic-ng/osf.old/linux/net/ipv4/CVS/Entries	2004-07-18 00:07:11.000000000 +0400
+++ ./patch-o-matic-ng/osf/linux/net/ipv4/CVS/Entries	1970-01-01 03:00:00.000000000 +0300
@@ -1 +0,0 @@
-D/netfilter////
diff -Nru ./patch-o-matic-ng/osf.old/linux/net/ipv4/CVS/Repository ./patch-o-matic-ng/osf/linux/net/ipv4/CVS/Repository
--- ./patch-o-matic-ng/osf.old/linux/net/ipv4/CVS/Repository	2004-07-18 00:07:11.000000000 +0400
+++ ./patch-o-matic-ng/osf/linux/net/ipv4/CVS/Repository	1970-01-01 03:00:00.000000000 +0300
@@ -1 +0,0 @@
-patch-o-matic-ng/osf/linux/net/ipv4
diff -Nru ./patch-o-matic-ng/osf.old/linux/net/ipv4/CVS/Root ./patch-o-matic-ng/osf/linux/net/ipv4/CVS/Root
--- ./patch-o-matic-ng/osf.old/linux/net/ipv4/CVS/Root	2004-07-18 00:07:11.000000000 +0400
+++ ./patch-o-matic-ng/osf/linux/net/ipv4/CVS/Root	1970-01-01 03:00:00.000000000 +0300
@@ -1 +0,0 @@
-:pserver:cvs:cvs@pserver.netfilter.org:/cvspublic
diff -Nru ./patch-o-matic-ng/osf.old/linux/net/ipv4/netfilter/Config.in.ladd ./patch-o-matic-ng/osf/linux/net/ipv4/netfilter/Config.in.ladd
--- ./patch-o-matic-ng/osf.old/linux/net/ipv4/netfilter/Config.in.ladd	2004-07-18 00:07:11.000000000 +0400
+++ ./patch-o-matic-ng/osf/linux/net/ipv4/netfilter/Config.in.ladd	1970-01-01 03:00:00.000000000 +0300
@@ -1,4 +0,0 @@
-  dep_tristate '  TOS match support' CONFIG_IP_NF_MATCH_TOS $CONFIG_IP_NF_IPTABLES
-  if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-    dep_tristate '  OSF match support (EXPERIMENTAL)' CONFIG_IP_NF_MATCH_OSF $CONFIG_IP_NF_IPTABLES
-  fi
diff -Nru ./patch-o-matic-ng/osf.old/linux/net/ipv4/netfilter/CVS/Entries ./patch-o-matic-ng/osf/linux/net/ipv4/netfilter/CVS/Entries
--- ./patch-o-matic-ng/osf.old/linux/net/ipv4/netfilter/CVS/Entries	2004-07-18 00:07:11.000000000 +0400
+++ ./patch-o-matic-ng/osf/linux/net/ipv4/netfilter/CVS/Entries	1970-01-01 03:00:00.000000000 +0300
@@ -1,5 +0,0 @@
-/Config.in.ladd/1.1/Thu Dec 18 18:28:43 2003//
-/Makefile.ladd/1.1/Thu Dec 18 18:28:43 2003//
-/Kconfig.ladd/1.2/Mon Jun 14 10:27:09 2004//
-/ipt_osf.c/1.2/Sat Mar  6 10:30:57 2004//
-D
diff -Nru ./patch-o-matic-ng/osf.old/linux/net/ipv4/netfilter/CVS/Repository ./patch-o-matic-ng/osf/linux/net/ipv4/netfilter/CVS/Repository
--- ./patch-o-matic-ng/osf.old/linux/net/ipv4/netfilter/CVS/Repository	2004-07-18 00:07:11.000000000 +0400
+++ ./patch-o-matic-ng/osf/linux/net/ipv4/netfilter/CVS/Repository	1970-01-01 03:00:00.000000000 +0300
@@ -1 +0,0 @@
-patch-o-matic-ng/osf/linux/net/ipv4/netfilter
diff -Nru ./patch-o-matic-ng/osf.old/linux/net/ipv4/netfilter/CVS/Root ./patch-o-matic-ng/osf/linux/net/ipv4/netfilter/CVS/Root
--- ./patch-o-matic-ng/osf.old/linux/net/ipv4/netfilter/CVS/Root	2004-07-18 00:07:11.000000000 +0400
+++ ./patch-o-matic-ng/osf/linux/net/ipv4/netfilter/CVS/Root	1970-01-01 03:00:00.000000000 +0300
@@ -1 +0,0 @@
-:pserver:cvs:cvs@pserver.netfilter.org:/cvspublic
diff -Nru ./patch-o-matic-ng/osf.old/linux/net/ipv4/netfilter/ipt_osf.c ./patch-o-matic-ng/osf/linux/net/ipv4/netfilter/ipt_osf.c
--- ./patch-o-matic-ng/osf.old/linux/net/ipv4/netfilter/ipt_osf.c	2004-07-18 00:07:11.000000000 +0400
+++ ./patch-o-matic-ng/osf/linux/net/ipv4/netfilter/ipt_osf.c	1970-01-01 03:00:00.000000000 +0300
@@ -1,865 +0,0 @@
-/*
- * ipt_osf.c
- *
- * Copyright (c) 2003 Evgeniy Polyakov <johnpol@2ka.mipt.ru>
- *
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-/*
- * OS fingerprint matching module.
- * It simply compares various parameters from SYN packet with
- * some hardcoded ones.
- *
- * Original table was created by Michal Zalewski <lcamtuf@coredump.cx>
- * for his p0f.
- */
-
-#include <linux/config.h>
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/string.h>
-#include <linux/smp.h>
-#include <linux/module.h>
-#include <linux/skbuff.h>
-#include <linux/file.h>
-#include <linux/ip.h>
-#include <linux/proc_fs.h>
-#include <linux/fs.h>
-#include <linux/slab.h>
-#include <linux/spinlock.h>
-#include <linux/ctype.h>
-#include <linux/list.h>
-#include <linux/if.h>
-
-#include <net/sock.h>
-#include <net/ip.h>
-
-#include <linux/netfilter_ipv4/ip_tables.h>
-
-#include <linux/netfilter_ipv4/ipt_osf.h>
-
-#define OSF_DEBUG
-
-#ifdef OSF_DEBUG
-#define log(x...) 		printk(KERN_INFO "ipt_osf: " x)
-#define loga(x...) 		printk(x)
-#else
-#define log(x...) 		do {} while(0)
-#define loga(x...) 		do {} while(0)
-#endif
-
-#define FMATCH_WRONG		0
-#define FMATCH_OK		1
-#define FMATCH_OPT_WRONG	2
-
-#define OPTDEL			','
-#define OSFPDEL 		':'
-#define MAXOPTSTRLEN		128
-#define OSFFLUSH		"FLUSH"
-
-static rwlock_t osf_lock = RW_LOCK_UNLOCKED;
-static spinlock_t ipt_osf_netlink_lock = SPIN_LOCK_UNLOCKED;
-static struct list_head	finger_list;	
-static int match(const struct sk_buff *, const struct net_device *, const struct net_device *,
-		      const void *, int, 
-		      const void *, u_int16_t, 
-		      int *);
-static int checkentry(const char *, const struct ipt_ip *, void *,
-		           unsigned int, unsigned int);
-
-static unsigned long seq, ipt_osf_groups = 1;
-static struct sock *nts;
-
-static struct ipt_match osf_match = 
-{ 
-	{ NULL, NULL }, 
-	"osf", 
-	&match, 
-	&checkentry, 
-	NULL, 
-	THIS_MODULE 
-};
-
-static void ipt_osf_nlsend(struct osf_finger *f, const struct sk_buff *sk)
-{
-	unsigned int size;
-	struct sk_buff *skb;
-	struct ipt_osf_nlmsg *data;
-	struct nlmsghdr *nlh;
-
-	size = NLMSG_SPACE(sizeof(struct ipt_osf_nlmsg));
-
-	skb = alloc_skb(size, GFP_ATOMIC);
-	if (!skb)
-	{
-		log("skb_alloc() failed.\n");
-		return;
-	}
-	
-	nlh = NLMSG_PUT(skb, 0, seq++, NLMSG_DONE, size - sizeof(*nlh));
-	
-	data = (struct ipt_osf_nlmsg *)NLMSG_DATA(nlh);
-
-	memcpy(&data->f, f, sizeof(struct osf_finger));
-	memcpy(&data->ip, sk->nh.iph, sizeof(struct iphdr));
-	memcpy(&data->tcp, (struct tcphdr *)((u_int32_t *)sk->nh.iph + sk->nh.iph->ihl), sizeof(struct tcphdr));
-
-	NETLINK_CB(skb).dst_groups = ipt_osf_groups;
-	netlink_broadcast(nts, skb, 0, ipt_osf_groups, GFP_ATOMIC);
-
-nlmsg_failure:
-	return;
-}
-
-static inline int smart_dec(const struct sk_buff *skb, unsigned long flags, unsigned char f_ttl)
-{
-	struct iphdr *ip = skb->nh.iph;
-
-	if (flags & IPT_OSF_SMART)
-	{
-		struct in_device *in_dev = in_dev_get(skb->dev);
-
-		for_ifa(in_dev)
-		{
-			if (inet_ifa_match(ip->saddr, ifa))
-			{
-				in_dev_put(in_dev);
-				return (ip->ttl == f_ttl);
-			}
-		}
-		endfor_ifa(in_dev);
-		
-		in_dev_put(in_dev);
-		return (ip->ttl <= f_ttl);
-	}
-	else
-		return (ip->ttl == f_ttl);
-}
-
-static int
-match(const struct sk_buff *skb, const struct net_device *in, const struct net_device *out,
-      const void *matchinfo, int offset,
-      const void *hdr, u_int16_t datalen,
-      int *hotdrop)
-{
-	struct ipt_osf_info *info = (struct ipt_osf_info *)matchinfo;
-	struct iphdr *ip = skb->nh.iph;
-	struct tcphdr *tcp;
-	int fmatch = FMATCH_WRONG, fcount = 0;
-	unsigned long totlen, optsize = 0, window;
-	unsigned char df, *optp = NULL, *_optp = NULL;
-	char check_WSS = 0;
-	struct list_head *ent;
-	struct osf_finger *f;
-
-	if (!ip || !info)
-		return 0;
-				
-	tcp = (struct tcphdr *)((u_int32_t *)ip + ip->ihl);
-
-	if (!tcp->syn)
-		return 0;
-	
-	totlen = ntohs(ip->tot_len);
-	df = ((ntohs(ip->frag_off) & IP_DF)?1:0);
-	window = ntohs(tcp->window);
-	
-	if (tcp->doff*4 > sizeof(struct tcphdr))
-	{
-		_optp = optp = (char *)(tcp+1);
-		optsize = tcp->doff*4 - sizeof(struct tcphdr);
-	}
-
-	
-	/* Actually we can create hash/table of all genres and search
-	 * only in appropriate part, but here is initial variant,
-	 * so will use slow path.
-	 */
-	read_lock(&osf_lock);
-	list_for_each(ent, &finger_list)
-	{
-		f = list_entry(ent, struct osf_finger, flist);
-	
-		if (!(info->flags & IPT_OSF_LOG) && strcmp(info->genre, f->genre)) 
-			continue;
-
-		optp = _optp;
-		fmatch = FMATCH_WRONG;
-
-		if (totlen == f->ss && df == f->df && 
-			smart_dec(skb, info->flags, f->ttl))
-		{
-			unsigned long foptsize;
-			int optnum;
-			unsigned short mss = 0;
-
-			check_WSS = 0;
-
-			switch (f->wss.wc)
-			{
-				case 0:	  check_WSS = 0; break;
-				case 'S': check_WSS = 1; break;
-				case 'T': check_WSS = 2; break;
-				case '%': check_WSS = 3; break;
-				default: log("Wrong fingerprint wss.wc=%d, %s - %s\n", 
-							 f->wss.wc, f->genre, f->details);
-					 check_WSS = 4;
-					 break;
-			}
-			if (check_WSS == 4)
-				continue;
-
-			/* Check options */
-
-			foptsize = 0;
-			for (optnum=0; optnum<f->opt_num; ++optnum)
-				foptsize += f->opt[optnum].length;
-
-				
-			if (foptsize > MAX_IPOPTLEN || optsize > MAX_IPOPTLEN || optsize != foptsize)
-				continue;
-
-			if (!optp)
-			{
-				fmatch = FMATCH_OK;
-				loga("\tYEP : matching without options.\n");
-				if ((info->flags & IPT_OSF_LOG) && 
-					info->loglevel == IPT_OSF_LOGLEVEL_FIRST)
-					break;
-				else
-					continue;
-			}
-			
-
-			for (optnum=0; optnum<f->opt_num; ++optnum)
-			{
-				if (f->opt[optnum].kind == (*optp)) 
-				{
-					unsigned char len = f->opt[optnum].length;
-					unsigned char *optend = optp + len;
-					int loop_cont = 0;
-
-					fmatch = FMATCH_OK;
-
-
-					switch (*optp)
-					{
-						case OSFOPT_MSS:
-							mss = ntohs(*(unsigned short *)(optp+2));
-							break;
-						case OSFOPT_TS:
-							loop_cont = 1;
-							break;
-					}
-					
-					if (loop_cont)
-					{
-						optp = optend;
-						continue;
-					}
-					
-					if (len != 1)
-					{
-						/* Skip kind and length fields*/
-						optp += 2; 
-
-						if (f->opt[optnum].wc.val != 0)
-						{
-							unsigned long tmp = 0;
-							
-							/* Hmmm... It looks a bit ugly. :) */
-							memcpy(&tmp, optp, 
-								(len > sizeof(unsigned long)?
-								 	sizeof(unsigned long):len));
-							/* 2 + 2: optlen(2 bytes) + 
-							 * 	kind(1 byte) + length(1 byte) */
-							if (len == 4) 
-								tmp = ntohs(tmp);
-							else
-								tmp = ntohl(tmp);
-
-							if (f->opt[optnum].wc.wc == '%')
-							{
-								if ((tmp % f->opt[optnum].wc.val) != 0)
-									fmatch = FMATCH_OPT_WRONG;
-							}
-							else if (tmp != f->opt[optnum].wc.val)
-								fmatch = FMATCH_OPT_WRONG;
-						}
-					}
-
-					optp = optend;
-				}
-				else
-					fmatch = FMATCH_OPT_WRONG;
-
-				if (fmatch != FMATCH_OK)
-					break;
-			}
-
-			if (fmatch != FMATCH_OPT_WRONG)
-			{
-				fmatch = FMATCH_WRONG;
-
-				switch (check_WSS)
-				{
-					case 0:
-						if (f->wss.val == 0 || window == f->wss.val)
-							fmatch = FMATCH_OK;
-						break;
-					case 1: /* MSS */
-/* Lurked in OpenBSD */
-#define SMART_MSS	1460
-						if (window == f->wss.val*mss || 
-							window == f->wss.val*SMART_MSS)
-							fmatch = FMATCH_OK;
-						break;
-					case 2: /* MTU */
-						if (window == f->wss.val*(mss+40) ||
-							window == f->wss.val*(SMART_MSS+40))
-							fmatch = FMATCH_OK;
-						break;
-					case 3: /* MOD */
-						if ((window % f->wss.val) == 0)
-							fmatch = FMATCH_OK;
-						break;
-				}
-			}
-					
-
-			if (fmatch == FMATCH_OK)
-			{
-				fcount++;
-				log("%s [%s:%s:%s] : %u.%u.%u.%u:%u -> %u.%u.%u.%u:%u hops=%d\n", 
-					f->genre, f->version,
-					f->subtype, f->details,
-					NIPQUAD(ip->saddr), ntohs(tcp->source),
-					NIPQUAD(ip->daddr), ntohs(tcp->dest),
-					f->ttl - ip->ttl);
-				if (info->flags & IPT_OSF_NETLINK)
-				{
-					spin_lock_bh(&ipt_osf_netlink_lock);
-					ipt_osf_nlsend(f, skb);
-					spin_unlock_bh(&ipt_osf_netlink_lock);
-				}
-				if ((info->flags & IPT_OSF_LOG) && 
-					info->loglevel == IPT_OSF_LOGLEVEL_FIRST)
-					break;
-			}
-		}
-	}
-	if (!fcount && (info->flags & (IPT_OSF_LOG | IPT_OSF_NETLINK)))
-	{
-		unsigned char opt[4 * 15 - sizeof(struct tcphdr)];
-		unsigned int i, optsize;
-		struct osf_finger fg;
-
-		memset(&fg, 0, sizeof(fg));
-
-		if ((info->flags & IPT_OSF_LOG))
-			log("Unknown: %lu:%d:%d:%lu:", window, ip->ttl, df, totlen);
-		if (optp)
-		{
-			optsize = tcp->doff * 4 - sizeof(struct tcphdr);
-			if (skb_copy_bits(skb, ip->ihl*4 + sizeof(struct tcphdr),
-					  opt, optsize) < 0)
-			{
-				if (info->flags & IPT_OSF_LOG)
-					loga("TRUNCATED");
-				if (info->flags & IPT_OSF_NETLINK)
-					strcpy(fg.details, "TRUNCATED");
-			}
-			else
-			{
-				for (i = 0; i < optsize; i++)
-				{
-					if (info->flags & IPT_OSF_LOG)
-						loga("%02X", opt[i]);
-				}
-				if (info->flags & IPT_OSF_NETLINK)
-					memcpy(fg.details, opt, MAXDETLEN);
-			}
-		}
-		if ((info->flags & IPT_OSF_LOG))
-			loga(" %u.%u.%u.%u:%u -> %u.%u.%u.%u:%u\n", 
-				NIPQUAD(ip->saddr), ntohs(tcp->source),
-				NIPQUAD(ip->daddr), ntohs(tcp->dest));
-		
-		if (info->flags & IPT_OSF_NETLINK)
-		{
-			fg.wss.val 	= window;
-			fg.ttl		= ip->ttl;
-			fg.df		= df;
-			fg.ss		= totlen;
-			strncpy(fg.genre, "Unknown", MAXGENRELEN);
-
-			spin_lock_bh(&ipt_osf_netlink_lock);
-			ipt_osf_nlsend(&fg, skb);
-			spin_unlock_bh(&ipt_osf_netlink_lock);
-		}
-	}
-
-	read_unlock(&osf_lock);
-
-	return (fmatch == FMATCH_OK)?1:0;
-}
-
-static int
-checkentry(const char *tablename,
-           const struct ipt_ip *ip,
-           void *matchinfo,
-           unsigned int matchsize,
-           unsigned int hook_mask)
-{
-       if (matchsize != IPT_ALIGN(sizeof(struct ipt_osf_info)))
-               return 0;
-       if (ip->proto != IPPROTO_TCP)
-	       return 0;
-
-       return 1;
-}
-
-static char * osf_strchr(char *ptr, char c)
-{
-	char *tmp;
-
-	tmp = strchr(ptr, c);
-
-	while (tmp && tmp+1 && isspace(*(tmp+1)))
-		tmp++;
-
-	return tmp;
-}
-
-static struct osf_finger * finger_alloc(void)
-{
-	struct osf_finger *f;
-
-	f = kmalloc(sizeof(struct osf_finger), GFP_KERNEL);
-	if (f)
-		memset(f, 0, sizeof(struct osf_finger));
-	
-	return f;
-}
-
-static void finger_free(struct osf_finger *f)
-{
-	memset(f, 0, sizeof(struct osf_finger));
-	kfree(f);
-}
-
-
-static void osf_parse_opt(struct osf_opt *opt, int *optnum, char *obuf, int olen)
-{
-	int i, op;
-	char *ptr, wc;
-	unsigned long val;
-
-	ptr = &obuf[0];
-	i = 0;
-	while (ptr != NULL && i < olen)
-	{
-		val = 0;
-		op = 0;
-		wc = 0;
-		switch (obuf[i])
-		{
-			case 'N': 
-				op = OSFOPT_NOP;
-				ptr = osf_strchr(&obuf[i], OPTDEL);
-				if (ptr)
-				{
-					*ptr = '\0';
-					ptr++;
-					i += (int)(ptr-&obuf[i]);
-
-				}
-				else
-					i++;
-				break;
-			case 'S': 
-				op = OSFOPT_SACKP;
-				ptr = osf_strchr(&obuf[i], OPTDEL);
-				if (ptr)
-				{
-					*ptr = '\0';
-					ptr++;
-					i += (int)(ptr-&obuf[i]);
-
-				}
-				else
-					i++;
-				break;
-			case 'T': 
-				op = OSFOPT_TS;
-				ptr = osf_strchr(&obuf[i], OPTDEL);
-				if (ptr)
-				{
-					*ptr = '\0';
-					ptr++;
-					i += (int)(ptr-&obuf[i]);
-
-				}
-				else
-					i++;
-				break;
-			case 'W': 
-				op = OSFOPT_WSO;
-				ptr = osf_strchr(&obuf[i], OPTDEL);
-				if (ptr)
-				{
-					switch (obuf[i+1])
-					{
-						case '%':	wc = '%'; break;
-						case 'S':	wc = 'S'; break;
-						case 'T':	wc = 'T'; break;
-						default:	wc = 0; break;
-					}
-					
-					*ptr = '\0';
-					ptr++;
-					if (wc)
-						val = simple_strtoul(&obuf[i+2], NULL, 10);
-					else
-						val = simple_strtoul(&obuf[i+1], NULL, 10);
-					i += (int)(ptr-&obuf[i]);
-
-				}
-				else
-					i++;
-				break;
-			case 'M': 
-				op = OSFOPT_MSS;
-				ptr = osf_strchr(&obuf[i], OPTDEL);
-				if (ptr)
-				{
-					if (obuf[i+1] == '%')
-						wc = '%';
-					*ptr = '\0';
-					ptr++;
-					if (wc)
-						val = simple_strtoul(&obuf[i+2], NULL, 10);
-					else
-						val = simple_strtoul(&obuf[i+1], NULL, 10);
-					i += (int)(ptr-&obuf[i]);
-
-				}
-				else
-					i++;
-				break;
-			case 'E': 
-				op = OSFOPT_EOL;
-				ptr = osf_strchr(&obuf[i], OPTDEL);
-				if (ptr)
-				{
-					*ptr = '\0';
-					ptr++;
-					i += (int)(ptr-&obuf[i]);
-
-				}
-				else
-					i++;
-				break;
-			default:
-				ptr = osf_strchr(&obuf[i], OPTDEL);
-				if (ptr)
-				{
-					ptr++;
-					i += (int)(ptr-&obuf[i]);
-
-				}
-				else
-					i++;
-				break;
-		}
-
-		opt[*optnum].kind 	= IANA_opts[op].kind;
-		opt[*optnum].length 	= IANA_opts[op].length;
-		opt[*optnum].wc.wc 	= wc;
-		opt[*optnum].wc.val	= val;
-
-		(*optnum)++;
-	}
-}
-
-static int osf_proc_read(char *buf, char **start, off_t off, int count, int *eof, void *data)
-{
-	struct list_head *ent;
-	struct osf_finger *f = NULL;
-	int i;
-	
-	*eof = 1;
-	count = 0;
-
-	read_lock_bh(&osf_lock);
-	list_for_each(ent, &finger_list)
-	{
-		f = list_entry(ent, struct osf_finger, flist);
-
-		log("%s [%s]", f->genre, f->details);
-		
-		count += sprintf(buf+count, "%s - %s[%s] : %s", 
-					f->genre, f->version,
-					f->subtype, f->details);
-		
-		if (f->opt_num)
-		{
-			loga(" OPT: ");
-			//count += sprintf(buf+count, " OPT: ");
-			for (i=0; i<f->opt_num; ++i)
-			{
-				//count += sprintf(buf+count, "%d.%c%lu; ", 
-				//	f->opt[i].kind, (f->opt[i].wc.wc)?f->opt[i].wc.wc:' ', f->opt[i].wc.val);
-				loga("%d.%c%lu; ", 
-					f->opt[i].kind, (f->opt[i].wc.wc)?f->opt[i].wc.wc:' ', f->opt[i].wc.val);
-			}
-		}
-		loga("\n");
-		count += sprintf(buf+count, "\n");
-	}
-	read_unlock_bh(&osf_lock);
-
-	return count;
-}
-
-static int osf_proc_write(struct file *file, const char *buffer, unsigned long count, void *data)
-{
-	int cnt;
-	unsigned long i;
-	char obuf[MAXOPTSTRLEN];
-	struct osf_finger *finger;
-	struct list_head *ent, *n;
-
-	char *pbeg, *pend;
-
-	if (count == strlen(OSFFLUSH) && !strncmp(buffer, OSFFLUSH, strlen(OSFFLUSH)))
-	{
-		int i = 0;
-		write_lock_bh(&osf_lock);
-		list_for_each_safe(ent, n, &finger_list)
-		{
-			i++;
-			finger = list_entry(ent, struct osf_finger, flist);
-			list_del(&finger->flist);
-			finger_free(finger);
-		}
-		write_unlock_bh(&osf_lock);
-	
-		log("Flushed %d entries.\n", i);
-		
-		return count;
-	}
-
-	
-	cnt = 0;
-	for (i=0; i<count && buffer[i] != '\0'; ++i)
-		if (buffer[i] == ':')
-			cnt++;
-
-	if (cnt != 8 || i != count)
-	{
-		log("Wrong input line cnt=%d[8], len=%lu[%lu]\n", 
-			cnt, i, count);
-		return count;
-	}
-
-	memset(obuf, 0, sizeof(obuf));
-	
-	finger = finger_alloc();
-	if (!finger)
-	{
-		log("Failed to allocate new fingerprint entry.\n");
-		return -ENOMEM;
-	}
-
-	pbeg = (char *)buffer;
-	pend = osf_strchr(pbeg, OSFPDEL);
-	if (pend)
-	{
-		*pend = '\0';
-		if (pbeg[0] == 'S')
-		{
-			finger->wss.wc = 'S';
-			if (pbeg[1] == '%')
-				finger->wss.val = simple_strtoul(pbeg+2, NULL, 10);
-			else if (pbeg[1] == '*')
-				finger->wss.val = 0;
-			else 
-				finger->wss.val = simple_strtoul(pbeg+1, NULL, 10);
-		}
-		else if (pbeg[0] == 'T')
-		{
-			finger->wss.wc = 'T';
-			if (pbeg[1] == '%')
-				finger->wss.val = simple_strtoul(pbeg+2, NULL, 10);
-			else if (pbeg[1] == '*')
-				finger->wss.val = 0;
-			else 
-				finger->wss.val = simple_strtoul(pbeg+1, NULL, 10);
-		}
-		else if (pbeg[0] == '%')
-		{
-			finger->wss.wc = '%';
-			finger->wss.val = simple_strtoul(pbeg+1, NULL, 10);
-		}
-		else if (isdigit(pbeg[0]))
-		{
-			finger->wss.wc = 0;
-			finger->wss.val = simple_strtoul(pbeg, NULL, 10);
-		}
-
-		pbeg = pend+1;
-	}
-	pend = osf_strchr(pbeg, OSFPDEL);
-	if (pend)
-	{
-		*pend = '\0';
-		finger->ttl = simple_strtoul(pbeg, NULL, 10);
-		pbeg = pend+1;
-	}
-	pend = osf_strchr(pbeg, OSFPDEL);
-	if (pend)
-	{
-		*pend = '\0';
-		finger->df = simple_strtoul(pbeg, NULL, 10);
-		pbeg = pend+1;
-	}
-	pend = osf_strchr(pbeg, OSFPDEL);
-	if (pend)
-	{
-		*pend = '\0';
-		finger->ss = simple_strtoul(pbeg, NULL, 10);
-		pbeg = pend+1;
-	}
-
-	pend = osf_strchr(pbeg, OSFPDEL);
-	if (pend)
-	{
-		*pend = '\0';
-		cnt = snprintf(obuf, sizeof(obuf), "%s", pbeg);
-		pbeg = pend+1;
-	}
-
-	pend = osf_strchr(pbeg, OSFPDEL);
-	if (pend)
-	{
-		*pend = '\0';
-		if (pbeg[0] == '@' || pbeg[0] == '*')
-			cnt = snprintf(finger->genre, sizeof(finger->genre), "%s", pbeg+1);
-		else
-			cnt = snprintf(finger->genre, sizeof(finger->genre), "%s", pbeg);
-		pbeg = pend+1;
-	}
-	
-	pend = osf_strchr(pbeg, OSFPDEL);
-	if (pend)
-	{
-		*pend = '\0';
-		cnt = snprintf(finger->version, sizeof(finger->version), "%s", pbeg);
-		pbeg = pend+1;
-	}
-	
-	pend = osf_strchr(pbeg, OSFPDEL);
-	if (pend)
-	{
-		*pend = '\0';
-		cnt = snprintf(finger->subtype, sizeof(finger->subtype), "%s", pbeg);
-		pbeg = pend+1;
-	}
-
-	cnt = snprintf(finger->details, 
-			((count - (pbeg - buffer)+1) > MAXDETLEN)?MAXDETLEN:(count - (pbeg - buffer)+1), 
-			"%s", pbeg);
-	
-	log("%s - %s[%s] : %s\n", 
-		finger->genre, finger->version,
-		finger->subtype, finger->details);
-	
-	osf_parse_opt(finger->opt, &finger->opt_num, obuf, sizeof(obuf));
-	
-
-	write_lock_bh(&osf_lock);
-	list_add_tail(&finger->flist, &finger_list);
-	write_unlock_bh(&osf_lock);
-
-	return count;
-}
-
-static int __init osf_init(void)
-{
-	int err;
-	struct proc_dir_entry *p;
-
-	log("Startng OS fingerprint matching module.\n");
-
-	INIT_LIST_HEAD(&finger_list);
-	
-	err = ipt_register_match(&osf_match);
-	if (err)
-	{
-		log("Failed to register OS fingerprint matching module.\n");
-		return -ENXIO;
-	}
-
-	p = create_proc_entry("sys/net/ipv4/osf", S_IFREG | 0644, NULL);
-	if (!p)
-	{
-		ipt_unregister_match(&osf_match);
-		return -ENXIO;
-	}
-
-	p->write_proc = osf_proc_write;
-	p->read_proc  = osf_proc_read;
-	
-	nts = netlink_kernel_create(NETLINK_NFLOG, NULL);
-	if (!nts)
-	{
-		log("netlink_kernel_create() failed\n");
-		remove_proc_entry("sys/net/ipv4/osf", NULL);
-		ipt_unregister_match(&osf_match);
-		return -ENOMEM;
-	}
-
-	return 0;
-}
-
-static void __exit osf_fini(void)
-{
-	struct list_head *ent, *n;
-	struct osf_finger *f;
-	
-	remove_proc_entry("sys/net/ipv4/osf", NULL);
-	ipt_unregister_match(&osf_match);
-	if (nts && nts->socket)
-		sock_release(nts->socket);
-
-	list_for_each_safe(ent, n, &finger_list)
-	{
-		f = list_entry(ent, struct osf_finger, flist);
-		list_del(&f->flist);
-		finger_free(f);
-	}
-	
-	log("OS fingerprint matching module finished.\n");
-}
-
-module_init(osf_init);
-module_exit(osf_fini);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Evgeniy Polyakov <johnpol@2ka.mipt.ru>");
-MODULE_DESCRIPTION("Passive OS fingerprint matching.");
diff -Nru ./patch-o-matic-ng/osf.old/linux/net/ipv4/netfilter/Kconfig.ladd ./patch-o-matic-ng/osf/linux/net/ipv4/netfilter/Kconfig.ladd
--- ./patch-o-matic-ng/osf.old/linux/net/ipv4/netfilter/Kconfig.ladd	2004-07-18 00:07:11.000000000 +0400
+++ ./patch-o-matic-ng/osf/linux/net/ipv4/netfilter/Kconfig.ladd	1970-01-01 03:00:00.000000000 +0300
@@ -1,21 +0,0 @@
-config IP_NF_MATCH_OSF
-	tristate  'OSF match support'
-	depends on IP_NF_IPTABLES
-	help
-	
-	  The idea of passive OS fingerprint matching exists for quite a long time,
-	  but was created as extension fo OpenBSD pf only some weeks ago.
-	  Original idea was lurked in some OpenBSD mailing list (thanks
-	  grange@open...) and than adopted for Linux netfilter in form of this code.
-	
-	  Original table was created by Michal Zalewski <lcamtuf@coredump.cx> for
-	  his excellent p0f and than changed a bit for more convenience.
-	
-	  This module compares some data(WS, MSS, options and it's order, ttl,
-	  df and others) from first SYN packet (actually from packets with SYN
-	  bit set) with hardcoded in fingers[] table ones.
-	
-	  If you say Y here, try iptables -m osf --help for more information.
-	 
-	  If you want to compile it as a module, say M here and read
-	  Documentation/modules.txt.  If unsure, say `N'.
diff -Nru ./patch-o-matic-ng/osf.old/linux/net/ipv4/netfilter/Makefile.ladd ./patch-o-matic-ng/osf/linux/net/ipv4/netfilter/Makefile.ladd
--- ./patch-o-matic-ng/osf.old/linux/net/ipv4/netfilter/Makefile.ladd	2004-07-18 00:07:11.000000000 +0400
+++ ./patch-o-matic-ng/osf/linux/net/ipv4/netfilter/Makefile.ladd	1970-01-01 03:00:00.000000000 +0300
@@ -1,4 +0,0 @@
-obj-$(CONFIG_IP_NF_MATCH_TOS) += ipt_tos.o
-
-obj-$(CONFIG_IP_NF_MATCH_OSF) += ipt_osf.o
-
diff -Nru ./patch-o-matic-ng/osf.old/linux-2.4/CVS/Entries ./patch-o-matic-ng/osf/linux-2.4/CVS/Entries
--- ./patch-o-matic-ng/osf.old/linux-2.4/CVS/Entries	1970-01-01 03:00:00.000000000 +0300
+++ ./patch-o-matic-ng/osf/linux-2.4/CVS/Entries	2004-06-14 14:27:19.000000000 +0400
@@ -0,0 +1,3 @@
+D/include////
+D/net////
+D/Documentation////
diff -Nru ./patch-o-matic-ng/osf.old/linux-2.4/CVS/Repository ./patch-o-matic-ng/osf/linux-2.4/CVS/Repository
--- ./patch-o-matic-ng/osf.old/linux-2.4/CVS/Repository	1970-01-01 03:00:00.000000000 +0300
+++ ./patch-o-matic-ng/osf/linux-2.4/CVS/Repository	2004-01-31 15:25:05.000000000 +0300
@@ -0,0 +1 @@
+patch-o-matic-ng/osf/linux
diff -Nru ./patch-o-matic-ng/osf.old/linux-2.4/CVS/Root ./patch-o-matic-ng/osf/linux-2.4/CVS/Root
--- ./patch-o-matic-ng/osf.old/linux-2.4/CVS/Root	1970-01-01 03:00:00.000000000 +0300
+++ ./patch-o-matic-ng/osf/linux-2.4/CVS/Root	2004-01-31 15:25:05.000000000 +0300
@@ -0,0 +1 @@
+:pserver:cvs:cvs@pserver.netfilter.org:/cvspublic
diff -Nru ./patch-o-matic-ng/osf.old/linux-2.4/Documentation/Configure.help.ladd ./patch-o-matic-ng/osf/linux-2.4/Documentation/Configure.help.ladd
--- ./patch-o-matic-ng/osf.old/linux-2.4/Documentation/Configure.help.ladd	1970-01-01 03:00:00.000000000 +0300
+++ ./patch-o-matic-ng/osf/linux-2.4/Documentation/Configure.help.ladd	2004-03-05 12:30:27.000000000 +0300
@@ -0,0 +1,20 @@
+CONFIG_IP_NF_MATCH_TOS
+OSF match support
+CONFIG_IP_NF_MATCH_OSF
+
+  The idea of passive OS fingerprint matching exists for quite a long time,
+  but was created as extension fo OpenBSD pf only some weeks ago.
+  Original idea was lurked in some OpenBSD mailing list (thanks
+  grange@open...) and than adopted for Linux netfilter in form of this code.
+
+  Original table was created by Michal Zalewski <lcamtuf@coredump.cx> for
+  his excellent p0f and than changed a bit for more convenience.
+
+  This module compares some data(WS, MSS, options and it's order, ttl,
+  df and others) from first SYN packet (actually from packets with SYN
+  bit set) with hardcoded in fingers[] table ones.
+
+  If you say Y here, try iptables -m osf --help for more information.
+ 
+  If you want to compile it as a module, say M here and read
+  Documentation/modules.txt.  If unsure, say `N'.
diff -Nru ./patch-o-matic-ng/osf.old/linux-2.4/Documentation/CVS/Entries ./patch-o-matic-ng/osf/linux-2.4/Documentation/CVS/Entries
--- ./patch-o-matic-ng/osf.old/linux-2.4/Documentation/CVS/Entries	1970-01-01 03:00:00.000000000 +0300
+++ ./patch-o-matic-ng/osf/linux-2.4/Documentation/CVS/Entries	2004-06-14 14:27:09.000000000 +0400
@@ -0,0 +1,2 @@
+/Configure.help.ladd/1.1/Fri Mar  5 09:30:27 2004//
+D
diff -Nru ./patch-o-matic-ng/osf.old/linux-2.4/Documentation/CVS/Repository ./patch-o-matic-ng/osf/linux-2.4/Documentation/CVS/Repository
--- ./patch-o-matic-ng/osf.old/linux-2.4/Documentation/CVS/Repository	1970-01-01 03:00:00.000000000 +0300
+++ ./patch-o-matic-ng/osf/linux-2.4/Documentation/CVS/Repository	2004-06-14 14:27:09.000000000 +0400
@@ -0,0 +1 @@
+patch-o-matic-ng/osf/linux/Documentation
diff -Nru ./patch-o-matic-ng/osf.old/linux-2.4/Documentation/CVS/Root ./patch-o-matic-ng/osf/linux-2.4/Documentation/CVS/Root
--- ./patch-o-matic-ng/osf.old/linux-2.4/Documentation/CVS/Root	1970-01-01 03:00:00.000000000 +0300
+++ ./patch-o-matic-ng/osf/linux-2.4/Documentation/CVS/Root	2004-06-14 14:27:09.000000000 +0400
@@ -0,0 +1 @@
+:pserver:cvs:cvs@pserver.netfilter.org:/cvspublic
diff -Nru ./patch-o-matic-ng/osf.old/linux-2.4/include/CVS/Entries ./patch-o-matic-ng/osf/linux-2.4/include/CVS/Entries
--- ./patch-o-matic-ng/osf.old/linux-2.4/include/CVS/Entries	1970-01-01 03:00:00.000000000 +0300
+++ ./patch-o-matic-ng/osf/linux-2.4/include/CVS/Entries	2004-01-31 15:37:49.000000000 +0300
@@ -0,0 +1 @@
+D/linux////
diff -Nru ./patch-o-matic-ng/osf.old/linux-2.4/include/CVS/Repository ./patch-o-matic-ng/osf/linux-2.4/include/CVS/Repository
--- ./patch-o-matic-ng/osf.old/linux-2.4/include/CVS/Repository	1970-01-01 03:00:00.000000000 +0300
+++ ./patch-o-matic-ng/osf/linux-2.4/include/CVS/Repository	2004-01-31 15:25:05.000000000 +0300
@@ -0,0 +1 @@
+patch-o-matic-ng/osf/linux/include
diff -Nru ./patch-o-matic-ng/osf.old/linux-2.4/include/CVS/Root ./patch-o-matic-ng/osf/linux-2.4/include/CVS/Root
--- ./patch-o-matic-ng/osf.old/linux-2.4/include/CVS/Root	1970-01-01 03:00:00.000000000 +0300
+++ ./patch-o-matic-ng/osf/linux-2.4/include/CVS/Root	2004-01-31 15:25:05.000000000 +0300
@@ -0,0 +1 @@
+:pserver:cvs:cvs@pserver.netfilter.org:/cvspublic
diff -Nru ./patch-o-matic-ng/osf.old/linux-2.4/include/linux/CVS/Entries ./patch-o-matic-ng/osf/linux-2.4/include/linux/CVS/Entries
--- ./patch-o-matic-ng/osf.old/linux-2.4/include/linux/CVS/Entries	1970-01-01 03:00:00.000000000 +0300
+++ ./patch-o-matic-ng/osf/linux-2.4/include/linux/CVS/Entries	2004-01-31 15:37:49.000000000 +0300
@@ -0,0 +1 @@
+D/netfilter_ipv4////
diff -Nru ./patch-o-matic-ng/osf.old/linux-2.4/include/linux/CVS/Repository ./patch-o-matic-ng/osf/linux-2.4/include/linux/CVS/Repository
--- ./patch-o-matic-ng/osf.old/linux-2.4/include/linux/CVS/Repository	1970-01-01 03:00:00.000000000 +0300
+++ ./patch-o-matic-ng/osf/linux-2.4/include/linux/CVS/Repository	2004-01-31 15:25:05.000000000 +0300
@@ -0,0 +1 @@
+patch-o-matic-ng/osf/linux/include/linux
diff -Nru ./patch-o-matic-ng/osf.old/linux-2.4/include/linux/CVS/Root ./patch-o-matic-ng/osf/linux-2.4/include/linux/CVS/Root
--- ./patch-o-matic-ng/osf.old/linux-2.4/include/linux/CVS/Root	1970-01-01 03:00:00.000000000 +0300
+++ ./patch-o-matic-ng/osf/linux-2.4/include/linux/CVS/Root	2004-01-31 15:25:05.000000000 +0300
@@ -0,0 +1 @@
+:pserver:cvs:cvs@pserver.netfilter.org:/cvspublic
diff -Nru ./patch-o-matic-ng/osf.old/linux-2.4/include/linux/netfilter_ipv4/CVS/Entries ./patch-o-matic-ng/osf/linux-2.4/include/linux/netfilter_ipv4/CVS/Entries
--- ./patch-o-matic-ng/osf.old/linux-2.4/include/linux/netfilter_ipv4/CVS/Entries	1970-01-01 03:00:00.000000000 +0300
+++ ./patch-o-matic-ng/osf/linux-2.4/include/linux/netfilter_ipv4/CVS/Entries	2004-06-14 14:27:09.000000000 +0400
@@ -0,0 +1,2 @@
+/ipt_osf.h/1.2/Sat Mar  6 10:30:56 2004//
+D
diff -Nru ./patch-o-matic-ng/osf.old/linux-2.4/include/linux/netfilter_ipv4/CVS/Repository ./patch-o-matic-ng/osf/linux-2.4/include/linux/netfilter_ipv4/CVS/Repository
--- ./patch-o-matic-ng/osf.old/linux-2.4/include/linux/netfilter_ipv4/CVS/Repository	1970-01-01 03:00:00.000000000 +0300
+++ ./patch-o-matic-ng/osf/linux-2.4/include/linux/netfilter_ipv4/CVS/Repository	2004-01-31 15:25:05.000000000 +0300
@@ -0,0 +1 @@
+patch-o-matic-ng/osf/linux/include/linux/netfilter_ipv4
diff -Nru ./patch-o-matic-ng/osf.old/linux-2.4/include/linux/netfilter_ipv4/CVS/Root ./patch-o-matic-ng/osf/linux-2.4/include/linux/netfilter_ipv4/CVS/Root
--- ./patch-o-matic-ng/osf.old/linux-2.4/include/linux/netfilter_ipv4/CVS/Root	1970-01-01 03:00:00.000000000 +0300
+++ ./patch-o-matic-ng/osf/linux-2.4/include/linux/netfilter_ipv4/CVS/Root	2004-01-31 15:25:05.000000000 +0300
@@ -0,0 +1 @@
+:pserver:cvs:cvs@pserver.netfilter.org:/cvspublic
diff -Nru ./patch-o-matic-ng/osf.old/linux-2.4/include/linux/netfilter_ipv4/ipt_osf.h ./patch-o-matic-ng/osf/linux-2.4/include/linux/netfilter_ipv4/ipt_osf.h
--- ./patch-o-matic-ng/osf.old/linux-2.4/include/linux/netfilter_ipv4/ipt_osf.h	1970-01-01 03:00:00.000000000 +0300
+++ ./patch-o-matic-ng/osf/linux-2.4/include/linux/netfilter_ipv4/ipt_osf.h	2004-03-06 13:30:56.000000000 +0300
@@ -0,0 +1,148 @@
+/*
+ * ipt_osf.h
+ *
+ * Copyright (c) 2003 Evgeniy Polyakov <johnpol@2ka.mipt.ru>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _IPT_OSF_H
+#define _IPT_OSF_H
+
+#define MAXGENRELEN		32
+#define MAXDETLEN		64
+
+#define IPT_OSF_GENRE		1
+#define	IPT_OSF_SMART		2
+#define IPT_OSF_LOG		4
+#define IPT_OSF_NETLINK		8
+
+#define IPT_OSF_LOGLEVEL_ALL	0
+#define IPT_OSF_LOGLEVEL_FIRST	1
+
+#include <linux/list.h>
+
+#ifndef __KERNEL__
+#include <netinet/ip.h>
+#include <netinet/tcp.h>
+
+struct list_head
+{
+	struct list_head *prev, *next;
+};
+#endif
+
+struct ipt_osf_info
+{
+	char 			genre[MAXGENRELEN];
+	int			len;
+	unsigned long		flags;
+	int			loglevel;
+	int			invert; /* UNSUPPORTED */
+};
+
+struct osf_wc
+{
+	char			wc;
+	unsigned long		val;
+};
+
+/* This struct represents IANA options
+ * http://www.iana.org/assignments/tcp-parameters
+ */
+struct osf_opt
+{
+	unsigned char		kind;
+	unsigned char		length;
+	struct osf_wc		wc;
+};
+
+struct osf_finger
+{
+	struct list_head	flist;
+	struct osf_wc		wss;
+	unsigned char		ttl;
+	unsigned char		df;
+	unsigned long		ss;
+	unsigned char		genre[MAXGENRELEN];
+	unsigned char		version[MAXGENRELEN], subtype[MAXGENRELEN];
+	
+	/* Not needed, but for consistency with original table from Michal Zalewski */
+	unsigned char		details[MAXDETLEN]; 
+
+	int 			opt_num;
+	struct osf_opt		opt[MAX_IPOPTLEN]; /* In case it is all NOP or EOL */
+
+};
+
+struct ipt_osf_nlmsg
+{
+	struct osf_finger	f;
+	struct iphdr 		ip;
+	struct tcphdr 		tcp;
+};
+
+#ifdef __KERNEL__
+
+/* Defines for IANA option kinds */
+
+#define OSFOPT_EOL		0	/* End of options */
+#define OSFOPT_NOP		1	/* NOP */
+#define OSFOPT_MSS		2	/* Maximum segment size */
+#define OSFOPT_WSO		3	/* Window scale option */
+#define OSFOPT_SACKP		4	/* SACK permitted */
+#define OSFOPT_SACK		5	/* SACK */
+#define OSFOPT_ECHO		6	
+#define OSFOPT_ECHOREPLY	7
+#define OSFOPT_TS		8	/* Timestamp option */
+#define OSFOPT_POCP		9	/* Partial Order Connection Permitted */
+#define OSFOPT_POSP		10	/* Partial Order Service Profile */
+/* Others are not used in current OSF */
+
+static struct osf_opt IANA_opts[] = 
+{
+	{0, 1,},
+	{1, 1,},
+	{2, 4,},
+	{3, 3,},
+	{4, 2,},
+	{5, 1 ,}, /* SACK length is not defined */
+	{6, 6,},
+	{7, 6,},
+	{8, 10,},
+	{9, 2,},
+	{10, 3,},
+	{11, 1,}, /* CC: Suppose 1 */
+	{12, 1,}, /* the same */
+	{13, 1,}, /* and here too */
+	{14, 3,},
+	{15, 1,}, /* TCP Alternate Checksum Data. Length is not defined */
+	{16, 1,},
+	{17, 1,},
+	{18, 3,},
+	{19, 18,},
+	{20, 1,},
+	{21, 1,},
+	{22, 1,},
+	{23, 1,},
+	{24, 1,},
+	{25, 1,},
+	{26, 1,},
+};
+
+#endif /* __KERNEL__ */
+
+#endif /* _IPT_OSF_H */
diff -Nru ./patch-o-matic-ng/osf.old/linux-2.4/net/CVS/Entries ./patch-o-matic-ng/osf/linux-2.4/net/CVS/Entries
--- ./patch-o-matic-ng/osf.old/linux-2.4/net/CVS/Entries	1970-01-01 03:00:00.000000000 +0300
+++ ./patch-o-matic-ng/osf/linux-2.4/net/CVS/Entries	2004-01-31 15:37:49.000000000 +0300
@@ -0,0 +1 @@
+D/ipv4////
diff -Nru ./patch-o-matic-ng/osf.old/linux-2.4/net/CVS/Repository ./patch-o-matic-ng/osf/linux-2.4/net/CVS/Repository
--- ./patch-o-matic-ng/osf.old/linux-2.4/net/CVS/Repository	1970-01-01 03:00:00.000000000 +0300
+++ ./patch-o-matic-ng/osf/linux-2.4/net/CVS/Repository	2004-01-31 15:25:05.000000000 +0300
@@ -0,0 +1 @@
+patch-o-matic-ng/osf/linux/net
diff -Nru ./patch-o-matic-ng/osf.old/linux-2.4/net/CVS/Root ./patch-o-matic-ng/osf/linux-2.4/net/CVS/Root
--- ./patch-o-matic-ng/osf.old/linux-2.4/net/CVS/Root	1970-01-01 03:00:00.000000000 +0300
+++ ./patch-o-matic-ng/osf/linux-2.4/net/CVS/Root	2004-01-31 15:25:05.000000000 +0300
@@ -0,0 +1 @@
+:pserver:cvs:cvs@pserver.netfilter.org:/cvspublic
diff -Nru ./patch-o-matic-ng/osf.old/linux-2.4/net/ipv4/CVS/Entries ./patch-o-matic-ng/osf/linux-2.4/net/ipv4/CVS/Entries
--- ./patch-o-matic-ng/osf.old/linux-2.4/net/ipv4/CVS/Entries	1970-01-01 03:00:00.000000000 +0300
+++ ./patch-o-matic-ng/osf/linux-2.4/net/ipv4/CVS/Entries	2004-01-31 15:37:49.000000000 +0300
@@ -0,0 +1 @@
+D/netfilter////
diff -Nru ./patch-o-matic-ng/osf.old/linux-2.4/net/ipv4/CVS/Repository ./patch-o-matic-ng/osf/linux-2.4/net/ipv4/CVS/Repository
--- ./patch-o-matic-ng/osf.old/linux-2.4/net/ipv4/CVS/Repository	1970-01-01 03:00:00.000000000 +0300
+++ ./patch-o-matic-ng/osf/linux-2.4/net/ipv4/CVS/Repository	2004-01-31 15:25:05.000000000 +0300
@@ -0,0 +1 @@
+patch-o-matic-ng/osf/linux/net/ipv4
diff -Nru ./patch-o-matic-ng/osf.old/linux-2.4/net/ipv4/CVS/Root ./patch-o-matic-ng/osf/linux-2.4/net/ipv4/CVS/Root
--- ./patch-o-matic-ng/osf.old/linux-2.4/net/ipv4/CVS/Root	1970-01-01 03:00:00.000000000 +0300
+++ ./patch-o-matic-ng/osf/linux-2.4/net/ipv4/CVS/Root	2004-01-31 15:25:05.000000000 +0300
@@ -0,0 +1 @@
+:pserver:cvs:cvs@pserver.netfilter.org:/cvspublic
diff -Nru ./patch-o-matic-ng/osf.old/linux-2.4/net/ipv4/netfilter/Config.in.ladd ./patch-o-matic-ng/osf/linux-2.4/net/ipv4/netfilter/Config.in.ladd
--- ./patch-o-matic-ng/osf.old/linux-2.4/net/ipv4/netfilter/Config.in.ladd	1970-01-01 03:00:00.000000000 +0300
+++ ./patch-o-matic-ng/osf/linux-2.4/net/ipv4/netfilter/Config.in.ladd	2003-12-18 21:28:43.000000000 +0300
@@ -0,0 +1,4 @@
+  dep_tristate '  TOS match support' CONFIG_IP_NF_MATCH_TOS $CONFIG_IP_NF_IPTABLES
+  if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+    dep_tristate '  OSF match support (EXPERIMENTAL)' CONFIG_IP_NF_MATCH_OSF $CONFIG_IP_NF_IPTABLES
+  fi
diff -Nru ./patch-o-matic-ng/osf.old/linux-2.4/net/ipv4/netfilter/CVS/Entries ./patch-o-matic-ng/osf/linux-2.4/net/ipv4/netfilter/CVS/Entries
--- ./patch-o-matic-ng/osf.old/linux-2.4/net/ipv4/netfilter/CVS/Entries	1970-01-01 03:00:00.000000000 +0300
+++ ./patch-o-matic-ng/osf/linux-2.4/net/ipv4/netfilter/CVS/Entries	2004-06-14 14:27:09.000000000 +0400
@@ -0,0 +1,5 @@
+/Config.in.ladd/1.1/Thu Dec 18 18:28:43 2003//
+/Makefile.ladd/1.1/Thu Dec 18 18:28:43 2003//
+/Kconfig.ladd/1.2/Mon Jun 14 10:27:09 2004//
+/ipt_osf.c/1.2/Sat Mar  6 10:30:57 2004//
+D
diff -Nru ./patch-o-matic-ng/osf.old/linux-2.4/net/ipv4/netfilter/CVS/Repository ./patch-o-matic-ng/osf/linux-2.4/net/ipv4/netfilter/CVS/Repository
--- ./patch-o-matic-ng/osf.old/linux-2.4/net/ipv4/netfilter/CVS/Repository	1970-01-01 03:00:00.000000000 +0300
+++ ./patch-o-matic-ng/osf/linux-2.4/net/ipv4/netfilter/CVS/Repository	2004-01-31 15:25:05.000000000 +0300
@@ -0,0 +1 @@
+patch-o-matic-ng/osf/linux/net/ipv4/netfilter
diff -Nru ./patch-o-matic-ng/osf.old/linux-2.4/net/ipv4/netfilter/CVS/Root ./patch-o-matic-ng/osf/linux-2.4/net/ipv4/netfilter/CVS/Root
--- ./patch-o-matic-ng/osf.old/linux-2.4/net/ipv4/netfilter/CVS/Root	1970-01-01 03:00:00.000000000 +0300
+++ ./patch-o-matic-ng/osf/linux-2.4/net/ipv4/netfilter/CVS/Root	2004-01-31 15:25:05.000000000 +0300
@@ -0,0 +1 @@
+:pserver:cvs:cvs@pserver.netfilter.org:/cvspublic
diff -Nru ./patch-o-matic-ng/osf.old/linux-2.4/net/ipv4/netfilter/ipt_osf.c ./patch-o-matic-ng/osf/linux-2.4/net/ipv4/netfilter/ipt_osf.c
--- ./patch-o-matic-ng/osf.old/linux-2.4/net/ipv4/netfilter/ipt_osf.c	1970-01-01 03:00:00.000000000 +0300
+++ ./patch-o-matic-ng/osf/linux-2.4/net/ipv4/netfilter/ipt_osf.c	2004-03-06 13:30:57.000000000 +0300
@@ -0,0 +1,865 @@
+/*
+ * ipt_osf.c
+ *
+ * Copyright (c) 2003 Evgeniy Polyakov <johnpol@2ka.mipt.ru>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/*
+ * OS fingerprint matching module.
+ * It simply compares various parameters from SYN packet with
+ * some hardcoded ones.
+ *
+ * Original table was created by Michal Zalewski <lcamtuf@coredump.cx>
+ * for his p0f.
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/smp.h>
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/file.h>
+#include <linux/ip.h>
+#include <linux/proc_fs.h>
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/ctype.h>
+#include <linux/list.h>
+#include <linux/if.h>
+
+#include <net/sock.h>
+#include <net/ip.h>
+
+#include <linux/netfilter_ipv4/ip_tables.h>
+
+#include <linux/netfilter_ipv4/ipt_osf.h>
+
+#define OSF_DEBUG
+
+#ifdef OSF_DEBUG
+#define log(x...) 		printk(KERN_INFO "ipt_osf: " x)
+#define loga(x...) 		printk(x)
+#else
+#define log(x...) 		do {} while(0)
+#define loga(x...) 		do {} while(0)
+#endif
+
+#define FMATCH_WRONG		0
+#define FMATCH_OK		1
+#define FMATCH_OPT_WRONG	2
+
+#define OPTDEL			','
+#define OSFPDEL 		':'
+#define MAXOPTSTRLEN		128
+#define OSFFLUSH		"FLUSH"
+
+static rwlock_t osf_lock = RW_LOCK_UNLOCKED;
+static spinlock_t ipt_osf_netlink_lock = SPIN_LOCK_UNLOCKED;
+static struct list_head	finger_list;	
+static int match(const struct sk_buff *, const struct net_device *, const struct net_device *,
+		      const void *, int, 
+		      const void *, u_int16_t, 
+		      int *);
+static int checkentry(const char *, const struct ipt_ip *, void *,
+		           unsigned int, unsigned int);
+
+static unsigned long seq, ipt_osf_groups = 1;
+static struct sock *nts;
+
+static struct ipt_match osf_match = 
+{ 
+	{ NULL, NULL }, 
+	"osf", 
+	&match, 
+	&checkentry, 
+	NULL, 
+	THIS_MODULE 
+};
+
+static void ipt_osf_nlsend(struct osf_finger *f, const struct sk_buff *sk)
+{
+	unsigned int size;
+	struct sk_buff *skb;
+	struct ipt_osf_nlmsg *data;
+	struct nlmsghdr *nlh;
+
+	size = NLMSG_SPACE(sizeof(struct ipt_osf_nlmsg));
+
+	skb = alloc_skb(size, GFP_ATOMIC);
+	if (!skb)
+	{
+		log("skb_alloc() failed.\n");
+		return;
+	}
+	
+	nlh = NLMSG_PUT(skb, 0, seq++, NLMSG_DONE, size - sizeof(*nlh));
+	
+	data = (struct ipt_osf_nlmsg *)NLMSG_DATA(nlh);
+
+	memcpy(&data->f, f, sizeof(struct osf_finger));
+	memcpy(&data->ip, sk->nh.iph, sizeof(struct iphdr));
+	memcpy(&data->tcp, (struct tcphdr *)((u_int32_t *)sk->nh.iph + sk->nh.iph->ihl), sizeof(struct tcphdr));
+
+	NETLINK_CB(skb).dst_groups = ipt_osf_groups;
+	netlink_broadcast(nts, skb, 0, ipt_osf_groups, GFP_ATOMIC);
+
+nlmsg_failure:
+	return;
+}
+
+static inline int smart_dec(const struct sk_buff *skb, unsigned long flags, unsigned char f_ttl)
+{
+	struct iphdr *ip = skb->nh.iph;
+
+	if (flags & IPT_OSF_SMART)
+	{
+		struct in_device *in_dev = in_dev_get(skb->dev);
+
+		for_ifa(in_dev)
+		{
+			if (inet_ifa_match(ip->saddr, ifa))
+			{
+				in_dev_put(in_dev);
+				return (ip->ttl == f_ttl);
+			}
+		}
+		endfor_ifa(in_dev);
+		
+		in_dev_put(in_dev);
+		return (ip->ttl <= f_ttl);
+	}
+	else
+		return (ip->ttl == f_ttl);
+}
+
+static int
+match(const struct sk_buff *skb, const struct net_device *in, const struct net_device *out,
+      const void *matchinfo, int offset,
+      const void *hdr, u_int16_t datalen,
+      int *hotdrop)
+{
+	struct ipt_osf_info *info = (struct ipt_osf_info *)matchinfo;
+	struct iphdr *ip = skb->nh.iph;
+	struct tcphdr *tcp;
+	int fmatch = FMATCH_WRONG, fcount = 0;
+	unsigned long totlen, optsize = 0, window;
+	unsigned char df, *optp = NULL, *_optp = NULL;
+	char check_WSS = 0;
+	struct list_head *ent;
+	struct osf_finger *f;
+
+	if (!ip || !info)
+		return 0;
+				
+	tcp = (struct tcphdr *)((u_int32_t *)ip + ip->ihl);
+
+	if (!tcp->syn)
+		return 0;
+	
+	totlen = ntohs(ip->tot_len);
+	df = ((ntohs(ip->frag_off) & IP_DF)?1:0);
+	window = ntohs(tcp->window);
+	
+	if (tcp->doff*4 > sizeof(struct tcphdr))
+	{
+		_optp = optp = (char *)(tcp+1);
+		optsize = tcp->doff*4 - sizeof(struct tcphdr);
+	}
+
+	
+	/* Actually we can create hash/table of all genres and search
+	 * only in appropriate part, but here is initial variant,
+	 * so will use slow path.
+	 */
+	read_lock(&osf_lock);
+	list_for_each(ent, &finger_list)
+	{
+		f = list_entry(ent, struct osf_finger, flist);
+	
+		if (!(info->flags & IPT_OSF_LOG) && strcmp(info->genre, f->genre)) 
+			continue;
+
+		optp = _optp;
+		fmatch = FMATCH_WRONG;
+
+		if (totlen == f->ss && df == f->df && 
+			smart_dec(skb, info->flags, f->ttl))
+		{
+			unsigned long foptsize;
+			int optnum;
+			unsigned short mss = 0;
+
+			check_WSS = 0;
+
+			switch (f->wss.wc)
+			{
+				case 0:	  check_WSS = 0; break;
+				case 'S': check_WSS = 1; break;
+				case 'T': check_WSS = 2; break;
+				case '%': check_WSS = 3; break;
+				default: log("Wrong fingerprint wss.wc=%d, %s - %s\n", 
+							 f->wss.wc, f->genre, f->details);
+					 check_WSS = 4;
+					 break;
+			}
+			if (check_WSS == 4)
+				continue;
+
+			/* Check options */
+
+			foptsize = 0;
+			for (optnum=0; optnum<f->opt_num; ++optnum)
+				foptsize += f->opt[optnum].length;
+
+				
+			if (foptsize > MAX_IPOPTLEN || optsize > MAX_IPOPTLEN || optsize != foptsize)
+				continue;
+
+			if (!optp)
+			{
+				fmatch = FMATCH_OK;
+				loga("\tYEP : matching without options.\n");
+				if ((info->flags & IPT_OSF_LOG) && 
+					info->loglevel == IPT_OSF_LOGLEVEL_FIRST)
+					break;
+				else
+					continue;
+			}
+			
+
+			for (optnum=0; optnum<f->opt_num; ++optnum)
+			{
+				if (f->opt[optnum].kind == (*optp)) 
+				{
+					unsigned char len = f->opt[optnum].length;
+					unsigned char *optend = optp + len;
+					int loop_cont = 0;
+
+					fmatch = FMATCH_OK;
+
+
+					switch (*optp)
+					{
+						case OSFOPT_MSS:
+							mss = ntohs(*(unsigned short *)(optp+2));
+							break;
+						case OSFOPT_TS:
+							loop_cont = 1;
+							break;
+					}
+					
+					if (loop_cont)
+					{
+						optp = optend;
+						continue;
+					}
+					
+					if (len != 1)
+					{
+						/* Skip kind and length fields*/
+						optp += 2; 
+
+						if (f->opt[optnum].wc.val != 0)
+						{
+							unsigned long tmp = 0;
+							
+							/* Hmmm... It looks a bit ugly. :) */
+							memcpy(&tmp, optp, 
+								(len > sizeof(unsigned long)?
+								 	sizeof(unsigned long):len));
+							/* 2 + 2: optlen(2 bytes) + 
+							 * 	kind(1 byte) + length(1 byte) */
+							if (len == 4) 
+								tmp = ntohs(tmp);
+							else
+								tmp = ntohl(tmp);
+
+							if (f->opt[optnum].wc.wc == '%')
+							{
+								if ((tmp % f->opt[optnum].wc.val) != 0)
+									fmatch = FMATCH_OPT_WRONG;
+							}
+							else if (tmp != f->opt[optnum].wc.val)
+								fmatch = FMATCH_OPT_WRONG;
+						}
+					}
+
+					optp = optend;
+				}
+				else
+					fmatch = FMATCH_OPT_WRONG;
+
+				if (fmatch != FMATCH_OK)
+					break;
+			}
+
+			if (fmatch != FMATCH_OPT_WRONG)
+			{
+				fmatch = FMATCH_WRONG;
+
+				switch (check_WSS)
+				{
+					case 0:
+						if (f->wss.val == 0 || window == f->wss.val)
+							fmatch = FMATCH_OK;
+						break;
+					case 1: /* MSS */
+/* Lurked in OpenBSD */
+#define SMART_MSS	1460
+						if (window == f->wss.val*mss || 
+							window == f->wss.val*SMART_MSS)
+							fmatch = FMATCH_OK;
+						break;
+					case 2: /* MTU */
+						if (window == f->wss.val*(mss+40) ||
+							window == f->wss.val*(SMART_MSS+40))
+							fmatch = FMATCH_OK;
+						break;
+					case 3: /* MOD */
+						if ((window % f->wss.val) == 0)
+							fmatch = FMATCH_OK;
+						break;
+				}
+			}
+					
+
+			if (fmatch == FMATCH_OK)
+			{
+				fcount++;
+				log("%s [%s:%s:%s] : %u.%u.%u.%u:%u -> %u.%u.%u.%u:%u hops=%d\n", 
+					f->genre, f->version,
+					f->subtype, f->details,
+					NIPQUAD(ip->saddr), ntohs(tcp->source),
+					NIPQUAD(ip->daddr), ntohs(tcp->dest),
+					f->ttl - ip->ttl);
+				if (info->flags & IPT_OSF_NETLINK)
+				{
+					spin_lock_bh(&ipt_osf_netlink_lock);
+					ipt_osf_nlsend(f, skb);
+					spin_unlock_bh(&ipt_osf_netlink_lock);
+				}
+				if ((info->flags & IPT_OSF_LOG) && 
+					info->loglevel == IPT_OSF_LOGLEVEL_FIRST)
+					break;
+			}
+		}
+	}
+	if (!fcount && (info->flags & (IPT_OSF_LOG | IPT_OSF_NETLINK)))
+	{
+		unsigned char opt[4 * 15 - sizeof(struct tcphdr)];
+		unsigned int i, optsize;
+		struct osf_finger fg;
+
+		memset(&fg, 0, sizeof(fg));
+
+		if ((info->flags & IPT_OSF_LOG))
+			log("Unknown: %lu:%d:%d:%lu:", window, ip->ttl, df, totlen);
+		if (optp)
+		{
+			optsize = tcp->doff * 4 - sizeof(struct tcphdr);
+			if (skb_copy_bits(skb, ip->ihl*4 + sizeof(struct tcphdr),
+					  opt, optsize) < 0)
+			{
+				if (info->flags & IPT_OSF_LOG)
+					loga("TRUNCATED");
+				if (info->flags & IPT_OSF_NETLINK)
+					strcpy(fg.details, "TRUNCATED");
+			}
+			else
+			{
+				for (i = 0; i < optsize; i++)
+				{
+					if (info->flags & IPT_OSF_LOG)
+						loga("%02X", opt[i]);
+				}
+				if (info->flags & IPT_OSF_NETLINK)
+					memcpy(fg.details, opt, MAXDETLEN);
+			}
+		}
+		if ((info->flags & IPT_OSF_LOG))
+			loga(" %u.%u.%u.%u:%u -> %u.%u.%u.%u:%u\n", 
+				NIPQUAD(ip->saddr), ntohs(tcp->source),
+				NIPQUAD(ip->daddr), ntohs(tcp->dest));
+		
+		if (info->flags & IPT_OSF_NETLINK)
+		{
+			fg.wss.val 	= window;
+			fg.ttl		= ip->ttl;
+			fg.df		= df;
+			fg.ss		= totlen;
+			strncpy(fg.genre, "Unknown", MAXGENRELEN);
+
+			spin_lock_bh(&ipt_osf_netlink_lock);
+			ipt_osf_nlsend(&fg, skb);
+			spin_unlock_bh(&ipt_osf_netlink_lock);
+		}
+	}
+
+	read_unlock(&osf_lock);
+
+	return (fmatch == FMATCH_OK)?1:0;
+}
+
+static int
+checkentry(const char *tablename,
+           const struct ipt_ip *ip,
+           void *matchinfo,
+           unsigned int matchsize,
+           unsigned int hook_mask)
+{
+       if (matchsize != IPT_ALIGN(sizeof(struct ipt_osf_info)))
+               return 0;
+       if (ip->proto != IPPROTO_TCP)
+	       return 0;
+
+       return 1;
+}
+
+static char * osf_strchr(char *ptr, char c)
+{
+	char *tmp;
+
+	tmp = strchr(ptr, c);
+
+	while (tmp && tmp+1 && isspace(*(tmp+1)))
+		tmp++;
+
+	return tmp;
+}
+
+static struct osf_finger * finger_alloc(void)
+{
+	struct osf_finger *f;
+
+	f = kmalloc(sizeof(struct osf_finger), GFP_KERNEL);
+	if (f)
+		memset(f, 0, sizeof(struct osf_finger));
+	
+	return f;
+}
+
+static void finger_free(struct osf_finger *f)
+{
+	memset(f, 0, sizeof(struct osf_finger));
+	kfree(f);
+}
+
+
+static void osf_parse_opt(struct osf_opt *opt, int *optnum, char *obuf, int olen)
+{
+	int i, op;
+	char *ptr, wc;
+	unsigned long val;
+
+	ptr = &obuf[0];
+	i = 0;
+	while (ptr != NULL && i < olen)
+	{
+		val = 0;
+		op = 0;
+		wc = 0;
+		switch (obuf[i])
+		{
+			case 'N': 
+				op = OSFOPT_NOP;
+				ptr = osf_strchr(&obuf[i], OPTDEL);
+				if (ptr)
+				{
+					*ptr = '\0';
+					ptr++;
+					i += (int)(ptr-&obuf[i]);
+
+				}
+				else
+					i++;
+				break;
+			case 'S': 
+				op = OSFOPT_SACKP;
+				ptr = osf_strchr(&obuf[i], OPTDEL);
+				if (ptr)
+				{
+					*ptr = '\0';
+					ptr++;
+					i += (int)(ptr-&obuf[i]);
+
+				}
+				else
+					i++;
+				break;
+			case 'T': 
+				op = OSFOPT_TS;
+				ptr = osf_strchr(&obuf[i], OPTDEL);
+				if (ptr)
+				{
+					*ptr = '\0';
+					ptr++;
+					i += (int)(ptr-&obuf[i]);
+
+				}
+				else
+					i++;
+				break;
+			case 'W': 
+				op = OSFOPT_WSO;
+				ptr = osf_strchr(&obuf[i], OPTDEL);
+				if (ptr)
+				{
+					switch (obuf[i+1])
+					{
+						case '%':	wc = '%'; break;
+						case 'S':	wc = 'S'; break;
+						case 'T':	wc = 'T'; break;
+						default:	wc = 0; break;
+					}
+					
+					*ptr = '\0';
+					ptr++;
+					if (wc)
+						val = simple_strtoul(&obuf[i+2], NULL, 10);
+					else
+						val = simple_strtoul(&obuf[i+1], NULL, 10);
+					i += (int)(ptr-&obuf[i]);
+
+				}
+				else
+					i++;
+				break;
+			case 'M': 
+				op = OSFOPT_MSS;
+				ptr = osf_strchr(&obuf[i], OPTDEL);
+				if (ptr)
+				{
+					if (obuf[i+1] == '%')
+						wc = '%';
+					*ptr = '\0';
+					ptr++;
+					if (wc)
+						val = simple_strtoul(&obuf[i+2], NULL, 10);
+					else
+						val = simple_strtoul(&obuf[i+1], NULL, 10);
+					i += (int)(ptr-&obuf[i]);
+
+				}
+				else
+					i++;
+				break;
+			case 'E': 
+				op = OSFOPT_EOL;
+				ptr = osf_strchr(&obuf[i], OPTDEL);
+				if (ptr)
+				{
+					*ptr = '\0';
+					ptr++;
+					i += (int)(ptr-&obuf[i]);
+
+				}
+				else
+					i++;
+				break;
+			default:
+				ptr = osf_strchr(&obuf[i], OPTDEL);
+				if (ptr)
+				{
+					ptr++;
+					i += (int)(ptr-&obuf[i]);
+
+				}
+				else
+					i++;
+				break;
+		}
+
+		opt[*optnum].kind 	= IANA_opts[op].kind;
+		opt[*optnum].length 	= IANA_opts[op].length;
+		opt[*optnum].wc.wc 	= wc;
+		opt[*optnum].wc.val	= val;
+
+		(*optnum)++;
+	}
+}
+
+static int osf_proc_read(char *buf, char **start, off_t off, int count, int *eof, void *data)
+{
+	struct list_head *ent;
+	struct osf_finger *f = NULL;
+	int i;
+	
+	*eof = 1;
+	count = 0;
+
+	read_lock_bh(&osf_lock);
+	list_for_each(ent, &finger_list)
+	{
+		f = list_entry(ent, struct osf_finger, flist);
+
+		log("%s [%s]", f->genre, f->details);
+		
+		count += sprintf(buf+count, "%s - %s[%s] : %s", 
+					f->genre, f->version,
+					f->subtype, f->details);
+		
+		if (f->opt_num)
+		{
+			loga(" OPT: ");
+			//count += sprintf(buf+count, " OPT: ");
+			for (i=0; i<f->opt_num; ++i)
+			{
+				//count += sprintf(buf+count, "%d.%c%lu; ", 
+				//	f->opt[i].kind, (f->opt[i].wc.wc)?f->opt[i].wc.wc:' ', f->opt[i].wc.val);
+				loga("%d.%c%lu; ", 
+					f->opt[i].kind, (f->opt[i].wc.wc)?f->opt[i].wc.wc:' ', f->opt[i].wc.val);
+			}
+		}
+		loga("\n");
+		count += sprintf(buf+count, "\n");
+	}
+	read_unlock_bh(&osf_lock);
+
+	return count;
+}
+
+static int osf_proc_write(struct file *file, const char *buffer, unsigned long count, void *data)
+{
+	int cnt;
+	unsigned long i;
+	char obuf[MAXOPTSTRLEN];
+	struct osf_finger *finger;
+	struct list_head *ent, *n;
+
+	char *pbeg, *pend;
+
+	if (count == strlen(OSFFLUSH) && !strncmp(buffer, OSFFLUSH, strlen(OSFFLUSH)))
+	{
+		int i = 0;
+		write_lock_bh(&osf_lock);
+		list_for_each_safe(ent, n, &finger_list)
+		{
+			i++;
+			finger = list_entry(ent, struct osf_finger, flist);
+			list_del(&finger->flist);
+			finger_free(finger);
+		}
+		write_unlock_bh(&osf_lock);
+	
+		log("Flushed %d entries.\n", i);
+		
+		return count;
+	}
+
+	
+	cnt = 0;
+	for (i=0; i<count && buffer[i] != '\0'; ++i)
+		if (buffer[i] == ':')
+			cnt++;
+
+	if (cnt != 8 || i != count)
+	{
+		log("Wrong input line cnt=%d[8], len=%lu[%lu]\n", 
+			cnt, i, count);
+		return count;
+	}
+
+	memset(obuf, 0, sizeof(obuf));
+	
+	finger = finger_alloc();
+	if (!finger)
+	{
+		log("Failed to allocate new fingerprint entry.\n");
+		return -ENOMEM;
+	}
+
+	pbeg = (char *)buffer;
+	pend = osf_strchr(pbeg, OSFPDEL);
+	if (pend)
+	{
+		*pend = '\0';
+		if (pbeg[0] == 'S')
+		{
+			finger->wss.wc = 'S';
+			if (pbeg[1] == '%')
+				finger->wss.val = simple_strtoul(pbeg+2, NULL, 10);
+			else if (pbeg[1] == '*')
+				finger->wss.val = 0;
+			else 
+				finger->wss.val = simple_strtoul(pbeg+1, NULL, 10);
+		}
+		else if (pbeg[0] == 'T')
+		{
+			finger->wss.wc = 'T';
+			if (pbeg[1] == '%')
+				finger->wss.val = simple_strtoul(pbeg+2, NULL, 10);
+			else if (pbeg[1] == '*')
+				finger->wss.val = 0;
+			else 
+				finger->wss.val = simple_strtoul(pbeg+1, NULL, 10);
+		}
+		else if (pbeg[0] == '%')
+		{
+			finger->wss.wc = '%';
+			finger->wss.val = simple_strtoul(pbeg+1, NULL, 10);
+		}
+		else if (isdigit(pbeg[0]))
+		{
+			finger->wss.wc = 0;
+			finger->wss.val = simple_strtoul(pbeg, NULL, 10);
+		}
+
+		pbeg = pend+1;
+	}
+	pend = osf_strchr(pbeg, OSFPDEL);
+	if (pend)
+	{
+		*pend = '\0';
+		finger->ttl = simple_strtoul(pbeg, NULL, 10);
+		pbeg = pend+1;
+	}
+	pend = osf_strchr(pbeg, OSFPDEL);
+	if (pend)
+	{
+		*pend = '\0';
+		finger->df = simple_strtoul(pbeg, NULL, 10);
+		pbeg = pend+1;
+	}
+	pend = osf_strchr(pbeg, OSFPDEL);
+	if (pend)
+	{
+		*pend = '\0';
+		finger->ss = simple_strtoul(pbeg, NULL, 10);
+		pbeg = pend+1;
+	}
+
+	pend = osf_strchr(pbeg, OSFPDEL);
+	if (pend)
+	{
+		*pend = '\0';
+		cnt = snprintf(obuf, sizeof(obuf), "%s", pbeg);
+		pbeg = pend+1;
+	}
+
+	pend = osf_strchr(pbeg, OSFPDEL);
+	if (pend)
+	{
+		*pend = '\0';
+		if (pbeg[0] == '@' || pbeg[0] == '*')
+			cnt = snprintf(finger->genre, sizeof(finger->genre), "%s", pbeg+1);
+		else
+			cnt = snprintf(finger->genre, sizeof(finger->genre), "%s", pbeg);
+		pbeg = pend+1;
+	}
+	
+	pend = osf_strchr(pbeg, OSFPDEL);
+	if (pend)
+	{
+		*pend = '\0';
+		cnt = snprintf(finger->version, sizeof(finger->version), "%s", pbeg);
+		pbeg = pend+1;
+	}
+	
+	pend = osf_strchr(pbeg, OSFPDEL);
+	if (pend)
+	{
+		*pend = '\0';
+		cnt = snprintf(finger->subtype, sizeof(finger->subtype), "%s", pbeg);
+		pbeg = pend+1;
+	}
+
+	cnt = snprintf(finger->details, 
+			((count - (pbeg - buffer)+1) > MAXDETLEN)?MAXDETLEN:(count - (pbeg - buffer)+1), 
+			"%s", pbeg);
+	
+	log("%s - %s[%s] : %s\n", 
+		finger->genre, finger->version,
+		finger->subtype, finger->details);
+	
+	osf_parse_opt(finger->opt, &finger->opt_num, obuf, sizeof(obuf));
+	
+
+	write_lock_bh(&osf_lock);
+	list_add_tail(&finger->flist, &finger_list);
+	write_unlock_bh(&osf_lock);
+
+	return count;
+}
+
+static int __init osf_init(void)
+{
+	int err;
+	struct proc_dir_entry *p;
+
+	log("Startng OS fingerprint matching module.\n");
+
+	INIT_LIST_HEAD(&finger_list);
+	
+	err = ipt_register_match(&osf_match);
+	if (err)
+	{
+		log("Failed to register OS fingerprint matching module.\n");
+		return -ENXIO;
+	}
+
+	p = create_proc_entry("sys/net/ipv4/osf", S_IFREG | 0644, NULL);
+	if (!p)
+	{
+		ipt_unregister_match(&osf_match);
+		return -ENXIO;
+	}
+
+	p->write_proc = osf_proc_write;
+	p->read_proc  = osf_proc_read;
+	
+	nts = netlink_kernel_create(NETLINK_NFLOG, NULL);
+	if (!nts)
+	{
+		log("netlink_kernel_create() failed\n");
+		remove_proc_entry("sys/net/ipv4/osf", NULL);
+		ipt_unregister_match(&osf_match);
+		return -ENOMEM;
+	}
+
+	return 0;
+}
+
+static void __exit osf_fini(void)
+{
+	struct list_head *ent, *n;
+	struct osf_finger *f;
+	
+	remove_proc_entry("sys/net/ipv4/osf", NULL);
+	ipt_unregister_match(&osf_match);
+	if (nts && nts->socket)
+		sock_release(nts->socket);
+
+	list_for_each_safe(ent, n, &finger_list)
+	{
+		f = list_entry(ent, struct osf_finger, flist);
+		list_del(&f->flist);
+		finger_free(f);
+	}
+	
+	log("OS fingerprint matching module finished.\n");
+}
+
+module_init(osf_init);
+module_exit(osf_fini);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Evgeniy Polyakov <johnpol@2ka.mipt.ru>");
+MODULE_DESCRIPTION("Passive OS fingerprint matching.");
diff -Nru ./patch-o-matic-ng/osf.old/linux-2.4/net/ipv4/netfilter/Kconfig.ladd ./patch-o-matic-ng/osf/linux-2.4/net/ipv4/netfilter/Kconfig.ladd
--- ./patch-o-matic-ng/osf.old/linux-2.4/net/ipv4/netfilter/Kconfig.ladd	1970-01-01 03:00:00.000000000 +0300
+++ ./patch-o-matic-ng/osf/linux-2.4/net/ipv4/netfilter/Kconfig.ladd	2004-06-14 14:27:09.000000000 +0400
@@ -0,0 +1,21 @@
+config IP_NF_MATCH_OSF
+	tristate  'OSF match support'
+	depends on IP_NF_IPTABLES
+	help
+	
+	  The idea of passive OS fingerprint matching exists for quite a long time,
+	  but was created as extension fo OpenBSD pf only some weeks ago.
+	  Original idea was lurked in some OpenBSD mailing list (thanks
+	  grange@open...) and than adopted for Linux netfilter in form of this code.
+	
+	  Original table was created by Michal Zalewski <lcamtuf@coredump.cx> for
+	  his excellent p0f and than changed a bit for more convenience.
+	
+	  This module compares some data(WS, MSS, options and it's order, ttl,
+	  df and others) from first SYN packet (actually from packets with SYN
+	  bit set) with hardcoded in fingers[] table ones.
+	
+	  If you say Y here, try iptables -m osf --help for more information.
+	 
+	  If you want to compile it as a module, say M here and read
+	  Documentation/modules.txt.  If unsure, say `N'.
diff -Nru ./patch-o-matic-ng/osf.old/linux-2.4/net/ipv4/netfilter/Makefile.ladd ./patch-o-matic-ng/osf/linux-2.4/net/ipv4/netfilter/Makefile.ladd
--- ./patch-o-matic-ng/osf.old/linux-2.4/net/ipv4/netfilter/Makefile.ladd	1970-01-01 03:00:00.000000000 +0300
+++ ./patch-o-matic-ng/osf/linux-2.4/net/ipv4/netfilter/Makefile.ladd	2003-12-18 21:28:43.000000000 +0300
@@ -0,0 +1,4 @@
+obj-$(CONFIG_IP_NF_MATCH_TOS) += ipt_tos.o
+
+obj-$(CONFIG_IP_NF_MATCH_OSF) += ipt_osf.o
+
diff -Nru ./patch-o-matic-ng/osf.old/linux-2.6/CVS/Entries ./patch-o-matic-ng/osf/linux-2.6/CVS/Entries
--- ./patch-o-matic-ng/osf.old/linux-2.6/CVS/Entries	1970-01-01 03:00:00.000000000 +0300
+++ ./patch-o-matic-ng/osf/linux-2.6/CVS/Entries	2004-07-18 00:07:28.000000000 +0400
@@ -0,0 +1,3 @@
+D/include////
+D/net////
+D/Documentation////
diff -Nru ./patch-o-matic-ng/osf.old/linux-2.6/CVS/Repository ./patch-o-matic-ng/osf/linux-2.6/CVS/Repository
--- ./patch-o-matic-ng/osf.old/linux-2.6/CVS/Repository	1970-01-01 03:00:00.000000000 +0300
+++ ./patch-o-matic-ng/osf/linux-2.6/CVS/Repository	2004-07-18 00:07:28.000000000 +0400
@@ -0,0 +1 @@
+patch-o-matic-ng/osf/linux
diff -Nru ./patch-o-matic-ng/osf.old/linux-2.6/CVS/Root ./patch-o-matic-ng/osf/linux-2.6/CVS/Root
--- ./patch-o-matic-ng/osf.old/linux-2.6/CVS/Root	1970-01-01 03:00:00.000000000 +0300
+++ ./patch-o-matic-ng/osf/linux-2.6/CVS/Root	2004-07-18 00:07:28.000000000 +0400
@@ -0,0 +1 @@
+:pserver:cvs:cvs@pserver.netfilter.org:/cvspublic
diff -Nru ./patch-o-matic-ng/osf.old/linux-2.6/Documentation/Configure.help.ladd ./patch-o-matic-ng/osf/linux-2.6/Documentation/Configure.help.ladd
--- ./patch-o-matic-ng/osf.old/linux-2.6/Documentation/Configure.help.ladd	1970-01-01 03:00:00.000000000 +0300
+++ ./patch-o-matic-ng/osf/linux-2.6/Documentation/Configure.help.ladd	2004-07-18 00:07:28.000000000 +0400
@@ -0,0 +1,20 @@
+CONFIG_IP_NF_MATCH_TOS
+OSF match support
+CONFIG_IP_NF_MATCH_OSF
+
+  The idea of passive OS fingerprint matching exists for quite a long time,
+  but was created as extension fo OpenBSD pf only some weeks ago.
+  Original idea was lurked in some OpenBSD mailing list (thanks
+  grange@open...) and than adopted for Linux netfilter in form of this code.
+
+  Original table was created by Michal Zalewski <lcamtuf@coredump.cx> for
+  his excellent p0f and than changed a bit for more convenience.
+
+  This module compares some data(WS, MSS, options and it's order, ttl,
+  df and others) from first SYN packet (actually from packets with SYN
+  bit set) with hardcoded in fingers[] table ones.
+
+  If you say Y here, try iptables -m osf --help for more information.
+ 
+  If you want to compile it as a module, say M here and read
+  Documentation/modules.txt.  If unsure, say `N'.
diff -Nru ./patch-o-matic-ng/osf.old/linux-2.6/Documentation/CVS/Entries ./patch-o-matic-ng/osf/linux-2.6/Documentation/CVS/Entries
--- ./patch-o-matic-ng/osf.old/linux-2.6/Documentation/CVS/Entries	1970-01-01 03:00:00.000000000 +0300
+++ ./patch-o-matic-ng/osf/linux-2.6/Documentation/CVS/Entries	2004-07-18 00:07:28.000000000 +0400
@@ -0,0 +1,2 @@
+/Configure.help.ladd/1.1/Fri Mar  5 09:30:27 2004//
+D
diff -Nru ./patch-o-matic-ng/osf.old/linux-2.6/Documentation/CVS/Repository ./patch-o-matic-ng/osf/linux-2.6/Documentation/CVS/Repository
--- ./patch-o-matic-ng/osf.old/linux-2.6/Documentation/CVS/Repository	1970-01-01 03:00:00.000000000 +0300
+++ ./patch-o-matic-ng/osf/linux-2.6/Documentation/CVS/Repository	2004-07-18 00:07:28.000000000 +0400
@@ -0,0 +1 @@
+patch-o-matic-ng/osf/linux/Documentation
diff -Nru ./patch-o-matic-ng/osf.old/linux-2.6/Documentation/CVS/Root ./patch-o-matic-ng/osf/linux-2.6/Documentation/CVS/Root
--- ./patch-o-matic-ng/osf.old/linux-2.6/Documentation/CVS/Root	1970-01-01 03:00:00.000000000 +0300
+++ ./patch-o-matic-ng/osf/linux-2.6/Documentation/CVS/Root	2004-07-18 00:07:28.000000000 +0400
@@ -0,0 +1 @@
+:pserver:cvs:cvs@pserver.netfilter.org:/cvspublic
diff -Nru ./patch-o-matic-ng/osf.old/linux-2.6/include/CVS/Entries ./patch-o-matic-ng/osf/linux-2.6/include/CVS/Entries
--- ./patch-o-matic-ng/osf.old/linux-2.6/include/CVS/Entries	1970-01-01 03:00:00.000000000 +0300
+++ ./patch-o-matic-ng/osf/linux-2.6/include/CVS/Entries	2004-07-18 00:07:28.000000000 +0400
@@ -0,0 +1 @@
+D/linux////
diff -Nru ./patch-o-matic-ng/osf.old/linux-2.6/include/CVS/Repository ./patch-o-matic-ng/osf/linux-2.6/include/CVS/Repository
--- ./patch-o-matic-ng/osf.old/linux-2.6/include/CVS/Repository	1970-01-01 03:00:00.000000000 +0300
+++ ./patch-o-matic-ng/osf/linux-2.6/include/CVS/Repository	2004-07-18 00:07:28.000000000 +0400
@@ -0,0 +1 @@
+patch-o-matic-ng/osf/linux/include
diff -Nru ./patch-o-matic-ng/osf.old/linux-2.6/include/CVS/Root ./patch-o-matic-ng/osf/linux-2.6/include/CVS/Root
--- ./patch-o-matic-ng/osf.old/linux-2.6/include/CVS/Root	1970-01-01 03:00:00.000000000 +0300
+++ ./patch-o-matic-ng/osf/linux-2.6/include/CVS/Root	2004-07-18 00:07:28.000000000 +0400
@@ -0,0 +1 @@
+:pserver:cvs:cvs@pserver.netfilter.org:/cvspublic
diff -Nru ./patch-o-matic-ng/osf.old/linux-2.6/include/linux/CVS/Entries ./patch-o-matic-ng/osf/linux-2.6/include/linux/CVS/Entries
--- ./patch-o-matic-ng/osf.old/linux-2.6/include/linux/CVS/Entries	1970-01-01 03:00:00.000000000 +0300
+++ ./patch-o-matic-ng/osf/linux-2.6/include/linux/CVS/Entries	2004-07-18 00:07:28.000000000 +0400
@@ -0,0 +1 @@
+D/netfilter_ipv4////
diff -Nru ./patch-o-matic-ng/osf.old/linux-2.6/include/linux/CVS/Repository ./patch-o-matic-ng/osf/linux-2.6/include/linux/CVS/Repository
--- ./patch-o-matic-ng/osf.old/linux-2.6/include/linux/CVS/Repository	1970-01-01 03:00:00.000000000 +0300
+++ ./patch-o-matic-ng/osf/linux-2.6/include/linux/CVS/Repository	2004-07-18 00:07:28.000000000 +0400
@@ -0,0 +1 @@
+patch-o-matic-ng/osf/linux/include/linux
diff -Nru ./patch-o-matic-ng/osf.old/linux-2.6/include/linux/CVS/Root ./patch-o-matic-ng/osf/linux-2.6/include/linux/CVS/Root
--- ./patch-o-matic-ng/osf.old/linux-2.6/include/linux/CVS/Root	1970-01-01 03:00:00.000000000 +0300
+++ ./patch-o-matic-ng/osf/linux-2.6/include/linux/CVS/Root	2004-07-18 00:07:28.000000000 +0400
@@ -0,0 +1 @@
+:pserver:cvs:cvs@pserver.netfilter.org:/cvspublic
diff -Nru ./patch-o-matic-ng/osf.old/linux-2.6/include/linux/netfilter_ipv4/CVS/Entries ./patch-o-matic-ng/osf/linux-2.6/include/linux/netfilter_ipv4/CVS/Entries
--- ./patch-o-matic-ng/osf.old/linux-2.6/include/linux/netfilter_ipv4/CVS/Entries	1970-01-01 03:00:00.000000000 +0300
+++ ./patch-o-matic-ng/osf/linux-2.6/include/linux/netfilter_ipv4/CVS/Entries	2004-07-18 00:07:28.000000000 +0400
@@ -0,0 +1,2 @@
+/ipt_osf.h/1.2/Sat Mar  6 10:30:56 2004//
+D
diff -Nru ./patch-o-matic-ng/osf.old/linux-2.6/include/linux/netfilter_ipv4/CVS/Repository ./patch-o-matic-ng/osf/linux-2.6/include/linux/netfilter_ipv4/CVS/Repository
--- ./patch-o-matic-ng/osf.old/linux-2.6/include/linux/netfilter_ipv4/CVS/Repository	1970-01-01 03:00:00.000000000 +0300
+++ ./patch-o-matic-ng/osf/linux-2.6/include/linux/netfilter_ipv4/CVS/Repository	2004-07-18 00:07:28.000000000 +0400
@@ -0,0 +1 @@
+patch-o-matic-ng/osf/linux/include/linux/netfilter_ipv4
diff -Nru ./patch-o-matic-ng/osf.old/linux-2.6/include/linux/netfilter_ipv4/CVS/Root ./patch-o-matic-ng/osf/linux-2.6/include/linux/netfilter_ipv4/CVS/Root
--- ./patch-o-matic-ng/osf.old/linux-2.6/include/linux/netfilter_ipv4/CVS/Root	1970-01-01 03:00:00.000000000 +0300
+++ ./patch-o-matic-ng/osf/linux-2.6/include/linux/netfilter_ipv4/CVS/Root	2004-07-18 00:07:28.000000000 +0400
@@ -0,0 +1 @@
+:pserver:cvs:cvs@pserver.netfilter.org:/cvspublic
diff -Nru ./patch-o-matic-ng/osf.old/linux-2.6/include/linux/netfilter_ipv4/ipt_osf.h ./patch-o-matic-ng/osf/linux-2.6/include/linux/netfilter_ipv4/ipt_osf.h
--- ./patch-o-matic-ng/osf.old/linux-2.6/include/linux/netfilter_ipv4/ipt_osf.h	1970-01-01 03:00:00.000000000 +0300
+++ ./patch-o-matic-ng/osf/linux-2.6/include/linux/netfilter_ipv4/ipt_osf.h	2004-07-18 00:07:28.000000000 +0400
@@ -0,0 +1,148 @@
+/*
+ * ipt_osf.h
+ *
+ * Copyright (c) 2003 Evgeniy Polyakov <johnpol@2ka.mipt.ru>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _IPT_OSF_H
+#define _IPT_OSF_H
+
+#define MAXGENRELEN		32
+#define MAXDETLEN		64
+
+#define IPT_OSF_GENRE		1
+#define	IPT_OSF_SMART		2
+#define IPT_OSF_LOG		4
+#define IPT_OSF_NETLINK		8
+
+#define IPT_OSF_LOGLEVEL_ALL	0
+#define IPT_OSF_LOGLEVEL_FIRST	1
+
+#include <linux/list.h>
+
+#ifndef __KERNEL__
+#include <netinet/ip.h>
+#include <netinet/tcp.h>
+
+struct list_head
+{
+	struct list_head *prev, *next;
+};
+#endif
+
+struct ipt_osf_info
+{
+	char 			genre[MAXGENRELEN];
+	int			len;
+	unsigned long		flags;
+	int			loglevel;
+	int			invert; /* UNSUPPORTED */
+};
+
+struct osf_wc
+{
+	char			wc;
+	unsigned long		val;
+};
+
+/* This struct represents IANA options
+ * http://www.iana.org/assignments/tcp-parameters
+ */
+struct osf_opt
+{
+	unsigned char		kind;
+	unsigned char		length;
+	struct osf_wc		wc;
+};
+
+struct osf_finger
+{
+	struct list_head	flist;
+	struct osf_wc		wss;
+	unsigned char		ttl;
+	unsigned char		df;
+	unsigned long		ss;
+	unsigned char		genre[MAXGENRELEN];
+	unsigned char		version[MAXGENRELEN], subtype[MAXGENRELEN];
+	
+	/* Not needed, but for consistency with original table from Michal Zalewski */
+	unsigned char		details[MAXDETLEN]; 
+
+	int 			opt_num;
+	struct osf_opt		opt[MAX_IPOPTLEN]; /* In case it is all NOP or EOL */
+
+};
+
+struct ipt_osf_nlmsg
+{
+	struct osf_finger	f;
+	struct iphdr 		ip;
+	struct tcphdr 		tcp;
+};
+
+#ifdef __KERNEL__
+
+/* Defines for IANA option kinds */
+
+#define OSFOPT_EOL		0	/* End of options */
+#define OSFOPT_NOP		1	/* NOP */
+#define OSFOPT_MSS		2	/* Maximum segment size */
+#define OSFOPT_WSO		3	/* Window scale option */
+#define OSFOPT_SACKP		4	/* SACK permitted */
+#define OSFOPT_SACK		5	/* SACK */
+#define OSFOPT_ECHO		6	
+#define OSFOPT_ECHOREPLY	7
+#define OSFOPT_TS		8	/* Timestamp option */
+#define OSFOPT_POCP		9	/* Partial Order Connection Permitted */
+#define OSFOPT_POSP		10	/* Partial Order Service Profile */
+/* Others are not used in current OSF */
+
+static struct osf_opt IANA_opts[] = 
+{
+	{0, 1,},
+	{1, 1,},
+	{2, 4,},
+	{3, 3,},
+	{4, 2,},
+	{5, 1 ,}, /* SACK length is not defined */
+	{6, 6,},
+	{7, 6,},
+	{8, 10,},
+	{9, 2,},
+	{10, 3,},
+	{11, 1,}, /* CC: Suppose 1 */
+	{12, 1,}, /* the same */
+	{13, 1,}, /* and here too */
+	{14, 3,},
+	{15, 1,}, /* TCP Alternate Checksum Data. Length is not defined */
+	{16, 1,},
+	{17, 1,},
+	{18, 3,},
+	{19, 18,},
+	{20, 1,},
+	{21, 1,},
+	{22, 1,},
+	{23, 1,},
+	{24, 1,},
+	{25, 1,},
+	{26, 1,},
+};
+
+#endif /* __KERNEL__ */
+
+#endif /* _IPT_OSF_H */
diff -Nru ./patch-o-matic-ng/osf.old/linux-2.6/net/CVS/Entries ./patch-o-matic-ng/osf/linux-2.6/net/CVS/Entries
--- ./patch-o-matic-ng/osf.old/linux-2.6/net/CVS/Entries	1970-01-01 03:00:00.000000000 +0300
+++ ./patch-o-matic-ng/osf/linux-2.6/net/CVS/Entries	2004-07-18 00:07:28.000000000 +0400
@@ -0,0 +1 @@
+D/ipv4////
diff -Nru ./patch-o-matic-ng/osf.old/linux-2.6/net/CVS/Repository ./patch-o-matic-ng/osf/linux-2.6/net/CVS/Repository
--- ./patch-o-matic-ng/osf.old/linux-2.6/net/CVS/Repository	1970-01-01 03:00:00.000000000 +0300
+++ ./patch-o-matic-ng/osf/linux-2.6/net/CVS/Repository	2004-07-18 00:07:28.000000000 +0400
@@ -0,0 +1 @@
+patch-o-matic-ng/osf/linux/net
diff -Nru ./patch-o-matic-ng/osf.old/linux-2.6/net/CVS/Root ./patch-o-matic-ng/osf/linux-2.6/net/CVS/Root
--- ./patch-o-matic-ng/osf.old/linux-2.6/net/CVS/Root	1970-01-01 03:00:00.000000000 +0300
+++ ./patch-o-matic-ng/osf/linux-2.6/net/CVS/Root	2004-07-18 00:07:28.000000000 +0400
@@ -0,0 +1 @@
+:pserver:cvs:cvs@pserver.netfilter.org:/cvspublic
diff -Nru ./patch-o-matic-ng/osf.old/linux-2.6/net/ipv4/CVS/Entries ./patch-o-matic-ng/osf/linux-2.6/net/ipv4/CVS/Entries
--- ./patch-o-matic-ng/osf.old/linux-2.6/net/ipv4/CVS/Entries	1970-01-01 03:00:00.000000000 +0300
+++ ./patch-o-matic-ng/osf/linux-2.6/net/ipv4/CVS/Entries	2004-07-18 00:07:28.000000000 +0400
@@ -0,0 +1 @@
+D/netfilter////
diff -Nru ./patch-o-matic-ng/osf.old/linux-2.6/net/ipv4/CVS/Repository ./patch-o-matic-ng/osf/linux-2.6/net/ipv4/CVS/Repository
--- ./patch-o-matic-ng/osf.old/linux-2.6/net/ipv4/CVS/Repository	1970-01-01 03:00:00.000000000 +0300
+++ ./patch-o-matic-ng/osf/linux-2.6/net/ipv4/CVS/Repository	2004-07-18 00:07:28.000000000 +0400
@@ -0,0 +1 @@
+patch-o-matic-ng/osf/linux/net/ipv4
diff -Nru ./patch-o-matic-ng/osf.old/linux-2.6/net/ipv4/CVS/Root ./patch-o-matic-ng/osf/linux-2.6/net/ipv4/CVS/Root
--- ./patch-o-matic-ng/osf.old/linux-2.6/net/ipv4/CVS/Root	1970-01-01 03:00:00.000000000 +0300
+++ ./patch-o-matic-ng/osf/linux-2.6/net/ipv4/CVS/Root	2004-07-18 00:07:28.000000000 +0400
@@ -0,0 +1 @@
+:pserver:cvs:cvs@pserver.netfilter.org:/cvspublic
diff -Nru ./patch-o-matic-ng/osf.old/linux-2.6/net/ipv4/netfilter/Config.in.ladd ./patch-o-matic-ng/osf/linux-2.6/net/ipv4/netfilter/Config.in.ladd
--- ./patch-o-matic-ng/osf.old/linux-2.6/net/ipv4/netfilter/Config.in.ladd	1970-01-01 03:00:00.000000000 +0300
+++ ./patch-o-matic-ng/osf/linux-2.6/net/ipv4/netfilter/Config.in.ladd	2004-07-18 00:17:37.000000000 +0400
@@ -0,0 +1,9 @@
+config CONFIG_IP_NF_MATCH_OSF
+	tristate 'OS fingerprint matching module'
+        depends on IP_NF_IPTABLES
+	help
+	  This option adds an `osf' match, which allows you to create rules in
+	  any iptables table based on remote OS fingerprint.
+	 
+	  If you want to compile it as a module, say M here and read
+	  Documentation/modules.txt.  If unsure, say `N'.
diff -Nru ./patch-o-matic-ng/osf.old/linux-2.6/net/ipv4/netfilter/CVS/Entries ./patch-o-matic-ng/osf/linux-2.6/net/ipv4/netfilter/CVS/Entries
--- ./patch-o-matic-ng/osf.old/linux-2.6/net/ipv4/netfilter/CVS/Entries	1970-01-01 03:00:00.000000000 +0300
+++ ./patch-o-matic-ng/osf/linux-2.6/net/ipv4/netfilter/CVS/Entries	2004-07-18 00:07:28.000000000 +0400
@@ -0,0 +1,5 @@
+/Config.in.ladd/1.1/Thu Dec 18 18:28:43 2003//
+/Makefile.ladd/1.1/Thu Dec 18 18:28:43 2003//
+/Kconfig.ladd/1.2/Mon Jun 14 10:27:09 2004//
+/ipt_osf.c/1.2/Sat Mar  6 10:30:57 2004//
+D
diff -Nru ./patch-o-matic-ng/osf.old/linux-2.6/net/ipv4/netfilter/CVS/Repository ./patch-o-matic-ng/osf/linux-2.6/net/ipv4/netfilter/CVS/Repository
--- ./patch-o-matic-ng/osf.old/linux-2.6/net/ipv4/netfilter/CVS/Repository	1970-01-01 03:00:00.000000000 +0300
+++ ./patch-o-matic-ng/osf/linux-2.6/net/ipv4/netfilter/CVS/Repository	2004-07-18 00:07:28.000000000 +0400
@@ -0,0 +1 @@
+patch-o-matic-ng/osf/linux/net/ipv4/netfilter
diff -Nru ./patch-o-matic-ng/osf.old/linux-2.6/net/ipv4/netfilter/CVS/Root ./patch-o-matic-ng/osf/linux-2.6/net/ipv4/netfilter/CVS/Root
--- ./patch-o-matic-ng/osf.old/linux-2.6/net/ipv4/netfilter/CVS/Root	1970-01-01 03:00:00.000000000 +0300
+++ ./patch-o-matic-ng/osf/linux-2.6/net/ipv4/netfilter/CVS/Root	2004-07-18 00:07:28.000000000 +0400
@@ -0,0 +1 @@
+:pserver:cvs:cvs@pserver.netfilter.org:/cvspublic
diff -Nru ./patch-o-matic-ng/osf.old/linux-2.6/net/ipv4/netfilter/ipt_osf.c ./patch-o-matic-ng/osf/linux-2.6/net/ipv4/netfilter/ipt_osf.c
--- ./patch-o-matic-ng/osf.old/linux-2.6/net/ipv4/netfilter/ipt_osf.c	1970-01-01 03:00:00.000000000 +0300
+++ ./patch-o-matic-ng/osf/linux-2.6/net/ipv4/netfilter/ipt_osf.c	2004-07-18 00:10:43.000000000 +0400
@@ -0,0 +1,863 @@
+/*
+ * ipt_osf.c
+ *
+ * Copyright (c) 2003 Evgeniy Polyakov <johnpol@2ka.mipt.ru>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/*
+ * OS fingerprint matching module.
+ * It simply compares various parameters from SYN packet with
+ * some hardcoded ones.
+ *
+ * Original table was created by Michal Zalewski <lcamtuf@coredump.cx>
+ * for his p0f.
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/smp.h>
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/file.h>
+#include <linux/ip.h>
+#include <linux/proc_fs.h>
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/ctype.h>
+#include <linux/list.h>
+#include <linux/if.h>
+
+#include <net/sock.h>
+#include <net/ip.h>
+
+#include <linux/netfilter_ipv4/ip_tables.h>
+
+#include <linux/netfilter_ipv4/ipt_osf.h>
+
+#define OSF_DEBUG
+
+#ifdef OSF_DEBUG
+#define log(x...) 		printk(KERN_INFO "ipt_osf: " x)
+#define loga(x...) 		printk(x)
+#else
+#define log(x...) 		do {} while(0)
+#define loga(x...) 		do {} while(0)
+#endif
+
+#define FMATCH_WRONG		0
+#define FMATCH_OK		1
+#define FMATCH_OPT_WRONG	2
+
+#define OPTDEL			','
+#define OSFPDEL 		':'
+#define MAXOPTSTRLEN		128
+#define OSFFLUSH		"FLUSH"
+
+static rwlock_t osf_lock = RW_LOCK_UNLOCKED;
+static spinlock_t ipt_osf_netlink_lock = SPIN_LOCK_UNLOCKED;
+static struct list_head	finger_list;	
+static int match(const struct sk_buff *, const struct net_device *, const struct net_device *,
+		      const void *, int, 
+		      int *);
+static int checkentry(const char *, const struct ipt_ip *, void *,
+		           unsigned int, unsigned int);
+
+static unsigned long seq, ipt_osf_groups = 1;
+static struct sock *nts;
+
+static struct ipt_match osf_match = 
+{ 
+	{ NULL, NULL }, 
+	"osf", 
+	&match, 
+	&checkentry, 
+	NULL, 
+	THIS_MODULE 
+};
+
+static void ipt_osf_nlsend(struct osf_finger *f, const struct sk_buff *sk)
+{
+	unsigned int size;
+	struct sk_buff *skb;
+	struct ipt_osf_nlmsg *data;
+	struct nlmsghdr *nlh;
+
+	size = NLMSG_SPACE(sizeof(struct ipt_osf_nlmsg));
+
+	skb = alloc_skb(size, GFP_ATOMIC);
+	if (!skb)
+	{
+		log("skb_alloc() failed.\n");
+		return;
+	}
+	
+	nlh = NLMSG_PUT(skb, 0, seq++, NLMSG_DONE, size - sizeof(*nlh));
+	
+	data = (struct ipt_osf_nlmsg *)NLMSG_DATA(nlh);
+
+	memcpy(&data->f, f, sizeof(struct osf_finger));
+	memcpy(&data->ip, sk->nh.iph, sizeof(struct iphdr));
+	memcpy(&data->tcp, (struct tcphdr *)((u_int32_t *)sk->nh.iph + sk->nh.iph->ihl), sizeof(struct tcphdr));
+
+	NETLINK_CB(skb).dst_groups = ipt_osf_groups;
+	netlink_broadcast(nts, skb, 0, ipt_osf_groups, GFP_ATOMIC);
+
+nlmsg_failure:
+	return;
+}
+
+static inline int smart_dec(const struct sk_buff *skb, unsigned long flags, unsigned char f_ttl)
+{
+	struct iphdr *ip = skb->nh.iph;
+
+	if (flags & IPT_OSF_SMART)
+	{
+		struct in_device *in_dev = in_dev_get(skb->dev);
+
+		for_ifa(in_dev)
+		{
+			if (inet_ifa_match(ip->saddr, ifa))
+			{
+				in_dev_put(in_dev);
+				return (ip->ttl == f_ttl);
+			}
+		}
+		endfor_ifa(in_dev);
+		
+		in_dev_put(in_dev);
+		return (ip->ttl <= f_ttl);
+	}
+	else
+		return (ip->ttl == f_ttl);
+}
+
+static int
+match(const struct sk_buff *skb, const struct net_device *in, const struct net_device *out,
+      const void *matchinfo, int offset,
+      int *hotdrop)
+{
+	struct ipt_osf_info *info = (struct ipt_osf_info *)matchinfo;
+	struct iphdr *ip = skb->nh.iph;
+	struct tcphdr *tcp;
+	int fmatch = FMATCH_WRONG, fcount = 0;
+	unsigned long totlen, optsize = 0, window;
+	unsigned char df, *optp = NULL, *_optp = NULL;
+	char check_WSS = 0;
+	struct list_head *ent;
+	struct osf_finger *f;
+
+	if (!ip || !info)
+		return 0;
+				
+	tcp = (struct tcphdr *)((u_int32_t *)ip + ip->ihl);
+
+	if (!tcp->syn)
+		return 0;
+	
+	totlen = ntohs(ip->tot_len);
+	df = ((ntohs(ip->frag_off) & IP_DF)?1:0);
+	window = ntohs(tcp->window);
+	
+	if (tcp->doff*4 > sizeof(struct tcphdr))
+	{
+		_optp = optp = (char *)(tcp+1);
+		optsize = tcp->doff*4 - sizeof(struct tcphdr);
+	}
+
+	
+	/* Actually we can create hash/table of all genres and search
+	 * only in appropriate part, but here is initial variant,
+	 * so will use slow path.
+	 */
+	read_lock(&osf_lock);
+	list_for_each(ent, &finger_list)
+	{
+		f = list_entry(ent, struct osf_finger, flist);
+	
+		if (!(info->flags & IPT_OSF_LOG) && strcmp(info->genre, f->genre)) 
+			continue;
+
+		optp = _optp;
+		fmatch = FMATCH_WRONG;
+
+		if (totlen == f->ss && df == f->df && 
+			smart_dec(skb, info->flags, f->ttl))
+		{
+			unsigned long foptsize;
+			int optnum;
+			unsigned short mss = 0;
+
+			check_WSS = 0;
+
+			switch (f->wss.wc)
+			{
+				case 0:	  check_WSS = 0; break;
+				case 'S': check_WSS = 1; break;
+				case 'T': check_WSS = 2; break;
+				case '%': check_WSS = 3; break;
+				default: log("Wrong fingerprint wss.wc=%d, %s - %s\n", 
+							 f->wss.wc, f->genre, f->details);
+					 check_WSS = 4;
+					 break;
+			}
+			if (check_WSS == 4)
+				continue;
+
+			/* Check options */
+
+			foptsize = 0;
+			for (optnum=0; optnum<f->opt_num; ++optnum)
+				foptsize += f->opt[optnum].length;
+
+				
+			if (foptsize > MAX_IPOPTLEN || optsize > MAX_IPOPTLEN || optsize != foptsize)
+				continue;
+
+			if (!optp)
+			{
+				fmatch = FMATCH_OK;
+				loga("\tYEP : matching without options.\n");
+				if ((info->flags & IPT_OSF_LOG) && 
+					info->loglevel == IPT_OSF_LOGLEVEL_FIRST)
+					break;
+				else
+					continue;
+			}
+			
+
+			for (optnum=0; optnum<f->opt_num; ++optnum)
+			{
+				if (f->opt[optnum].kind == (*optp)) 
+				{
+					unsigned char len = f->opt[optnum].length;
+					unsigned char *optend = optp + len;
+					int loop_cont = 0;
+
+					fmatch = FMATCH_OK;
+
+
+					switch (*optp)
+					{
+						case OSFOPT_MSS:
+							mss = ntohs(*(unsigned short *)(optp+2));
+							break;
+						case OSFOPT_TS:
+							loop_cont = 1;
+							break;
+					}
+					
+					if (loop_cont)
+					{
+						optp = optend;
+						continue;
+					}
+					
+					if (len != 1)
+					{
+						/* Skip kind and length fields*/
+						optp += 2; 
+
+						if (f->opt[optnum].wc.val != 0)
+						{
+							unsigned long tmp = 0;
+							
+							/* Hmmm... It looks a bit ugly. :) */
+							memcpy(&tmp, optp, 
+								(len > sizeof(unsigned long)?
+								 	sizeof(unsigned long):len));
+							/* 2 + 2: optlen(2 bytes) + 
+							 * 	kind(1 byte) + length(1 byte) */
+							if (len == 4) 
+								tmp = ntohs(tmp);
+							else
+								tmp = ntohl(tmp);
+
+							if (f->opt[optnum].wc.wc == '%')
+							{
+								if ((tmp % f->opt[optnum].wc.val) != 0)
+									fmatch = FMATCH_OPT_WRONG;
+							}
+							else if (tmp != f->opt[optnum].wc.val)
+								fmatch = FMATCH_OPT_WRONG;
+						}
+					}
+
+					optp = optend;
+				}
+				else
+					fmatch = FMATCH_OPT_WRONG;
+
+				if (fmatch != FMATCH_OK)
+					break;
+			}
+
+			if (fmatch != FMATCH_OPT_WRONG)
+			{
+				fmatch = FMATCH_WRONG;
+
+				switch (check_WSS)
+				{
+					case 0:
+						if (f->wss.val == 0 || window == f->wss.val)
+							fmatch = FMATCH_OK;
+						break;
+					case 1: /* MSS */
+/* Lurked in OpenBSD */
+#define SMART_MSS	1460
+						if (window == f->wss.val*mss || 
+							window == f->wss.val*SMART_MSS)
+							fmatch = FMATCH_OK;
+						break;
+					case 2: /* MTU */
+						if (window == f->wss.val*(mss+40) ||
+							window == f->wss.val*(SMART_MSS+40))
+							fmatch = FMATCH_OK;
+						break;
+					case 3: /* MOD */
+						if ((window % f->wss.val) == 0)
+							fmatch = FMATCH_OK;
+						break;
+				}
+			}
+					
+
+			if (fmatch == FMATCH_OK)
+			{
+				fcount++;
+				log("%s [%s:%s:%s] : %u.%u.%u.%u:%u -> %u.%u.%u.%u:%u hops=%d\n", 
+					f->genre, f->version,
+					f->subtype, f->details,
+					NIPQUAD(ip->saddr), ntohs(tcp->source),
+					NIPQUAD(ip->daddr), ntohs(tcp->dest),
+					f->ttl - ip->ttl);
+				if (info->flags & IPT_OSF_NETLINK)
+				{
+					spin_lock_bh(&ipt_osf_netlink_lock);
+					ipt_osf_nlsend(f, skb);
+					spin_unlock_bh(&ipt_osf_netlink_lock);
+				}
+				if ((info->flags & IPT_OSF_LOG) && 
+					info->loglevel == IPT_OSF_LOGLEVEL_FIRST)
+					break;
+			}
+		}
+	}
+	if (!fcount && (info->flags & (IPT_OSF_LOG | IPT_OSF_NETLINK)))
+	{
+		unsigned char opt[4 * 15 - sizeof(struct tcphdr)];
+		unsigned int i, optsize;
+		struct osf_finger fg;
+
+		memset(&fg, 0, sizeof(fg));
+
+		if ((info->flags & IPT_OSF_LOG))
+			log("Unknown: %lu:%d:%d:%lu:", window, ip->ttl, df, totlen);
+		if (optp)
+		{
+			optsize = tcp->doff * 4 - sizeof(struct tcphdr);
+			if (skb_copy_bits(skb, ip->ihl*4 + sizeof(struct tcphdr),
+					  opt, optsize) < 0)
+			{
+				if (info->flags & IPT_OSF_LOG)
+					loga("TRUNCATED");
+				if (info->flags & IPT_OSF_NETLINK)
+					strcpy(fg.details, "TRUNCATED");
+			}
+			else
+			{
+				for (i = 0; i < optsize; i++)
+				{
+					if (info->flags & IPT_OSF_LOG)
+						loga("%02X", opt[i]);
+				}
+				if (info->flags & IPT_OSF_NETLINK)
+					memcpy(fg.details, opt, MAXDETLEN);
+			}
+		}
+		if ((info->flags & IPT_OSF_LOG))
+			loga(" %u.%u.%u.%u:%u -> %u.%u.%u.%u:%u\n", 
+				NIPQUAD(ip->saddr), ntohs(tcp->source),
+				NIPQUAD(ip->daddr), ntohs(tcp->dest));
+		
+		if (info->flags & IPT_OSF_NETLINK)
+		{
+			fg.wss.val 	= window;
+			fg.ttl		= ip->ttl;
+			fg.df		= df;
+			fg.ss		= totlen;
+			strncpy(fg.genre, "Unknown", MAXGENRELEN);
+
+			spin_lock_bh(&ipt_osf_netlink_lock);
+			ipt_osf_nlsend(&fg, skb);
+			spin_unlock_bh(&ipt_osf_netlink_lock);
+		}
+	}
+
+	read_unlock(&osf_lock);
+
+	return (fmatch == FMATCH_OK)?1:0;
+}
+
+static int
+checkentry(const char *tablename,
+           const struct ipt_ip *ip,
+           void *matchinfo,
+           unsigned int matchsize,
+           unsigned int hook_mask)
+{
+       if (matchsize != IPT_ALIGN(sizeof(struct ipt_osf_info)))
+               return 0;
+       if (ip->proto != IPPROTO_TCP)
+	       return 0;
+
+       return 1;
+}
+
+static char * osf_strchr(char *ptr, char c)
+{
+	char *tmp;
+
+	tmp = strchr(ptr, c);
+
+	while (tmp && tmp+1 && isspace(*(tmp+1)))
+		tmp++;
+
+	return tmp;
+}
+
+static struct osf_finger * finger_alloc(void)
+{
+	struct osf_finger *f;
+
+	f = kmalloc(sizeof(struct osf_finger), GFP_KERNEL);
+	if (f)
+		memset(f, 0, sizeof(struct osf_finger));
+	
+	return f;
+}
+
+static void finger_free(struct osf_finger *f)
+{
+	memset(f, 0, sizeof(struct osf_finger));
+	kfree(f);
+}
+
+
+static void osf_parse_opt(struct osf_opt *opt, int *optnum, char *obuf, int olen)
+{
+	int i, op;
+	char *ptr, wc;
+	unsigned long val;
+
+	ptr = &obuf[0];
+	i = 0;
+	while (ptr != NULL && i < olen)
+	{
+		val = 0;
+		op = 0;
+		wc = 0;
+		switch (obuf[i])
+		{
+			case 'N': 
+				op = OSFOPT_NOP;
+				ptr = osf_strchr(&obuf[i], OPTDEL);
+				if (ptr)
+				{
+					*ptr = '\0';
+					ptr++;
+					i += (int)(ptr-&obuf[i]);
+
+				}
+				else
+					i++;
+				break;
+			case 'S': 
+				op = OSFOPT_SACKP;
+				ptr = osf_strchr(&obuf[i], OPTDEL);
+				if (ptr)
+				{
+					*ptr = '\0';
+					ptr++;
+					i += (int)(ptr-&obuf[i]);
+
+				}
+				else
+					i++;
+				break;
+			case 'T': 
+				op = OSFOPT_TS;
+				ptr = osf_strchr(&obuf[i], OPTDEL);
+				if (ptr)
+				{
+					*ptr = '\0';
+					ptr++;
+					i += (int)(ptr-&obuf[i]);
+
+				}
+				else
+					i++;
+				break;
+			case 'W': 
+				op = OSFOPT_WSO;
+				ptr = osf_strchr(&obuf[i], OPTDEL);
+				if (ptr)
+				{
+					switch (obuf[i+1])
+					{
+						case '%':	wc = '%'; break;
+						case 'S':	wc = 'S'; break;
+						case 'T':	wc = 'T'; break;
+						default:	wc = 0; break;
+					}
+					
+					*ptr = '\0';
+					ptr++;
+					if (wc)
+						val = simple_strtoul(&obuf[i+2], NULL, 10);
+					else
+						val = simple_strtoul(&obuf[i+1], NULL, 10);
+					i += (int)(ptr-&obuf[i]);
+
+				}
+				else
+					i++;
+				break;
+			case 'M': 
+				op = OSFOPT_MSS;
+				ptr = osf_strchr(&obuf[i], OPTDEL);
+				if (ptr)
+				{
+					if (obuf[i+1] == '%')
+						wc = '%';
+					*ptr = '\0';
+					ptr++;
+					if (wc)
+						val = simple_strtoul(&obuf[i+2], NULL, 10);
+					else
+						val = simple_strtoul(&obuf[i+1], NULL, 10);
+					i += (int)(ptr-&obuf[i]);
+
+				}
+				else
+					i++;
+				break;
+			case 'E': 
+				op = OSFOPT_EOL;
+				ptr = osf_strchr(&obuf[i], OPTDEL);
+				if (ptr)
+				{
+					*ptr = '\0';
+					ptr++;
+					i += (int)(ptr-&obuf[i]);
+
+				}
+				else
+					i++;
+				break;
+			default:
+				ptr = osf_strchr(&obuf[i], OPTDEL);
+				if (ptr)
+				{
+					ptr++;
+					i += (int)(ptr-&obuf[i]);
+
+				}
+				else
+					i++;
+				break;
+		}
+
+		opt[*optnum].kind 	= IANA_opts[op].kind;
+		opt[*optnum].length 	= IANA_opts[op].length;
+		opt[*optnum].wc.wc 	= wc;
+		opt[*optnum].wc.val	= val;
+
+		(*optnum)++;
+	}
+}
+
+static int osf_proc_read(char *buf, char **start, off_t off, int count, int *eof, void *data)
+{
+	struct list_head *ent;
+	struct osf_finger *f = NULL;
+	int i;
+	
+	*eof = 1;
+	count = 0;
+
+	read_lock_bh(&osf_lock);
+	list_for_each(ent, &finger_list)
+	{
+		f = list_entry(ent, struct osf_finger, flist);
+
+		log("%s [%s]", f->genre, f->details);
+		
+		count += sprintf(buf+count, "%s - %s[%s] : %s", 
+					f->genre, f->version,
+					f->subtype, f->details);
+		
+		if (f->opt_num)
+		{
+			loga(" OPT: ");
+			//count += sprintf(buf+count, " OPT: ");
+			for (i=0; i<f->opt_num; ++i)
+			{
+				//count += sprintf(buf+count, "%d.%c%lu; ", 
+				//	f->opt[i].kind, (f->opt[i].wc.wc)?f->opt[i].wc.wc:' ', f->opt[i].wc.val);
+				loga("%d.%c%lu; ", 
+					f->opt[i].kind, (f->opt[i].wc.wc)?f->opt[i].wc.wc:' ', f->opt[i].wc.val);
+			}
+		}
+		loga("\n");
+		count += sprintf(buf+count, "\n");
+	}
+	read_unlock_bh(&osf_lock);
+
+	return count;
+}
+
+static int osf_proc_write(struct file *file, const char *buffer, unsigned long count, void *data)
+{
+	int cnt;
+	unsigned long i;
+	char obuf[MAXOPTSTRLEN];
+	struct osf_finger *finger;
+	struct list_head *ent, *n;
+
+	char *pbeg, *pend;
+
+	if (count == strlen(OSFFLUSH) && !strncmp(buffer, OSFFLUSH, strlen(OSFFLUSH)))
+	{
+		int i = 0;
+		write_lock_bh(&osf_lock);
+		list_for_each_safe(ent, n, &finger_list)
+		{
+			i++;
+			finger = list_entry(ent, struct osf_finger, flist);
+			list_del(&finger->flist);
+			finger_free(finger);
+		}
+		write_unlock_bh(&osf_lock);
+	
+		log("Flushed %d entries.\n", i);
+		
+		return count;
+	}
+
+	
+	cnt = 0;
+	for (i=0; i<count && buffer[i] != '\0'; ++i)
+		if (buffer[i] == ':')
+			cnt++;
+
+	if (cnt != 8 || i != count)
+	{
+		log("Wrong input line cnt=%d[8], len=%lu[%lu]\n", 
+			cnt, i, count);
+		return count;
+	}
+
+	memset(obuf, 0, sizeof(obuf));
+	
+	finger = finger_alloc();
+	if (!finger)
+	{
+		log("Failed to allocate new fingerprint entry.\n");
+		return -ENOMEM;
+	}
+
+	pbeg = (char *)buffer;
+	pend = osf_strchr(pbeg, OSFPDEL);
+	if (pend)
+	{
+		*pend = '\0';
+		if (pbeg[0] == 'S')
+		{
+			finger->wss.wc = 'S';
+			if (pbeg[1] == '%')
+				finger->wss.val = simple_strtoul(pbeg+2, NULL, 10);
+			else if (pbeg[1] == '*')
+				finger->wss.val = 0;
+			else 
+				finger->wss.val = simple_strtoul(pbeg+1, NULL, 10);
+		}
+		else if (pbeg[0] == 'T')
+		{
+			finger->wss.wc = 'T';
+			if (pbeg[1] == '%')
+				finger->wss.val = simple_strtoul(pbeg+2, NULL, 10);
+			else if (pbeg[1] == '*')
+				finger->wss.val = 0;
+			else 
+				finger->wss.val = simple_strtoul(pbeg+1, NULL, 10);
+		}
+		else if (pbeg[0] == '%')
+		{
+			finger->wss.wc = '%';
+			finger->wss.val = simple_strtoul(pbeg+1, NULL, 10);
+		}
+		else if (isdigit(pbeg[0]))
+		{
+			finger->wss.wc = 0;
+			finger->wss.val = simple_strtoul(pbeg, NULL, 10);
+		}
+
+		pbeg = pend+1;
+	}
+	pend = osf_strchr(pbeg, OSFPDEL);
+	if (pend)
+	{
+		*pend = '\0';
+		finger->ttl = simple_strtoul(pbeg, NULL, 10);
+		pbeg = pend+1;
+	}
+	pend = osf_strchr(pbeg, OSFPDEL);
+	if (pend)
+	{
+		*pend = '\0';
+		finger->df = simple_strtoul(pbeg, NULL, 10);
+		pbeg = pend+1;
+	}
+	pend = osf_strchr(pbeg, OSFPDEL);
+	if (pend)
+	{
+		*pend = '\0';
+		finger->ss = simple_strtoul(pbeg, NULL, 10);
+		pbeg = pend+1;
+	}
+
+	pend = osf_strchr(pbeg, OSFPDEL);
+	if (pend)
+	{
+		*pend = '\0';
+		cnt = snprintf(obuf, sizeof(obuf), "%s", pbeg);
+		pbeg = pend+1;
+	}
+
+	pend = osf_strchr(pbeg, OSFPDEL);
+	if (pend)
+	{
+		*pend = '\0';
+		if (pbeg[0] == '@' || pbeg[0] == '*')
+			cnt = snprintf(finger->genre, sizeof(finger->genre), "%s", pbeg+1);
+		else
+			cnt = snprintf(finger->genre, sizeof(finger->genre), "%s", pbeg);
+		pbeg = pend+1;
+	}
+	
+	pend = osf_strchr(pbeg, OSFPDEL);
+	if (pend)
+	{
+		*pend = '\0';
+		cnt = snprintf(finger->version, sizeof(finger->version), "%s", pbeg);
+		pbeg = pend+1;
+	}
+	
+	pend = osf_strchr(pbeg, OSFPDEL);
+	if (pend)
+	{
+		*pend = '\0';
+		cnt = snprintf(finger->subtype, sizeof(finger->subtype), "%s", pbeg);
+		pbeg = pend+1;
+	}
+
+	cnt = snprintf(finger->details, 
+			((count - (pbeg - buffer)+1) > MAXDETLEN)?MAXDETLEN:(count - (pbeg - buffer)+1), 
+			"%s", pbeg);
+	
+	log("%s - %s[%s] : %s\n", 
+		finger->genre, finger->version,
+		finger->subtype, finger->details);
+	
+	osf_parse_opt(finger->opt, &finger->opt_num, obuf, sizeof(obuf));
+	
+
+	write_lock_bh(&osf_lock);
+	list_add_tail(&finger->flist, &finger_list);
+	write_unlock_bh(&osf_lock);
+
+	return count;
+}
+
+static int __init osf_init(void)
+{
+	int err;
+	struct proc_dir_entry *p;
+
+	log("Startng OS fingerprint matching module.\n");
+
+	INIT_LIST_HEAD(&finger_list);
+	
+	err = ipt_register_match(&osf_match);
+	if (err)
+	{
+		log("Failed to register OS fingerprint matching module.\n");
+		return -ENXIO;
+	}
+
+	p = create_proc_entry("sys/net/ipv4/osf", S_IFREG | 0644, NULL);
+	if (!p)
+	{
+		ipt_unregister_match(&osf_match);
+		return -ENXIO;
+	}
+
+	p->write_proc = osf_proc_write;
+	p->read_proc  = osf_proc_read;
+	
+	nts = netlink_kernel_create(NETLINK_NFLOG, NULL);
+	if (!nts)
+	{
+		log("netlink_kernel_create() failed\n");
+		remove_proc_entry("sys/net/ipv4/osf", NULL);
+		ipt_unregister_match(&osf_match);
+		return -ENOMEM;
+	}
+
+	return 0;
+}
+
+static void __exit osf_fini(void)
+{
+	struct list_head *ent, *n;
+	struct osf_finger *f;
+	
+	remove_proc_entry("sys/net/ipv4/osf", NULL);
+	ipt_unregister_match(&osf_match);
+	if (nts && nts->sk_socket)
+		sock_release(nts->sk_socket);
+
+	list_for_each_safe(ent, n, &finger_list)
+	{
+		f = list_entry(ent, struct osf_finger, flist);
+		list_del(&f->flist);
+		finger_free(f);
+	}
+	
+	log("OS fingerprint matching module finished.\n");
+}
+
+module_init(osf_init);
+module_exit(osf_fini);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Evgeniy Polyakov <johnpol@2ka.mipt.ru>");
+MODULE_DESCRIPTION("Passive OS fingerprint matching.");
diff -Nru ./patch-o-matic-ng/osf.old/linux-2.6/net/ipv4/netfilter/Kconfig.ladd ./patch-o-matic-ng/osf/linux-2.6/net/ipv4/netfilter/Kconfig.ladd
--- ./patch-o-matic-ng/osf.old/linux-2.6/net/ipv4/netfilter/Kconfig.ladd	1970-01-01 03:00:00.000000000 +0300
+++ ./patch-o-matic-ng/osf/linux-2.6/net/ipv4/netfilter/Kconfig.ladd	2004-07-18 00:07:28.000000000 +0400
@@ -0,0 +1,21 @@
+config IP_NF_MATCH_OSF
+	tristate  'OSF match support'
+	depends on IP_NF_IPTABLES
+	help
+	
+	  The idea of passive OS fingerprint matching exists for quite a long time,
+	  but was created as extension fo OpenBSD pf only some weeks ago.
+	  Original idea was lurked in some OpenBSD mailing list (thanks
+	  grange@open...) and than adopted for Linux netfilter in form of this code.
+	
+	  Original table was created by Michal Zalewski <lcamtuf@coredump.cx> for
+	  his excellent p0f and than changed a bit for more convenience.
+	
+	  This module compares some data(WS, MSS, options and it's order, ttl,
+	  df and others) from first SYN packet (actually from packets with SYN
+	  bit set) with hardcoded in fingers[] table ones.
+	
+	  If you say Y here, try iptables -m osf --help for more information.
+	 
+	  If you want to compile it as a module, say M here and read
+	  Documentation/modules.txt.  If unsure, say `N'.
diff -Nru ./patch-o-matic-ng/osf.old/linux-2.6/net/ipv4/netfilter/Makefile.ladd ./patch-o-matic-ng/osf/linux-2.6/net/ipv4/netfilter/Makefile.ladd
--- ./patch-o-matic-ng/osf.old/linux-2.6/net/ipv4/netfilter/Makefile.ladd	1970-01-01 03:00:00.000000000 +0300
+++ ./patch-o-matic-ng/osf/linux-2.6/net/ipv4/netfilter/Makefile.ladd	2004-07-18 00:07:28.000000000 +0400
@@ -0,0 +1,4 @@
+obj-$(CONFIG_IP_NF_MATCH_TOS) += ipt_tos.o
+
+obj-$(CONFIG_IP_NF_MATCH_OSF) += ipt_osf.o
+

--Multipart=_Sun__18_Jul_2004_00_25_35_+0400_u9MvSL1Iq.o/BSMm--