]> git.pld-linux.org Git - packages/kernel.git/blame - 2.6.1-rc2-NF-osf-20040107.patch
- added description of djurban's branch
[packages/kernel.git] / 2.6.1-rc2-NF-osf-20040107.patch
CommitLineData
68329dea 1diff -Nur linux-2.6.1-rc2.org/include/linux/netfilter_ipv4/ipt_osf.h linux-2.6.1-rc2/include/linux/netfilter_ipv4/ipt_osf.h
2--- linux-2.6.1-rc2.org/include/linux/netfilter_ipv4/ipt_osf.h 1970-01-01 01:00:00.000000000 +0100
3+++ linux-2.6.1-rc2/include/linux/netfilter_ipv4/ipt_osf.h 2004-01-07 19:54:12.127377416 +0100
4@@ -0,0 +1,130 @@
5+/*
6+ * ipt_osf.h
7+ *
8+ * Copyright (c) 2003 Evgeniy Polyakov <johnpol@2ka.mipt.ru>
9+ *
10+ *
11+ * This program is free software; you can redistribute it and/or modify
12+ * it under the terms of the GNU General Public License as published by
13+ * the Free Software Foundation; either version 2 of the License, or
14+ * (at your option) any later version.
15+ *
16+ * This program is distributed in the hope that it will be useful,
17+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
18+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19+ * GNU General Public License for more details.
20+ *
21+ * You should have received a copy of the GNU General Public License
22+ * along with this program; if not, write to the Free Software
23+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24+ */
25+
26+#ifndef _IPT_OSF_H
27+#define _IPT_OSF_H
28+
29+#define MAXGENRELEN 32
30+#define MAXDETLEN 64
31+
32+#define IPT_OSF_GENRE 1
33+#define IPT_OSF_SMART 2
34+#define IPT_OSF_LOG 4
35+
36+#define IPT_OSF_LOGLEVEL_ALL 0
37+#define IPT_OSF_LOGLEVEL_FIRST 1
38+
39+#include <linux/list.h>
40+
41+struct ipt_osf_info
42+{
43+ char genre[MAXGENRELEN];
44+ int len;
45+ unsigned long flags;
46+ int loglevel;
47+ int invert; /* UNSUPPORTED */
48+};
49+
50+struct osf_wc
51+{
52+ char wc;
53+ unsigned long val;
54+};
55+
56+/* This struct represents IANA options
57+ * http://www.iana.org/assignments/tcp-parameters
58+ */
59+struct osf_opt
60+{
61+ unsigned char kind;
62+ unsigned char length;
63+ struct osf_wc wc;
64+};
65+
66+#ifdef __KERNEL__
67+
68+struct osf_finger
69+{
70+ struct list_head flist;
71+ struct osf_wc wss;
72+ unsigned char ttl;
73+ unsigned char df;
74+ unsigned long ss;
75+ char genre[MAXGENRELEN];
76+ char version[MAXGENRELEN], subtype[MAXGENRELEN];
77+
78+ /* Not needed, but for consistency with original table from Michal Zalewski */
79+ char details[MAXDETLEN];
80+
81+ int opt_num;
82+ struct osf_opt opt[MAX_IPOPTLEN]; /* In case it is all NOP or EOL */
83+
84+};
85+
86+/* Defines for IANA option kinds */
87+
88+#define OSFOPT_EOL 0 /* End of options */
89+#define OSFOPT_NOP 1 /* NOP */
90+#define OSFOPT_MSS 2 /* Maximum segment size */
91+#define OSFOPT_WSO 3 /* Window scale option */
92+#define OSFOPT_SACKP 4 /* SACK permitted */
93+#define OSFOPT_SACK 5 /* SACK */
94+#define OSFOPT_ECHO 6
95+#define OSFOPT_ECHOREPLY 7
96+#define OSFOPT_TS 8 /* Timestamp option */
97+#define OSFOPT_POCP 9 /* Partial Order Connection Permitted */
98+#define OSFOPT_POSP 10 /* Partial Order Service Profile */
99+/* Others are not used in current OSF */
100+
101+static struct osf_opt IANA_opts[] =
102+{
103+ {0, 1,},
104+ {1, 1,},
105+ {2, 4,},
106+ {3, 3,},
107+ {4, 2,},
108+ {5, 1 ,}, /* SACK length is not defined */
109+ {6, 6,},
110+ {7, 6,},
111+ {8, 10,},
112+ {9, 2,},
113+ {10, 3,},
114+ {11, 1,}, /* CC: Suppose 1 */
115+ {12, 1,}, /* the same */
116+ {13, 1,}, /* and here too */
117+ {14, 3,},
118+ {15, 1,}, /* TCP Alternate Checksum Data. Length is not defined */
119+ {16, 1,},
120+ {17, 1,},
121+ {18, 3,},
122+ {19, 18,},
123+ {20, 1,},
124+ {21, 1,},
125+ {22, 1,},
126+ {23, 1,},
127+ {24, 1,},
128+ {25, 1,},
129+ {26, 1,},
130+};
131+
132+#endif /* __KERNEL__ */
133+
134+#endif /* _IPT_OSF_H */
135diff -Nur linux-2.6.1-rc2.org/net/ipv4/netfilter/ipt_osf.c linux-2.6.1-rc2/net/ipv4/netfilter/ipt_osf.c
136--- linux-2.6.1-rc2.org/net/ipv4/netfilter/ipt_osf.c 1970-01-01 01:00:00.000000000 +0100
137+++ linux-2.6.1-rc2/net/ipv4/netfilter/ipt_osf.c 2004-01-07 19:54:12.128377264 +0100
138@@ -0,0 +1,733 @@
139+/*
140+ * ipt_osf.c
141+ *
142+ * Copyright (c) 2003 Evgeniy Polyakov <johnpol@2ka.mipt.ru>
143+ *
144+ *
145+ * This program is free software; you can redistribute it and/or modify
146+ * it under the terms of the GNU General Public License as published by
147+ * the Free Software Foundation; either version 2 of the License, or
148+ * (at your option) any later version.
149+ *
150+ * This program is distributed in the hope that it will be useful,
151+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
152+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
153+ * GNU General Public License for more details.
154+ *
155+ * You should have received a copy of the GNU General Public License
156+ * along with this program; if not, write to the Free Software
157+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
158+ */
159+
160+/*
161+ * OS fingerprint matching module.
162+ * It simply compares various parameters from SYN packet with
163+ * some hardcoded ones.
164+ *
165+ * Original table was created by Michal Zalewski <lcamtuf@coredump.cx>
166+ * for his p0f.
167+ */
168+
169+#include <linux/config.h>
170+#include <linux/kernel.h>
171+#include <linux/smp.h>
172+#include <linux/module.h>
173+#include <linux/skbuff.h>
174+#include <linux/file.h>
175+#include <linux/ip.h>
176+#include <linux/proc_fs.h>
177+#include <linux/fs.h>
178+#include <linux/slab.h>
179+#include <linux/spinlock.h>
180+#include <linux/ctype.h>
181+#include <linux/list.h>
182+
183+#include <net/sock.h>
184+#include <net/ip.h>
185+
186+#include <linux/netfilter_ipv4/ip_tables.h>
187+
188+#include <linux/netfilter_ipv4/ipt_osf.h>
189+
190+#define OSF_DEBUG
191+
192+#ifdef OSF_DEBUG
193+#define log(x...) printk(KERN_INFO "ipt_osf: " x)
194+#define loga(x...) printk(x)
195+#else
196+#define log(x...) do {} while(0)
197+#define loga(x...) do {} while(0)
198+#endif
199+
200+#define FMATCH_WRONG 0
201+#define FMATCH_OK 1
202+#define FMATCH_OPT_WRONG 2
203+
204+#define OPTDEL ','
205+#define OSFPDEL ':'
206+#define MAXOPTSTRLEN 128
207+#define OSFFLUSH "FLUSH"
208+
209+static rwlock_t osf_lock = RW_LOCK_UNLOCKED;
210+static struct list_head finger_list;
211+
212+static int match(const struct sk_buff *, const struct net_device *, const struct net_device *,
213+ const void *, int, const void *, u_int16_t, int *);
214+static int checkentry(const char *, const struct ipt_ip *, void *,
215+ unsigned int, unsigned int);
216+
217+static struct ipt_match osf_match =
218+{
219+ { NULL, NULL },
220+ "osf",
221+ &match,
222+ &checkentry,
223+ NULL,
224+ THIS_MODULE
225+};
226+
227+static inline int smart_dec(unsigned long flags, unsigned char ip_ttl, unsigned char f_ttl)
228+{
229+ if (flags & IPT_OSF_SMART)
230+ return 1;
231+ else
232+ return (ip_ttl == f_ttl);
233+}
234+
235+static int
236+match(const struct sk_buff *skb,
237+ const struct net_device *in,
238+ const struct net_device *out,
239+ const void *matchinfo,
240+ int offset,
241+ const void *hdr,
242+ u_int16_t datalen,
243+ int *hotdrop)
244+{
245+ struct ipt_osf_info *info = (struct ipt_osf_info *)matchinfo;
246+ struct iphdr *ip = skb->nh.iph;
247+ struct tcphdr *tcp;
248+ int fmatch = FMATCH_WRONG, fcount = 0;
249+ unsigned long totlen, optsize = 0, window;
250+ unsigned char df, *optp = NULL, *_optp = NULL;
251+ char check_WSS = 0;
252+ struct list_head *ent;
253+ struct osf_finger *f;
254+
255+ if (!ip || !info)
256+ return 0;
257+
258+ tcp = (struct tcphdr *)((u_int32_t *)ip + ip->ihl);
259+
260+ if (!tcp->syn)
261+ return 0;
262+ else if (tcp->ack)
263+ return 0;
264+
265+ totlen = ntohs(ip->tot_len);
266+ df = ((ntohs(ip->frag_off) & IP_DF)?1:0);
267+ window = ntohs(tcp->window);
268+
269+ if (tcp->doff*4 > sizeof(struct tcphdr))
270+ {
271+ _optp = optp = (char *)(tcp+1);
272+ optsize = tcp->doff*4 - sizeof(struct tcphdr);
273+ }
274+
275+
276+ /* Actually we can create hash/table of all genres and search
277+ * only in appropriate part, but here is initial variant,
278+ * so will use slow path.
279+ */
280+ read_lock(&osf_lock);
281+ list_for_each(ent, &finger_list)
282+ {
283+ f = list_entry(ent, struct osf_finger, flist);
284+
285+ if (!(info->flags & IPT_OSF_LOG) && strcmp(info->genre, f->genre))
286+ continue;
287+
288+ optp = _optp;
289+ fmatch = FMATCH_WRONG;
290+
291+ if (totlen == f->ss && df == f->df &&
292+ smart_dec(info->flags, ip->ttl, f->ttl))
293+ {
294+ unsigned long foptsize;
295+ int optnum;
296+ unsigned short mss = 0;
297+
298+ check_WSS = 0;
299+
300+ switch (f->wss.wc)
301+ {
302+ case 0: check_WSS = 0; break;
303+ case 'S': check_WSS = 1; break;
304+ case 'T': check_WSS = 2; break;
305+ case '%': check_WSS = 3; break;
306+ default: log("Wrong fingerprint wss.wc=%d, %s - %s\n",
307+ f->wss.wc, f->genre, f->details);
308+ check_WSS = 4;
309+ break;
310+ }
311+ if (check_WSS == 4)
312+ continue;
313+
314+ /* Check options */
315+
316+ foptsize = 0;
317+ for (optnum=0; optnum<f->opt_num; ++optnum)
318+ foptsize += f->opt[optnum].length;
319+
320+
321+ if (foptsize > MAX_IPOPTLEN || optsize > MAX_IPOPTLEN || optsize != foptsize)
322+ continue;
323+
324+ if (!optp)
325+ {
326+ fmatch = FMATCH_OK;
327+ loga("\tYEP : matching without options.\n");
328+ if ((info->flags & IPT_OSF_LOG) &&
329+ info->loglevel == IPT_OSF_LOGLEVEL_FIRST)
330+ break;
331+ else
332+ continue;
333+ }
334+
335+
336+ for (optnum=0; optnum<f->opt_num; ++optnum)
337+ {
338+ if (f->opt[optnum].kind == (*optp))
339+ {
340+ unsigned char len = f->opt[optnum].length;
341+ unsigned char *optend = optp + len;
342+
343+ fmatch = FMATCH_OK;
344+
345+ if (*optp == OSFOPT_MSS) /* MSS */
346+ mss = ntohs(*(unsigned short *)(optp+2));
347+
348+ if (len != 1)
349+ {
350+ /* Skip kind and length fields*/
351+ optp += 2;
352+
353+ if (f->opt[optnum].wc.wc != 0)
354+ {
355+ unsigned long tmp = 0;
356+
357+ /* Hmmm... It looks a bit ugly. :) */
358+ memcpy(&tmp, &f->opt[optnum].wc.val,
359+ (len > sizeof(unsigned long)?
360+ sizeof(unsigned long):len));
361+
362+ tmp = ntohl(tmp);
363+ if (tmp != f->opt[optnum].wc.val)
364+ fmatch = FMATCH_OPT_WRONG;
365+ }
366+ }
367+
368+ optp = optend;
369+ }
370+ else
371+ fmatch = FMATCH_OPT_WRONG;
372+
373+ if (fmatch != FMATCH_OK)
374+ break;
375+ }
376+
377+ if (fmatch != FMATCH_OPT_WRONG)
378+ {
379+ fmatch = FMATCH_WRONG;
380+
381+ switch (check_WSS)
382+ {
383+ case 0:
384+ if (window == f->wss.val)
385+ fmatch = FMATCH_OK;
386+ break;
387+ case 1: /* MSS */
388+ if (window == f->wss.val*mss)
389+ fmatch = FMATCH_OK;
390+ break;
391+ case 2: /* MTU */
392+ if (window == f->wss.val*(mss+40))
393+ fmatch = FMATCH_OK;
394+ break;
395+ case 3: /* MOD */
396+ if (window % f->wss.val == 0)
397+ fmatch = FMATCH_OK;
398+ break;
399+ }
400+ }
401+
402+
403+ if (fmatch == FMATCH_OK)
404+ {
405+ fcount++;
406+ log("%s [%s]: %u.%u.%u.%u:%u -> %u.%u.%u.%u:%u\n",
407+ f->genre, f->details,
408+ NIPQUAD(ip->saddr), ntohs(tcp->source),
409+ NIPQUAD(ip->daddr), ntohs(tcp->dest));
410+ if ((info->flags & IPT_OSF_LOG) &&
411+ info->loglevel == IPT_OSF_LOGLEVEL_FIRST)
412+ break;
413+ }
414+ }
415+ }
416+ if (!fcount && (info->flags & IPT_OSF_LOG))
417+ {
418+ log("Unknown: %lu:%d:%d:%lu:", window, ip->ttl, df, totlen);
419+ if (optp)
420+ {
421+ unsigned char opt[4 * 15 - sizeof(struct tcphdr)];
422+ unsigned int i, optsize;
423+
424+ optsize = tcp->doff * 4 - sizeof(struct tcphdr);
425+ if (skb_copy_bits(skb, ip->ihl*4 + sizeof(struct tcphdr),
426+ opt, optsize) < 0)
427+ loga("TRUNCATED");
428+ else
429+ for (i = 0; i < optsize; i++)
430+ loga("%02X", opt[i]);
431+
432+ }
433+ loga(" %u.%u.%u.%u:%u -> %u.%u.%u.%u:%u\n",
434+ NIPQUAD(ip->saddr), ntohs(tcp->source),
435+ NIPQUAD(ip->daddr), ntohs(tcp->dest));
436+ }
437+ read_unlock(&osf_lock);
438+
439+ return (fmatch == FMATCH_OK)?1:0;
440+}
441+
442+static int
443+checkentry(const char *tablename,
444+ const struct ipt_ip *ip,
445+ void *matchinfo,
446+ unsigned int matchsize,
447+ unsigned int hook_mask)
448+{
449+ if (matchsize != IPT_ALIGN(sizeof(struct ipt_osf_info)))
450+ return 0;
451+ if (ip->proto != IPPROTO_TCP)
452+ return 0;
453+
454+ return 1;
455+}
456+
457+static char * osf_strchr(char *ptr, char c)
458+{
459+ char *tmp;
460+
461+ tmp = strchr(ptr, c);
462+
463+ while (tmp && tmp+1 && isspace(*(tmp+1)))
464+ tmp++;
465+
466+ return tmp;
467+}
468+
469+static struct osf_finger * finger_alloc(void)
470+{
471+ struct osf_finger *f;
472+
473+ f = kmalloc(sizeof(struct osf_finger), GFP_KERNEL);
474+ if (f)
475+ memset(f, 0, sizeof(struct osf_finger));
476+
477+ return f;
478+}
479+
480+static void finger_free(struct osf_finger *f)
481+{
482+ memset(f, 0, sizeof(struct osf_finger));
483+ kfree(f);
484+}
485+
486+
487+static void osf_parse_opt(struct osf_opt *opt, int *optnum, char *obuf, int olen)
488+{
489+ int i, op;
490+ char *ptr, wc;
491+ unsigned long val;
492+
493+ ptr = &obuf[0];
494+ i = 0;
495+ while (ptr != NULL && i < olen)
496+ {
497+ val = 0;
498+ op = 0;
499+ wc = 0;
500+ switch (obuf[i])
501+ {
502+ case 'N':
503+ op = OSFOPT_NOP;
504+ ptr = osf_strchr(&obuf[i], OPTDEL);
505+ if (ptr)
506+ {
507+ *ptr = '\0';
508+ ptr++;
509+ i += (int)(ptr-&obuf[i]);
510+
511+ }
512+ else
513+ i++;
514+ break;
515+ case 'S':
516+ op = OSFOPT_SACKP;
517+ ptr = osf_strchr(&obuf[i], OPTDEL);
518+ if (ptr)
519+ {
520+ *ptr = '\0';
521+ ptr++;
522+ i += (int)(ptr-&obuf[i]);
523+
524+ }
525+ else
526+ i++;
527+ break;
528+ case 'T':
529+ op = OSFOPT_TS;
530+ ptr = osf_strchr(&obuf[i], OPTDEL);
531+ if (ptr)
532+ {
533+ *ptr = '\0';
534+ ptr++;
535+ i += (int)(ptr-&obuf[i]);
536+
537+ }
538+ else
539+ i++;
540+ break;
541+ case 'W':
542+ op = OSFOPT_WSO;
543+ ptr = osf_strchr(&obuf[i], OPTDEL);
544+ if (ptr)
545+ {
546+ switch (obuf[i+1])
547+ {
548+ case '%': wc = '%'; break;
549+ case 'S': wc = 'S'; break;
550+ case 'T': wc = 'T'; break;
551+ default: wc = 0; break;
552+ }
553+
554+ *ptr = '\0';
555+ ptr++;
556+ if (wc)
557+ val = simple_strtoul(&obuf[i+2], NULL, 10);
558+ else
559+ val = simple_strtoul(&obuf[i+1], NULL, 10);
560+ i += (int)(ptr-&obuf[i]);
561+
562+ }
563+ else
564+ i++;
565+ break;
566+ case 'M':
567+ op = OSFOPT_MSS;
568+ ptr = osf_strchr(&obuf[i], OPTDEL);
569+ if (ptr)
570+ {
571+ if (obuf[i+1] == '%')
572+ wc = '%';
573+ *ptr = '\0';
574+ ptr++;
575+ if (wc)
576+ val = simple_strtoul(&obuf[i+2], NULL, 10);
577+ else
578+ val = simple_strtoul(&obuf[i+1], NULL, 10);
579+ i += (int)(ptr-&obuf[i]);
580+
581+ }
582+ else
583+ i++;
584+ break;
585+ case 'E':
586+ op = OSFOPT_EOL;
587+ ptr = osf_strchr(&obuf[i], OPTDEL);
588+ if (ptr)
589+ {
590+ *ptr = '\0';
591+ ptr++;
592+ i += (int)(ptr-&obuf[i]);
593+
594+ }
595+ else
596+ i++;
597+ break;
598+ default:
599+ ptr = osf_strchr(&obuf[i], OPTDEL);
600+ if (ptr)
601+ {
602+ ptr++;
603+ i += (int)(ptr-&obuf[i]);
604+
605+ }
606+ else
607+ i++;
608+ break;
609+ }
610+
611+ opt[*optnum].kind = IANA_opts[op].kind;
612+ opt[*optnum].length = IANA_opts[op].length;
613+ opt[*optnum].wc.wc = wc;
614+ opt[*optnum].wc.val = val;
615+
616+ (*optnum)++;
617+ }
618+}
619+
620+static int osf_proc_read(char *buf, char **start, off_t off, int count, int *eof, void *data)
621+{
622+ struct list_head *ent;
623+ struct osf_finger *f = NULL;
624+ int i;
625+
626+ *eof = 1;
627+ count = 0;
628+
629+ read_lock_bh(&osf_lock);
630+ list_for_each(ent, &finger_list)
631+ {
632+ f = list_entry(ent, struct osf_finger, flist);
633+
634+ log("%s [%s]", f->genre, f->details);
635+
636+ count += sprintf(buf+count, "%s - %s[%s] : %s",
637+ f->genre, f->version,
638+ f->subtype, f->details);
639+
640+ if (f->opt_num)
641+ {
642+ loga(" OPT: ");
643+ //count += sprintf(buf+count, " OPT: ");
644+ for (i=0; i<f->opt_num; ++i)
645+ {
646+ //count += sprintf(buf+count, "%d.%c%lu; ",
647+ // f->opt[i].kind, (f->opt[i].wc.wc)?f->opt[i].wc.wc:' ', f->opt[i].wc.val);
648+ loga("%d.%c%lu; ",
649+ f->opt[i].kind, (f->opt[i].wc.wc)?f->opt[i].wc.wc:' ', f->opt[i].wc.val);
650+ }
651+ }
652+ loga("\n");
653+ count += sprintf(buf+count, "\n");
654+ }
655+ read_unlock_bh(&osf_lock);
656+
657+ return count;
658+}
659+
660+static int osf_proc_write(struct file *file, const char *buffer, unsigned long count, void *data)
661+{
662+ int cnt;
663+ unsigned long i;
664+ char obuf[MAXOPTSTRLEN];
665+ struct osf_finger *finger;
666+ struct list_head *ent, *n;
667+
668+ char *pbeg, *pend;
669+
670+ if (count == strlen(OSFFLUSH) && !strncmp(buffer, OSFFLUSH, strlen(OSFFLUSH)))
671+ {
672+ int i = 0;
673+ write_lock_bh(&osf_lock);
674+ list_for_each_safe(ent, n, &finger_list)
675+ {
676+ i++;
677+ finger = list_entry(ent, struct osf_finger, flist);
678+ list_del(&finger->flist);
679+ finger_free(finger);
680+ }
681+ write_unlock_bh(&osf_lock);
682+
683+ log("Flushed %d entries.\n", i);
684+
685+ return count;
686+ }
687+
688+
689+ cnt = 0;
690+ for (i=0; i<count && buffer[i] != '\0'; ++i)
691+ if (buffer[i] == ':')
692+ cnt++;
693+
694+ if (cnt != 8 || i != count)
695+ {
696+ log("Wrong input line cnt=%d[8], len=%lu[%lu]\n",
697+ cnt, i, count);
698+ return count;
699+ }
700+
701+ memset(obuf, 0, sizeof(obuf));
702+
703+ finger = finger_alloc();
704+ if (!finger)
705+ {
706+ log("Failed to allocate new fingerprint entry.\n");
707+ return -ENOMEM;
708+ }
709+
710+ pbeg = (char *)buffer;
711+ pend = osf_strchr(pbeg, OSFPDEL);
712+ if (pend)
713+ {
714+ *pend = '\0';
715+ if (pbeg[0] == 'S')
716+ {
717+ finger->wss.wc = 'S';
718+ if (pbeg[1] == '%')
719+ finger->wss.val = simple_strtoul(pbeg+2, NULL, 10);
720+ else if (pbeg[1] == '*')
721+ finger->wss.val = 0;
722+ else
723+ finger->wss.val = simple_strtoul(pbeg+1, NULL, 10);
724+ }
725+ else if (pbeg[0] == 'T')
726+ {
727+ finger->wss.wc = 'T';
728+ if (pbeg[1] == '%')
729+ finger->wss.val = simple_strtoul(pbeg+2, NULL, 10);
730+ else if (pbeg[1] == '*')
731+ finger->wss.val = 0;
732+ else
733+ finger->wss.val = simple_strtoul(pbeg+1, NULL, 10);
734+ }
735+ if (isdigit(pbeg[0]))
736+ {
737+ finger->wss.wc = 0;
738+ finger->wss.val = simple_strtoul(pbeg, NULL, 10);
739+ }
740+
741+ pbeg = pend+1;
742+ }
743+ pend = osf_strchr(pbeg, OSFPDEL);
744+ if (pend)
745+ {
746+ *pend = '\0';
747+ finger->ttl = simple_strtoul(pbeg, NULL, 10);
748+ pbeg = pend+1;
749+ }
750+ pend = osf_strchr(pbeg, OSFPDEL);
751+ if (pend)
752+ {
753+ *pend = '\0';
754+ finger->df = simple_strtoul(pbeg, NULL, 10);
755+ pbeg = pend+1;
756+ }
757+ pend = osf_strchr(pbeg, OSFPDEL);
758+ if (pend)
759+ {
760+ *pend = '\0';
761+ finger->ss = simple_strtoul(pbeg, NULL, 10);
762+ pbeg = pend+1;
763+ }
764+
765+ pend = osf_strchr(pbeg, OSFPDEL);
766+ if (pend)
767+ {
768+ *pend = '\0';
769+ cnt = snprintf(obuf, sizeof(obuf), "%s", pbeg);
770+ pbeg = pend+1;
771+ }
772+
773+ pend = osf_strchr(pbeg, OSFPDEL);
774+ if (pend)
775+ {
776+ *pend = '\0';
777+ if (pbeg[0] == '@' || pbeg[0] == '*')
778+ cnt = snprintf(finger->genre, sizeof(finger->genre), "%s", pbeg+1);
779+ else
780+ cnt = snprintf(finger->genre, sizeof(finger->genre), "%s", pbeg);
781+ pbeg = pend+1;
782+ }
783+
784+ pend = osf_strchr(pbeg, OSFPDEL);
785+ if (pend)
786+ {
787+ *pend = '\0';
788+ cnt = snprintf(finger->version, sizeof(finger->version), "%s", pbeg);
789+ pbeg = pend+1;
790+ }
791+
792+ pend = osf_strchr(pbeg, OSFPDEL);
793+ if (pend)
794+ {
795+ *pend = '\0';
796+ cnt = snprintf(finger->subtype, sizeof(finger->subtype), "%s", pbeg);
797+ pbeg = pend+1;
798+ }
799+
800+ cnt = snprintf(finger->details,
801+ ((count - (pbeg - buffer)+1) > MAXDETLEN)?MAXDETLEN:(count - (pbeg - buffer)+1),
802+ "%s", pbeg);
803+
804+ log("%s - %s[%s] : %s\n",
805+ finger->genre, finger->version,
806+ finger->subtype, finger->details);
807+
808+ osf_parse_opt(finger->opt, &finger->opt_num, obuf, sizeof(obuf));
809+
810+
811+ write_lock_bh(&osf_lock);
812+ list_add_tail(&finger->flist, &finger_list);
813+ write_unlock_bh(&osf_lock);
814+
815+ return count;
816+}
817+
818+static int __init osf_init(void)
819+{
820+ int err;
821+ struct proc_dir_entry *p;
822+
823+ log("Startng OS fingerprint matching module.\n");
824+
825+ INIT_LIST_HEAD(&finger_list);
826+
827+ err = ipt_register_match(&osf_match);
828+ if (err)
829+ {
830+ log("Failed to register OS fingerprint matching module.\n");
831+ return -ENXIO;
832+ }
833+
834+ p = create_proc_entry("sys/net/ipv4/osf", S_IFREG | 0644, NULL);
835+ if (!p)
836+ {
837+ ipt_unregister_match(&osf_match);
838+ return -ENXIO;
839+ }
840+
841+ p->write_proc = osf_proc_write;
842+ p->read_proc = osf_proc_read;
843+
844+ return 0;
845+}
846+
847+static void __exit osf_fini(void)
848+{
849+ struct list_head *ent, *n;
850+ struct osf_finger *f;
851+
852+ remove_proc_entry("sys/net/ipv4/osf", NULL);
853+ ipt_unregister_match(&osf_match);
854+
855+ list_for_each_safe(ent, n, &finger_list)
856+ {
857+ f = list_entry(ent, struct osf_finger, flist);
858+ list_del(&f->flist);
859+ finger_free(f);
860+ }
861+
862+ log("OS fingerprint matching module finished.\n");
863+}
864+
865+module_init(osf_init);
866+module_exit(osf_fini);
867+
868+MODULE_LICENSE("GPL");
869+MODULE_AUTHOR("Evgeniy Polyakov <johnpol@2ka.mipt.ru>");
870+MODULE_DESCRIPTION("Passive OS fingerprint matching.");
871+
872diff -Nur linux-2.6.1-rc2.org/net/ipv4/netfilter/Kconfig linux-2.6.1-rc2/net/ipv4/netfilter/Kconfig
873--- linux-2.6.1-rc2.org/net/ipv4/netfilter/Kconfig 2004-01-07 19:52:02.608067344 +0100
874+++ linux-2.6.1-rc2/net/ipv4/netfilter/Kconfig 2004-01-07 19:54:12.130376960 +0100
875@@ -609,5 +609,54 @@
876 lengths.
877 Details and examples are in the kernel module source.
878
879+config IP_NF_MATCH_OSF
880+ tristate 'OSF match support'
881+ depends on IP_NF_IPTABLES
882+ help
883+ The idea of passive OS fingerprint matching exists for quite a long time,
884+ but was created as extension fo OpenBSD pf only some weeks ago.
885+ Original idea was lurked in some OpenBSD mailing list (thanks
886+ grange@open...) and than adopted for Linux netfilter in form of this code.
887+
888+ Original table was created by Michal Zalewski <lcamtuf@coredump.cx> for
889+ his excellent p0f and than changed a bit for more convenience.
890+
891+ This module compares some data(WS, MSS, options and it's order, ttl,
892+ df and others) from first SYN packet (actually from packets with SYN
893+ bit set) with hardcoded in fingers[] table ones.
894+
895+ Example: (Of course this only an example, do not get inspired by this)
896+
897+ # iptables -N LINUX
898+ # iptables -A LINUX -j LOG --log-prefix "Linux"
899+
900+ # iptables -A INPUT -p tcp -m osf --genre Linux -j LINUX
901+ # iptables -A INPUT -p tcp -m osf --genre FreeBSD -j REJECT
902+
903+ NOTE: -p tcp is obviously required as it is a TCP match.
904+
905+ OSF also has:
906+ --log 1/0.
907+ If present, OSF will log determined genres even if they don't match
908+ desired one.
909+ 0 - log all determined entries,
910+ 1 - only first one.
911+
912+ Example:
913+ #iptables -I INPUT -j ACCEPT -p tcp -m osf --genre Linux --log 1 --smart
914+
915+ In syslog you find something like this:
916+ ipt_osf: Windows [Windows XP Pro SP1, 2000 SP3]: 11.22.33.55:4024 -> 11.22.33.44:139
917+ ipt_osf: Unknown: 16384:106:1:48:020405B401010402 44.33.22.11:1239 -> 11.22.33.44:80
918+
919+ --smart
920+ if present, OSF will use some smartness to determine remote OS.
921+ Now only not use TTL( with it far remote machines can be determined).
922+
923+ Fingerprints can be loaded through /proc/sys/net/ipv4/osf file.
924+ Only one fingerprint per open/close.
925+
926+ Fingerprints can be downloaded from http://www.openbsd.org/cgi-bin/cvsweb/src/etc/pf.os
927+
928 endmenu
929
930diff -Nur linux-2.6.1-rc2.org/net/ipv4/netfilter/Makefile linux-2.6.1-rc2/net/ipv4/netfilter/Makefile
931--- linux-2.6.1-rc2.org/net/ipv4/netfilter/Makefile 2004-01-07 19:52:02.608067344 +0100
932+++ linux-2.6.1-rc2/net/ipv4/netfilter/Makefile 2004-01-07 19:54:12.131376808 +0100
933@@ -51,6 +51,9 @@
934 obj-$(CONFIG_IP_NF_MATCH_OWNER) += ipt_owner.o
935 obj-$(CONFIG_IP_NF_MATCH_TOS) += ipt_tos.o
936
937+obj-$(CONFIG_IP_NF_MATCH_OSF) += ipt_osf.o
938+
939+
940 obj-$(CONFIG_IP_NF_MATCH_TIME) += ipt_time.o
941
942
This page took 0.203275 seconds and 4 git commands to generate.