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