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(+)
7 diff -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
14 + * Copyright (c) 2003 Evgeniy Polyakov <johnpol@2ka.mipt.ru>
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.
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.
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
35 +#define MAXGENRELEN 32
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
44 +#define IPT_OSF_LOGLEVEL_ALL 0
45 +#define IPT_OSF_LOGLEVEL_FIRST 1
48 +#include <netinet/ip.h>
49 +#include <netinet/tcp.h>
53 + struct list_head *prev, *next;
59 + char genre[MAXGENRELEN];
61 + unsigned long flags;
63 + int invert; /* UNSUPPORTED */
72 +/* This struct represents IANA options
73 + * http://www.iana.org/assignments/tcp-parameters
78 + unsigned char length;
84 + struct list_head flist;
89 + unsigned char genre[MAXGENRELEN];
90 + unsigned char version[MAXGENRELEN], subtype[MAXGENRELEN];
92 + /* Not needed, but for consistency with original table from Michal Zalewski */
93 + unsigned char details[MAXDETLEN];
96 + struct osf_opt opt[MAX_IPOPTLEN]; /* In case it is all NOP or EOL */
100 +struct ipt_osf_nlmsg
102 + struct osf_finger f;
109 +#include <linux/list.h>
110 +#include <net/tcp.h>
113 +/* Defines for IANA option kinds */
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 */
128 +static struct osf_opt IANA_opts[] =
135 + {5, 1 ,}, /* SACK length is not defined */
141 + {11, 1,}, /* CC: Suppose 1 */
142 + {12, 1,}, /* the same */
143 + {13, 1,}, /* and here too */
145 + {15, 1,}, /* TCP Alternate Checksum Data. Length is not defined */
159 +#endif /* __KERNEL__ */
161 +#endif /* _IPT_OSF_H */
162 diff -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
166 Allows altering the ARP packet payload: source and destination
167 hardware and network addresses.
169 +config IP_NF_MATCH_OSF
170 + tristate 'OSF match support'
171 + depends on IP_NF_IPTABLES
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.
179 + Original table was created by Michal Zalewski <lcamtuf@coredump.cx> for
180 + his excellent p0f and than changed a bit for more convenience.
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.
186 + If you say Y here, try iptables -m osf --help for more information.
188 + If you want to compile it as a module, say M here and read
189 + Documentation/modules.txt. If unsure, say `N'.
193 diff -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
197 +obj-$(CONFIG_IP_NF_MATCH_OSF) += ipt_osf.o
198 diff -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
205 + * Copyright (c) 2003-2005 Evgeniy Polyakov <johnpol@2ka.mipt.ru>
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.
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.
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
224 + * OS fingerprint matching module.
225 + * It simply compares various parameters from SYN packet with
226 + * some hardcoded ones.
228 + * Original table was created by Michal Zalewski <lcamtuf@coredump.cx>
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>
251 +#include <linux/tcp.h>
253 +#include <linux/netfilter_ipv4/ip_tables.h>
255 +#include <linux/netfilter_ipv4/ipt_osf.h>
260 +#define log(x...) printk(KERN_INFO "ipt_osf: " x)
261 +#define loga(x...) printk(x)
263 +#define log(x...) do {} while(0)
264 +#define loga(x...) do {} while(0)
267 +#define FMATCH_WRONG 0
269 +#define FMATCH_OPT_WRONG 2
273 +#define MAXOPTSTRLEN 128
274 +#define OSFFLUSH "FLUSH"
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,
282 +static int checkentry(const char *, const struct ipt_ip *, void *,
283 + unsigned int, unsigned int);
285 +static unsigned long seq, ipt_osf_groups = 1;
286 +static struct sock *nts;
288 +static struct ipt_match osf_match = {
291 + .checkentry = &checkentry,
296 +#ifdef CONFIG_CONNECTOR
297 +#include <linux/connector.h>
300 + * They should live in connector.h.
302 +#define CN_IDX_OSF 0x0001
303 +#define CN_VAL_OSF 0x0000
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};
309 +static void ipt_osf_send_connector(struct osf_finger *f, const struct sk_buff *sk)
312 + struct ipt_osf_nlmsg *data;
314 + m = (struct cn_msg *)osf_finger_buf;
315 + data = (struct ipt_osf_nlmsg *)(m+1);
317 + memcpy(&m->id, &osf_id, sizeof(m->id));
318 + m->seq = osf_seq++;
320 + m->len = sizeof(*data);
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));
326 + cn_netlink_send(m, m->id.idx, GFP_ATOMIC);
329 +static void ipt_osf_send_connector(struct osf_finger *f, const struct sk_buff *sk)
334 +static void ipt_osf_nlsend(struct osf_finger *f, const struct sk_buff *sk)
337 + struct sk_buff *skb;
338 + struct ipt_osf_nlmsg *data;
339 + struct nlmsghdr *nlh;
344 + size = NLMSG_SPACE(sizeof(struct ipt_osf_nlmsg));
346 + skb = alloc_skb(size, GFP_ATOMIC);
348 + log("skb_alloc() failed.\n");
352 + nlh = NLMSG_PUT(skb, 0, seq++, NLMSG_DONE, size - sizeof(*nlh));
354 + data = (struct ipt_osf_nlmsg *)NLMSG_DATA(nlh);
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));
360 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14)
361 + NETLINK_CB(skb).dst_groups = ipt_osf_groups;
363 + NETLINK_CB(skb).dst_group = ipt_osf_groups;
365 + netlink_broadcast(nts, skb, 0, ipt_osf_groups, GFP_ATOMIC);
371 +static inline int smart_dec(const struct sk_buff *skb, unsigned long flags, unsigned char f_ttl)
373 + struct iphdr *ip = skb->nh.iph;
375 + if (flags & IPT_OSF_SMART) {
376 + struct in_device *in_dev = in_dev_get(skb->dev);
379 + if (inet_ifa_match(ip->saddr, ifa)) {
380 + in_dev_put(in_dev);
381 + return (ip->ttl == f_ttl);
384 + endfor_ifa(in_dev);
386 + in_dev_put(in_dev);
387 + return (ip->ttl <= f_ttl);
390 + return (ip->ttl == f_ttl);
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,
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;
414 + ip = skb_header_pointer(skb, off, sizeof(_iph), &_iph);
418 + tcp = skb_header_pointer(skb, off + ip->ihl * 4, sizeof(_tcph), &_tcph);
425 + totlen = ntohs(ip->tot_len);
426 + df = ((ntohs(ip->frag_off) & IP_DF)?1:0);
427 + window = ntohs(tcp->window);
429 + if (tcp->doff*4 > sizeof(struct tcphdr)) {
430 + optsize = tcp->doff*4 - sizeof(struct tcphdr);
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);
438 + _optp = optp = skb_header_pointer(skb, off + ip->ihl*4 + sizeof(_tcph), optsize, opts);
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.
445 + read_lock(&osf_lock);
446 + list_for_each_entry(f, &finger_list, flist) {
448 + if (!(info->flags & IPT_OSF_LOG) && strcmp(info->genre, f->genre))
452 + fmatch = FMATCH_WRONG;
454 + if (totlen == f->ss && df == f->df &&
455 + smart_dec(skb, info->flags, f->ttl)) {
456 + unsigned long foptsize;
458 + unsigned short mss = 0;
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);
472 + if (check_WSS == 4)
475 + /* Check options */
478 + for (optnum=0; optnum<f->opt_num; ++optnum)
479 + foptsize += f->opt[optnum].length;
482 + if (foptsize > MAX_IPOPTLEN || optsize > MAX_IPOPTLEN || optsize != foptsize)
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)
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;
501 + fmatch = FMATCH_OK;
506 + mss = ntohs(*(unsigned short *)(optp+2));
519 + /* Skip kind and length fields*/
522 + if (f->opt[optnum].wc.val != 0) {
523 + unsigned long tmp = 0;
525 + /* Hmmm... It looks a bit ugly. :) */
527 + (len > sizeof(unsigned long)?
528 + sizeof(unsigned long):len));
529 + /* 2 + 2: optlen(2 bytes) +
530 + * kind(1 byte) + length(1 byte) */
536 + if (f->opt[optnum].wc.wc == '%') {
537 + if ((tmp % f->opt[optnum].wc.val) != 0)
538 + fmatch = FMATCH_OPT_WRONG;
540 + else if (tmp != f->opt[optnum].wc.val)
541 + fmatch = FMATCH_OPT_WRONG;
547 + fmatch = FMATCH_OPT_WRONG;
549 + if (fmatch != FMATCH_OK)
553 + if (fmatch != FMATCH_OPT_WRONG) {
554 + fmatch = FMATCH_WRONG;
556 + switch (check_WSS) {
558 + if (f->wss.val == 0 || window == f->wss.val)
559 + fmatch = FMATCH_OK;
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;
569 + if (window == f->wss.val*(mss+40) ||
570 + window == f->wss.val*(SMART_MSS+40))
571 + fmatch = FMATCH_OK;
574 + if ((window % f->wss.val) == 0)
575 + fmatch = FMATCH_OK;
581 + if (fmatch == FMATCH_OK) {
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),
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);
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);
599 + if ((info->flags & IPT_OSF_LOG) &&
600 + info->loglevel == IPT_OSF_LOGLEVEL_FIRST)
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;
610 + memset(&fg, 0, sizeof(fg));
612 + if ((info->flags & IPT_OSF_LOG))
613 + log("Unknown: %lu:%d:%d:%lu:", window, ip->ttl, df, totlen);
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)
620 + if (info->flags & IPT_OSF_NETLINK)
621 + strcpy(fg.details, "TRUNCATED");
623 + for (i = 0; i < optsize; i++) {
624 + if (info->flags & IPT_OSF_LOG)
625 + loga("%02X", opt[i]);
627 + if (info->flags & IPT_OSF_NETLINK)
628 + memcpy(fg.details, opt, MAXDETLEN);
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));
636 + if (info->flags & (IPT_OSF_NETLINK | IPT_OSF_CONNECTOR)) {
637 + fg.wss.val = window;
641 + strncpy(fg.genre, "Unknown", MAXGENRELEN);
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);
652 + read_unlock(&osf_lock);
655 + fmatch = FMATCH_OK;
657 + return (fmatch == FMATCH_OK)?1:0;
661 +checkentry(const char *tablename,
662 + const struct ipt_ip *ip,
664 + unsigned int matchsize,
665 + unsigned int hook_mask)
667 + if (matchsize != IPT_ALIGN(sizeof(struct ipt_osf_info)))
669 + if (ip->proto != IPPROTO_TCP)
675 +static char * osf_strchr(char *ptr, char c)
679 + tmp = strchr(ptr, c);
681 + while (tmp && tmp+1 && isspace(*(tmp+1)))
687 +static struct osf_finger * finger_alloc(void)
689 + struct osf_finger *f;
691 + f = kmalloc(sizeof(struct osf_finger), GFP_KERNEL);
693 + memset(f, 0, sizeof(struct osf_finger));
698 +static void finger_free(struct osf_finger *f)
700 + memset(f, 0, sizeof(struct osf_finger));
705 +static void osf_parse_opt(struct osf_opt *opt, int *optnum, char *obuf, int olen)
713 + while (ptr != NULL && i < olen) {
720 + ptr = osf_strchr(&obuf[i], OPTDEL);
724 + i += (int)(ptr-&obuf[i]);
731 + ptr = osf_strchr(&obuf[i], OPTDEL);
735 + i += (int)(ptr-&obuf[i]);
743 + ptr = osf_strchr(&obuf[i], OPTDEL);
747 + i += (int)(ptr-&obuf[i]);
754 + ptr = osf_strchr(&obuf[i], OPTDEL);
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;
766 + val = simple_strtoul(&obuf[i+2], NULL, 10);
768 + val = simple_strtoul(&obuf[i+1], NULL, 10);
769 + i += (int)(ptr-&obuf[i]);
776 + ptr = osf_strchr(&obuf[i], OPTDEL);
778 + if (obuf[i+1] == '%')
783 + val = simple_strtoul(&obuf[i+2], NULL, 10);
785 + val = simple_strtoul(&obuf[i+1], NULL, 10);
786 + i += (int)(ptr-&obuf[i]);
793 + ptr = osf_strchr(&obuf[i], OPTDEL);
797 + i += (int)(ptr-&obuf[i]);
803 + ptr = osf_strchr(&obuf[i], OPTDEL);
806 + i += (int)(ptr-&obuf[i]);
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;
822 +static int osf_proc_read(char *buf, char **start, off_t off, int count, int *eof, void *data)
824 + struct osf_finger *f = NULL;
825 + int i, __count, err;
831 + read_lock_bh(&osf_lock);
832 + list_for_each_entry(f, &finger_list, flist) {
833 + log("%s [%s]", f->genre, f->details);
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)
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);
849 + f->opt[i].kind, (f->opt[i].wc.wc)?f->opt[i].wc.wc:' ', f->opt[i].wc.val);
853 + err = snprintf(buf+count, __count-count, "\n");
854 + if (err == 0 || __count <= count + err)
859 + read_unlock_bh(&osf_lock);
864 +static int osf_proc_write(struct file *file, const char *buffer, unsigned long count, void *data)
868 + char obuf[MAXOPTSTRLEN];
869 + struct osf_finger *finger, *n;
873 + if (count == strlen(OSFFLUSH) && !strncmp(buffer, OSFFLUSH, strlen(OSFFLUSH))) {
875 + write_lock_bh(&osf_lock);
876 + list_for_each_entry_safe(finger, n, &finger_list, flist) {
878 + list_del(&finger->flist);
879 + finger_free(finger);
881 + write_unlock_bh(&osf_lock);
883 + log("Flushed %d entries.\n", i);
890 + for (i=0; i<count && buffer[i] != '\0'; ++i)
891 + if (buffer[i] == ':')
894 + if (cnt != 8 || i != count) {
895 + log("Wrong input line cnt=%d[8], len=%lu[%lu]\n",
900 + memset(obuf, 0, sizeof(obuf));
902 + finger = finger_alloc();
904 + log("Failed to allocate new fingerprint entry.\n");
908 + pbeg = (char *)buffer;
909 + pend = osf_strchr(pbeg, OSFPDEL);
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;
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;
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);
938 + pend = osf_strchr(pbeg, OSFPDEL);
941 + finger->ttl = simple_strtoul(pbeg, NULL, 10);
944 + pend = osf_strchr(pbeg, OSFPDEL);
947 + finger->df = simple_strtoul(pbeg, NULL, 10);
950 + pend = osf_strchr(pbeg, OSFPDEL);
953 + finger->ss = simple_strtoul(pbeg, NULL, 10);
957 + pend = osf_strchr(pbeg, OSFPDEL);
960 + cnt = snprintf(obuf, sizeof(obuf), "%s", pbeg);
964 + pend = osf_strchr(pbeg, OSFPDEL);
967 + if (pbeg[0] == '@' || pbeg[0] == '*')
968 + cnt = snprintf(finger->genre, sizeof(finger->genre), "%s", pbeg+1);
970 + cnt = snprintf(finger->genre, sizeof(finger->genre), "%s", pbeg);
974 + pend = osf_strchr(pbeg, OSFPDEL);
977 + cnt = snprintf(finger->version, sizeof(finger->version), "%s", pbeg);
981 + pend = osf_strchr(pbeg, OSFPDEL);
984 + cnt = snprintf(finger->subtype, sizeof(finger->subtype), "%s", pbeg);
988 + cnt = snprintf(finger->details,
989 + ((count - (pbeg - buffer)+1) > MAXDETLEN)?MAXDETLEN:(count - (pbeg - buffer)+1),
992 + log("%s - %s[%s] : %s\n",
993 + finger->genre, finger->version,
994 + finger->subtype, finger->details);
996 + osf_parse_opt(finger->opt, &finger->opt_num, obuf, sizeof(obuf));
999 + write_lock_bh(&osf_lock);
1000 + list_add_tail(&finger->flist, &finger_list);
1001 + write_unlock_bh(&osf_lock);
1006 +static int __devinit osf_init(void)
1009 + struct proc_dir_entry *p;
1011 + log("Startng OS fingerprint matching module.\n");
1013 + INIT_LIST_HEAD(&finger_list);
1015 + err = ipt_register_match(&osf_match);
1017 + log("Failed to register OS fingerprint matching module.\n");
1021 + p = create_proc_entry("sys/net/ipv4/osf", S_IFREG | 0644, NULL);
1023 + ipt_unregister_match(&osf_match);
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);
1032 + nts = netlink_kernel_create(NETLINK_NFLOG, 1, NULL, THIS_MODULE);
1035 + log("netlink_kernel_create() failed\n");
1041 +static void __devexit osf_fini(void)
1043 + struct osf_finger *f, *n;
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);
1050 + list_for_each_entry_safe(f, n, &finger_list, flist) {
1051 + list_del(&f->flist);
1055 + log("OS fingerprint matching module finished.\n");
1058 +module_init(osf_init);
1059 +module_exit(osf_fini);
1061 +MODULE_LICENSE("GPL");
1062 +MODULE_AUTHOR("Evgeniy Polyakov <johnpol@2ka.mipt.ru>");
1063 +MODULE_DESCRIPTION("Passive OS fingerprint matching.");