]> git.pld-linux.org Git - packages/kernel.git/blob - pom-ng-osf-20060504.patch
- backported security patches from 2.6.16.57-rc1 (resolves
[packages/kernel.git] / pom-ng-osf-20060504.patch
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
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
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 */
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
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  
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
196 @@ -0,0 +0,1 @@
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
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.104693 seconds and 3 git commands to generate.