1 diff -Nur linux-2.6.1.org/include/linux/netfilter_ipv4/ipt_TTL.h linux-2.6.1/include/linux/netfilter_ipv4/ipt_TTL.h
2 --- linux-2.6.1.org/include/linux/netfilter_ipv4/ipt_TTL.h 1970-01-01 01:00:00.000000000 +0100
3 +++ linux-2.6.1/include/linux/netfilter_ipv4/ipt_TTL.h 2004-01-14 14:06:00.000000000 +0100
5 +/* TTL modification module for IP tables
6 + * (C) 2000 by Harald Welte <laforge@gnumonks.org> */
17 +#define IPT_TTL_MAXMODE IPT_TTL_DEC
19 +struct ipt_TTL_info {
26 diff -Nur linux-2.6.1.org/include/linux/netfilter_ipv4/ipt_connlimit.h linux-2.6.1/include/linux/netfilter_ipv4/ipt_connlimit.h
27 --- linux-2.6.1.org/include/linux/netfilter_ipv4/ipt_connlimit.h 1970-01-01 01:00:00.000000000 +0100
28 +++ linux-2.6.1/include/linux/netfilter_ipv4/ipt_connlimit.h 2004-01-14 14:04:43.000000000 +0100
30 +#ifndef _IPT_CONNLIMIT_H
31 +#define _IPT_CONNLIMIT_H
33 +struct ipt_connlimit_data;
35 +struct ipt_connlimit_info {
39 + struct ipt_connlimit_data *data;
41 +#endif /* _IPT_CONNLIMIT_H */
42 diff -Nur linux-2.6.1.org/include/linux/netfilter_ipv4/ipt_osf.h linux-2.6.1/include/linux/netfilter_ipv4/ipt_osf.h
43 --- linux-2.6.1.org/include/linux/netfilter_ipv4/ipt_osf.h 1970-01-01 01:00:00.000000000 +0100
44 +++ linux-2.6.1/include/linux/netfilter_ipv4/ipt_osf.h 2004-01-14 14:04:31.000000000 +0100
49 + * Copyright (c) 2003 Evgeniy Polyakov <johnpol@2ka.mipt.ru>
52 + * This program is free software; you can redistribute it and/or modify
53 + * it under the terms of the GNU General Public License as published by
54 + * the Free Software Foundation; either version 2 of the License, or
55 + * (at your option) any later version.
57 + * This program is distributed in the hope that it will be useful,
58 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
59 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
60 + * GNU General Public License for more details.
62 + * You should have received a copy of the GNU General Public License
63 + * along with this program; if not, write to the Free Software
64 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
70 +#define MAXGENRELEN 32
73 +#define IPT_OSF_GENRE 1
74 +#define IPT_OSF_SMART 2
75 +#define IPT_OSF_LOG 4
77 +#define IPT_OSF_LOGLEVEL_ALL 0
78 +#define IPT_OSF_LOGLEVEL_FIRST 1
80 +#include <linux/list.h>
84 + char genre[MAXGENRELEN];
86 + unsigned long flags;
88 + int invert; /* UNSUPPORTED */
97 +/* This struct represents IANA options
98 + * http://www.iana.org/assignments/tcp-parameters
102 + unsigned char kind;
103 + unsigned char length;
111 + struct list_head flist;
116 + char genre[MAXGENRELEN];
117 + char version[MAXGENRELEN], subtype[MAXGENRELEN];
119 + /* Not needed, but for consistency with original table from Michal Zalewski */
120 + char details[MAXDETLEN];
123 + struct osf_opt opt[MAX_IPOPTLEN]; /* In case it is all NOP or EOL */
127 +/* Defines for IANA option kinds */
129 +#define OSFOPT_EOL 0 /* End of options */
130 +#define OSFOPT_NOP 1 /* NOP */
131 +#define OSFOPT_MSS 2 /* Maximum segment size */
132 +#define OSFOPT_WSO 3 /* Window scale option */
133 +#define OSFOPT_SACKP 4 /* SACK permitted */
134 +#define OSFOPT_SACK 5 /* SACK */
135 +#define OSFOPT_ECHO 6
136 +#define OSFOPT_ECHOREPLY 7
137 +#define OSFOPT_TS 8 /* Timestamp option */
138 +#define OSFOPT_POCP 9 /* Partial Order Connection Permitted */
139 +#define OSFOPT_POSP 10 /* Partial Order Service Profile */
140 +/* Others are not used in current OSF */
142 +static struct osf_opt IANA_opts[] =
149 + {5, 1 ,}, /* SACK length is not defined */
155 + {11, 1,}, /* CC: Suppose 1 */
156 + {12, 1,}, /* the same */
157 + {13, 1,}, /* and here too */
159 + {15, 1,}, /* TCP Alternate Checksum Data. Length is not defined */
173 +#endif /* __KERNEL__ */
175 +#endif /* _IPT_OSF_H */
176 diff -Nur linux-2.6.1.org/include/linux/netfilter_ipv4/ipt_psd.h linux-2.6.1/include/linux/netfilter_ipv4/ipt_psd.h
177 --- linux-2.6.1.org/include/linux/netfilter_ipv4/ipt_psd.h 1970-01-01 01:00:00.000000000 +0100
178 +++ linux-2.6.1/include/linux/netfilter_ipv4/ipt_psd.h 2004-01-14 14:04:53.000000000 +0100
183 +#include <linux/param.h>
184 +#include <linux/types.h>
187 + * High port numbers have a lower weight to reduce the frequency of false
188 + * positives, such as from passive mode FTP transfers.
190 +#define PORT_WEIGHT_PRIV 3
191 +#define PORT_WEIGHT_HIGH 1
194 + * Port scan detection thresholds: at least COUNT ports need to be scanned
195 + * from the same source, with no longer than DELAY ticks between ports.
197 +#define SCAN_MIN_COUNT 7
198 +#define SCAN_MAX_COUNT (SCAN_MIN_COUNT * PORT_WEIGHT_PRIV)
199 +#define SCAN_WEIGHT_THRESHOLD SCAN_MAX_COUNT
200 +#define SCAN_DELAY_THRESHOLD (HZ * 3)
203 + * Keep track of up to LIST_SIZE source addresses, using a hash table of
204 + * HASH_SIZE entries for faster lookups, but limiting hash collisions to
205 + * HASH_MAX source addresses per the same hash value.
207 +#define LIST_SIZE 0x100
209 +#define HASH_SIZE (1 << HASH_LOG)
210 +#define HASH_MAX 0x10
212 +struct ipt_psd_info {
213 + unsigned int weight_threshold;
214 + unsigned int delay_threshold;
215 + unsigned short lo_ports_weight;
216 + unsigned short hi_ports_weight;
219 +#endif /*_IPT_PSD_H*/
220 diff -Nur linux-2.6.1.org/include/linux/netfilter_ipv4/ipt_quota.h linux-2.6.1/include/linux/netfilter_ipv4/ipt_quota.h
221 --- linux-2.6.1.org/include/linux/netfilter_ipv4/ipt_quota.h 1970-01-01 01:00:00.000000000 +0100
222 +++ linux-2.6.1/include/linux/netfilter_ipv4/ipt_quota.h 2004-01-14 14:04:22.000000000 +0100
224 +#ifndef _IPT_QUOTA_H
225 +#define _IPT_QUOTA_H
227 +/* print debug info in both kernel/netfilter module & iptable library */
228 +//#define DEBUG_IPT_QUOTA
230 +struct ipt_quota_info {
234 +#endif /*_IPT_QUOTA_H*/
235 diff -Nur linux-2.6.1.org/include/linux/netfilter_ipv4/ipt_time.h linux-2.6.1/include/linux/netfilter_ipv4/ipt_time.h
236 --- linux-2.6.1.org/include/linux/netfilter_ipv4/ipt_time.h 1970-01-01 01:00:00.000000000 +0100
237 +++ linux-2.6.1/include/linux/netfilter_ipv4/ipt_time.h 2004-01-14 14:05:44.000000000 +0100
239 +#ifndef __ipt_time_h_included__
240 +#define __ipt_time_h_included__
243 +struct ipt_time_info {
244 + u_int8_t days_match; /* 1 bit per day. -SMTWTFS */
245 + u_int16_t time_start; /* 0 < time_start < 23*60+59 = 1439 */
246 + u_int16_t time_stop; /* 0:0 < time_stat < 23:59 */
247 + u_int8_t kerneltime; /* ignore skb time (and use kerneltime) or not. */
251 +#endif /* __ipt_time_h_included__ */
252 diff -Nur linux-2.6.1.org/include/linux/netfilter_ipv4/ipt_u32.h linux-2.6.1/include/linux/netfilter_ipv4/ipt_u32.h
253 --- linux-2.6.1.org/include/linux/netfilter_ipv4/ipt_u32.h 1970-01-01 01:00:00.000000000 +0100
254 +++ linux-2.6.1/include/linux/netfilter_ipv4/ipt_u32.h 2004-01-14 14:05:13.000000000 +0100
258 +#include <linux/netfilter_ipv4/ip_tables.h>
268 +struct ipt_u32_location_element
273 +struct ipt_u32_value_element
278 +/* *** any way to allow for an arbitrary number of elements?
279 + for now I settle for a limit of 10 of each */
280 +#define U32MAXSIZE 10
284 + struct ipt_u32_location_element location[U32MAXSIZE+1];
286 + struct ipt_u32_value_element value[U32MAXSIZE+1];
292 + struct ipt_u32_test tests[U32MAXSIZE+1];
295 +#endif /*_IPT_U32_H*/
296 diff -Nur linux-2.6.1.org/net/ipv4/netfilter/Kconfig linux-2.6.1/net/ipv4/netfilter/Kconfig
297 --- linux-2.6.1.org/net/ipv4/netfilter/Kconfig 2004-01-09 07:59:56.000000000 +0100
298 +++ linux-2.6.1/net/ipv4/netfilter/Kconfig 2004-01-14 14:06:00.000000000 +0100
301 To compile it as a module, choose M here. If unsure, say N.
303 +config IP_NF_TARGET_TTL
304 + tristate 'TTL target support'
305 + depends on IP_NF_MANGLE
307 + This adds an iptables TTL manipulation target, which enables the user
308 + to set the TTL value of an IP packet or to increment / decrement it
311 + To compile it as a module, choose M here. If unsure, say N.
313 config IP_NF_TARGET_CLASSIFY
314 tristate "CLASSIFY target support"
315 depends on IP_NF_MANGLE
316 @@ -566,5 +576,162 @@
318 To compile it as a module, choose M here. If unsure, say N.
320 +config IP_NF_MATCH_QUOTA
321 + tristate 'quota match support'
322 + depends on IP_NF_IPTABLES
324 + This option adds CONFIG_IP_NF_MATCH_QUOTA, which implements network
325 + quotas by decrementing a byte counter with each packet.
327 + Supported options are:
329 + The quota in bytes.
331 + KNOWN BUGS: this does not work on SMP systems.
334 +config IP_NF_MATCH_OSF
335 + tristate 'OSF match support'
336 + depends on IP_NF_IPTABLES
338 + The idea of passive OS fingerprint matching exists for quite a long time,
339 + but was created as extension fo OpenBSD pf only some weeks ago.
340 + Original idea was lurked in some OpenBSD mailing list (thanks
341 + grange@open...) and than adopted for Linux netfilter in form of this code.
343 + Original table was created by Michal Zalewski <lcamtuf@coredump.cx> for
344 + his excellent p0f and than changed a bit for more convenience.
346 + This module compares some data(WS, MSS, options and it's order, ttl,
347 + df and others) from first SYN packet (actually from packets with SYN
348 + bit set) with hardcoded in fingers[] table ones.
350 + Example: (Of course this only an example, do not get inspired by this)
352 + # iptables -N LINUX
353 + # iptables -A LINUX -j LOG --log-prefix "Linux"
355 + # iptables -A INPUT -p tcp -m osf --genre Linux -j LINUX
356 + # iptables -A INPUT -p tcp -m osf --genre FreeBSD -j REJECT
358 + NOTE: -p tcp is obviously required as it is a TCP match.
362 + If present, OSF will log determined genres even if they don't match
364 + 0 - log all determined entries,
365 + 1 - only first one.
368 + #iptables -I INPUT -j ACCEPT -p tcp -m osf --genre Linux --log 1 --smart
370 + In syslog you find something like this:
371 + ipt_osf: Windows [Windows XP Pro SP1, 2000 SP3]: 11.22.33.55:4024 -> 11.22.33.44:139
372 + ipt_osf: Unknown: 16384:106:1:48:020405B401010402 44.33.22.11:1239 -> 11.22.33.44:80
375 + if present, OSF will use some smartness to determine remote OS.
376 + Now only not use TTL( with it far remote machines can be determined).
378 + Fingerprints can be loaded through /proc/sys/net/ipv4/osf file.
379 + Only one fingerprint per open/close.
381 + Fingerprints can be downloaded from http://www.openbsd.org/cgi-bin/cvsweb/src/etc/pf.os
383 +config IP_NF_MATCH_CONNLIMIT
384 + tristate 'Connections/IP limit match support'
385 + depends on IP_NF_IPTABLES
387 + This adds an iptables match which allows you to restrict the
388 + number of parallel TCP connections to a server per client IP address
389 + (or address block).
393 + # allow 2 telnet connections per client host
394 + iptables -p tcp --syn --dport 23 -m connlimit --connlimit-above 2 -j REJECT
396 + # you can also match the other way around:
397 + iptables -p tcp --syn --dport 23 -m connlimit ! --connlimit-above 2 -j ACCEPT
399 + # limit the nr of parallel http requests to 16 per class C sized
400 + # network (24 bit netmask)
401 + iptables -p tcp --syn --dport 80 -m connlimit --connlimit-above 16 \
402 + --connlimit-mask 24 -j REJECT
404 +config IP_NF_MATCH_PSD
405 + tristate 'psd match support'
406 + depends on IP_NF_IPTABLES
408 + This option adds a `psd' match, which supplies portscan
409 + detection match (psd). This match will attempt to detect TCP and UDP
410 + port scans. This match was derived from Solar Designer's scanlogd.
412 + Suppported options are:
414 + --psd-weight-threshold <threshold>
416 + Total weight of the latest TCP/UDP packets with different
417 + destination ports coming from the same host to be treated as port
420 + --psd-delay-threshold <delay>
422 + Delay (in hundredths of second) for the packets with different
423 + destination ports coming from the same host to be treated as
424 + possible port scan subsequence.
426 + --psd-lo-ports-weight <weight>
428 + Weight of the packet with privileged (<=1024) destination port.
430 + --psd-hi-ports-weight <weight>
432 + Weight of the packet with non-priviliged destination port.
434 +config IP_NF_MATCH_U32
435 + tristate 'U32 match support'
436 + depends on IP_NF_IPTABLES
439 + U32 allows you to extract quantities of up to 4 bytes from a packet,
440 + AND them with specified masks, shift them by specified amounts and
441 + test whether the results are in any of a set of specified ranges.
442 + The specification of what to extract is general enough to skip over
443 + headers with lengths stored in the packet, as in IP or TCP header
445 + Details and examples are in the kernel module source.
447 +config IP_NF_MATCH_TIME
448 + tristate 'TIME match support'
449 + depends on IP_NF_IPTABLES
452 + This option adds CONFIG_IP_NF_MATCH_TIME, which supplies a time match module.
453 + This match allows you to filter based on the packet arrival time
454 + (arrival time at the machine which the netfilter is running on) or
455 + departure time (for locally generated packets).
457 + Supported options are:
459 + The starting point of the time match frame.
462 + The stopping point of the time match frame
465 + Days of the week to match separated by a coma, no space
466 + (one of Sun,Mon,Tue,Wed,Thu,Fri,Sat)
469 + -A INPUT -m time --timestart 8:00 --timestop 18:00 --days Mon,Tue,Wed,Thu,Fri
470 + will match packets that have an arrival timestamp in the range 8:00->18:00 from Monday
473 + -A OUTPUT -m time --timestart 8:00 --timestop 18:00 --Days Mon
474 + will match the packets (locally generated) that have a departure timestamp
475 + in the range 8:00->18:00 on Monday only.
479 diff -Nur linux-2.6.1.org/net/ipv4/netfilter/Makefile linux-2.6.1/net/ipv4/netfilter/Makefile
480 --- linux-2.6.1.org/net/ipv4/netfilter/Makefile 2004-01-09 07:59:18.000000000 +0100
481 +++ linux-2.6.1/net/ipv4/netfilter/Makefile 2004-01-14 14:06:00.000000000 +0100
484 obj-$(CONFIG_IP_NF_MATCH_HELPER) += ipt_helper.o
485 obj-$(CONFIG_IP_NF_MATCH_LIMIT) += ipt_limit.o
486 +obj-$(CONFIG_IP_NF_MATCH_QUOTA) += ipt_quota.o
487 obj-$(CONFIG_IP_NF_MATCH_MARK) += ipt_mark.o
488 obj-$(CONFIG_IP_NF_MATCH_MAC) += ipt_mac.o
489 obj-$(CONFIG_IP_NF_MATCH_IPRANGE) += ipt_iprange.o
491 obj-$(CONFIG_IP_NF_MATCH_OWNER) += ipt_owner.o
492 obj-$(CONFIG_IP_NF_MATCH_TOS) += ipt_tos.o
494 +obj-$(CONFIG_IP_NF_MATCH_TIME) += ipt_time.o
497 +obj-$(CONFIG_IP_NF_MATCH_PSD) += ipt_psd.o
499 +obj-$(CONFIG_IP_NF_MATCH_OSF) += ipt_osf.o
502 obj-$(CONFIG_IP_NF_MATCH_RECENT) += ipt_recent.o
504 obj-$(CONFIG_IP_NF_MATCH_ECN) += ipt_ecn.o
507 obj-$(CONFIG_IP_NF_MATCH_LENGTH) += ipt_length.o
509 +obj-$(CONFIG_IP_NF_MATCH_U32) += ipt_u32.o
512 obj-$(CONFIG_IP_NF_MATCH_TTL) += ipt_ttl.o
513 obj-$(CONFIG_IP_NF_MATCH_STATE) += ipt_state.o
514 +obj-$(CONFIG_IP_NF_MATCH_CONNLIMIT) += ipt_connlimit.o
515 obj-$(CONFIG_IP_NF_MATCH_CONNTRACK) += ipt_conntrack.o
516 obj-$(CONFIG_IP_NF_MATCH_TCPMSS) += ipt_tcpmss.o
519 obj-$(CONFIG_IP_NF_TARGET_ECN) += ipt_ECN.o
520 obj-$(CONFIG_IP_NF_TARGET_DSCP) += ipt_DSCP.o
521 obj-$(CONFIG_IP_NF_TARGET_MARK) += ipt_MARK.o
522 +obj-$(CONFIG_IP_NF_TARGET_TTL) += ipt_TTL.o
523 obj-$(CONFIG_IP_NF_TARGET_MASQUERADE) += ipt_MASQUERADE.o
524 obj-$(CONFIG_IP_NF_TARGET_REDIRECT) += ipt_REDIRECT.o
525 obj-$(CONFIG_IP_NF_TARGET_NETMAP) += ipt_NETMAP.o
526 diff -Nur linux-2.6.1.org/net/ipv4/netfilter/ipt_TTL.c linux-2.6.1/net/ipv4/netfilter/ipt_TTL.c
527 --- linux-2.6.1.org/net/ipv4/netfilter/ipt_TTL.c 1970-01-01 01:00:00.000000000 +0100
528 +++ linux-2.6.1/net/ipv4/netfilter/ipt_TTL.c 2004-01-14 14:06:00.000000000 +0100
530 +/* TTL modification target for IP tables
531 + * (C) 2000 by Harald Welte <laforge@gnumonks.org>
535 + * This software is distributed under the terms of GNU GPL
538 +#include <linux/module.h>
539 +#include <linux/skbuff.h>
540 +#include <linux/ip.h>
541 +#include <net/checksum.h>
543 +#include <linux/netfilter_ipv4/ip_tables.h>
544 +#include <linux/netfilter_ipv4/ipt_TTL.h>
546 +MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
547 +MODULE_DESCRIPTION("IP tables TTL modification module");
548 +MODULE_LICENSE("GPL");
550 +static unsigned int ipt_ttl_target(struct sk_buff **pskb,
551 + const struct net_device *in,
552 + const struct net_device *out,
553 + unsigned int hooknum,
554 + const void *targinfo,
557 + struct iphdr *iph = (*pskb)->nh.iph;
558 + const struct ipt_TTL_info *info = targinfo;
559 + u_int16_t diffs[2];
562 + switch (info->mode) {
564 + new_ttl = info->ttl;
567 + new_ttl = iph->ttl + info->ttl;
572 + new_ttl = iph->ttl + info->ttl;
577 + new_ttl = iph->ttl;
581 + if (new_ttl != iph->ttl) {
582 + diffs[0] = htons(((unsigned)iph->ttl) << 8) ^ 0xFFFF;
583 + iph->ttl = new_ttl;
584 + diffs[1] = htons(((unsigned)iph->ttl) << 8);
585 + iph->check = csum_fold(csum_partial((char *)diffs,
587 + iph->check^0xFFFF));
588 + (*pskb)->nfcache |= NFC_ALTERED;
591 + return IPT_CONTINUE;
594 +static int ipt_ttl_checkentry(const char *tablename,
595 + const struct ipt_entry *e,
597 + unsigned int targinfosize,
598 + unsigned int hook_mask)
600 + struct ipt_TTL_info *info = targinfo;
602 + if (targinfosize != IPT_ALIGN(sizeof(struct ipt_TTL_info))) {
603 + printk(KERN_WARNING "TTL: targinfosize %u != %Zu\n",
605 + IPT_ALIGN(sizeof(struct ipt_TTL_info)));
609 + if (strcmp(tablename, "mangle")) {
610 + printk(KERN_WARNING "TTL: can only be called from \"mangle\" table, not \"%s\"\n", tablename);
614 + if (info->mode > IPT_TTL_MAXMODE) {
615 + printk(KERN_WARNING "TTL: invalid or unknown Mode %u\n",
620 + if ((info->mode != IPT_TTL_SET) && (info->ttl == 0)) {
621 + printk(KERN_WARNING "TTL: increment/decrement doesn't make sense with value 0\n");
628 +static struct ipt_target ipt_TTL = {
630 + .target = ipt_ttl_target,
631 + .checkentry = ipt_ttl_checkentry,
635 +static int __init init(void)
637 + return ipt_register_target(&ipt_TTL);
640 +static void __exit fini(void)
642 + ipt_unregister_target(&ipt_TTL);
647 diff -Nur linux-2.6.1.org/net/ipv4/netfilter/ipt_connlimit.c linux-2.6.1/net/ipv4/netfilter/ipt_connlimit.c
648 --- linux-2.6.1.org/net/ipv4/netfilter/ipt_connlimit.c 1970-01-01 01:00:00.000000000 +0100
649 +++ linux-2.6.1/net/ipv4/netfilter/ipt_connlimit.c 2004-01-14 14:04:43.000000000 +0100
652 + * netfilter module to limit the number of parallel tcp
653 + * connections per IP address.
654 + * (c) 2000 Gerd Knorr <kraxel@bytesex.org>
655 + * Nov 2002: Martin Bene <martin.bene@icomedias.com>:
656 + * only ignore TIME_WAIT or gone connections
660 + * Kernel module to match connection tracking information.
661 + * GPL (C) 1999 Rusty Russell (rusty@rustcorp.com.au).
663 +#include <linux/module.h>
664 +#include <linux/skbuff.h>
665 +#include <linux/list.h>
666 +#include <linux/netfilter_ipv4/ip_conntrack.h>
667 +#include <linux/netfilter_ipv4/ip_conntrack_core.h>
668 +#include <linux/netfilter_ipv4/ip_conntrack_tcp.h>
669 +#include <linux/netfilter_ipv4/ip_tables.h>
670 +#include <linux/netfilter_ipv4/ipt_connlimit.h>
674 +MODULE_LICENSE("GPL");
676 +/* we'll save the tuples of all connections we care about */
677 +struct ipt_connlimit_conn
679 + struct list_head list;
680 + struct ip_conntrack_tuple tuple;
683 +struct ipt_connlimit_data {
685 + struct list_head iphash[256];
688 +static int ipt_iphash(u_int32_t addr)
692 + hash = addr & 0xff;
693 + hash ^= (addr >> 8) & 0xff;
694 + hash ^= (addr >> 16) & 0xff;
695 + hash ^= (addr >> 24) & 0xff;
699 +static int count_them(struct ipt_connlimit_data *data,
700 + u_int32_t addr, u_int32_t mask,
701 + struct ip_conntrack *ct)
704 + const static char *tcp[] = { "none", "established", "syn_sent", "syn_recv",
705 + "fin_wait", "time_wait", "close", "close_wait",
706 + "last_ack", "listen" };
708 + int addit = 1, matches = 0;
709 + struct ip_conntrack_tuple tuple;
710 + struct ip_conntrack_tuple_hash *found;
711 + struct ipt_connlimit_conn *conn;
712 + struct list_head *hash,*lh;
714 + spin_lock(&data->lock);
715 + tuple = ct->tuplehash[0].tuple;
716 + hash = &data->iphash[ipt_iphash(addr & mask)];
718 + /* check the saved connections */
719 + for (lh = hash->next; lh != hash; lh = lh->next) {
720 + conn = list_entry(lh,struct ipt_connlimit_conn,list);
721 + found = ip_conntrack_find_get(&conn->tuple,ct);
722 + if (0 == memcmp(&conn->tuple,&tuple,sizeof(tuple)) &&
724 + found->ctrack->proto.tcp.state != TCP_CONNTRACK_TIME_WAIT) {
725 + /* Just to be sure we have it only once in the list.
726 + We should'nt see tuples twice unless someone hooks this
727 + into a table without "-p tcp --syn" */
731 + printk("ipt_connlimit [%d]: src=%u.%u.%u.%u:%d dst=%u.%u.%u.%u:%d %s\n",
732 + ipt_iphash(addr & mask),
733 + NIPQUAD(conn->tuple.src.ip), ntohs(conn->tuple.src.u.tcp.port),
734 + NIPQUAD(conn->tuple.dst.ip), ntohs(conn->tuple.dst.u.tcp.port),
735 + (NULL != found) ? tcp[found->ctrack->proto.tcp.state] : "gone");
737 + if (NULL == found) {
738 + /* this one is gone */
740 + list_del(lh->next);
744 + if (found->ctrack->proto.tcp.state == TCP_CONNTRACK_TIME_WAIT) {
745 + /* we don't care about connections which are
746 + closed already -> ditch it */
748 + list_del(lh->next);
750 + nf_conntrack_put(&found->ctrack->infos[0]);
753 + if ((addr & mask) == (conn->tuple.src.ip & mask)) {
754 + /* same source IP address -> be counted! */
757 + nf_conntrack_put(&found->ctrack->infos[0]);
760 + /* save the new connection in our list */
762 + printk("ipt_connlimit [%d]: src=%u.%u.%u.%u:%d dst=%u.%u.%u.%u:%d new\n",
763 + ipt_iphash(addr & mask),
764 + NIPQUAD(tuple.src.ip), ntohs(tuple.src.u.tcp.port),
765 + NIPQUAD(tuple.dst.ip), ntohs(tuple.dst.u.tcp.port));
767 + conn = kmalloc(sizeof(*conn),GFP_ATOMIC);
770 + memset(conn,0,sizeof(*conn));
771 + INIT_LIST_HEAD(&conn->list);
772 + conn->tuple = tuple;
773 + list_add(&conn->list,hash);
776 + spin_unlock(&data->lock);
781 +match(const struct sk_buff *skb,
782 + const struct net_device *in,
783 + const struct net_device *out,
784 + const void *matchinfo,
790 + const struct ipt_connlimit_info *info = matchinfo;
791 + int connections, match;
792 + struct ip_conntrack *ct;
793 + enum ip_conntrack_info ctinfo;
795 + ct = ip_conntrack_get((struct sk_buff *)skb, &ctinfo);
797 + printk("ipt_connlimit: Oops: invalid ct state ?\n");
801 + connections = count_them(info->data,skb->nh.iph->saddr,info->mask,ct);
802 + if (-1 == connections) {
803 + printk("ipt_connlimit: Hmm, kmalloc failed :-(\n");
804 + *hotdrop = 1; /* let's free some memory :-) */
807 + match = (info->inverse) ? (connections <= info->limit) : (connections > info->limit);
809 + printk("ipt_connlimit: src=%u.%u.%u.%u mask=%u.%u.%u.%u "
810 + "connections=%d limit=%d match=%s\n",
811 + NIPQUAD(skb->nh.iph->saddr), NIPQUAD(info->mask),
812 + connections, info->limit, match ? "yes" : "no");
818 +static int check(const char *tablename,
819 + const struct ipt_ip *ip,
821 + unsigned int matchsize,
822 + unsigned int hook_mask)
824 + struct ipt_connlimit_info *info = matchinfo;
828 + if (matchsize != IPT_ALIGN(sizeof(struct ipt_connlimit_info)))
831 + /* refuse anything but tcp */
832 + if (ip->proto != IPPROTO_TCP)
835 + /* init private data */
836 + info->data = kmalloc(sizeof(struct ipt_connlimit_data),GFP_KERNEL);
837 + spin_lock_init(&(info->data->lock));
838 + for (i = 0; i < 256; i++)
839 + INIT_LIST_HEAD(&(info->data->iphash[i]));
844 +static void destroy(void *matchinfo, unsigned int matchinfosize)
846 + struct ipt_connlimit_info *info = matchinfo;
847 + struct ipt_connlimit_conn *conn;
848 + struct list_head *hash;
852 + for (i = 0; i < 256; i++) {
853 + hash = &(info->data->iphash[i]);
854 + while (hash != hash->next) {
855 + conn = list_entry(hash->next,struct ipt_connlimit_conn,list);
856 + list_del(hash->next);
863 +static struct ipt_match connlimit_match = {
864 + .name = "connlimit",
866 + .checkentry = &check,
867 + .me = THIS_MODULE };
869 +static int __init init(void)
871 + return ipt_register_match(&connlimit_match);
874 +static void __exit fini(void)
876 + ipt_unregister_match(&connlimit_match);
881 diff -Nur linux-2.6.1.org/net/ipv4/netfilter/ipt_osf.c linux-2.6.1/net/ipv4/netfilter/ipt_osf.c
882 --- linux-2.6.1.org/net/ipv4/netfilter/ipt_osf.c 1970-01-01 01:00:00.000000000 +0100
883 +++ linux-2.6.1/net/ipv4/netfilter/ipt_osf.c 2004-01-14 14:04:31.000000000 +0100
888 + * Copyright (c) 2003 Evgeniy Polyakov <johnpol@2ka.mipt.ru>
891 + * This program is free software; you can redistribute it and/or modify
892 + * it under the terms of the GNU General Public License as published by
893 + * the Free Software Foundation; either version 2 of the License, or
894 + * (at your option) any later version.
896 + * This program is distributed in the hope that it will be useful,
897 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
898 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
899 + * GNU General Public License for more details.
901 + * You should have received a copy of the GNU General Public License
902 + * along with this program; if not, write to the Free Software
903 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
907 + * OS fingerprint matching module.
908 + * It simply compares various parameters from SYN packet with
909 + * some hardcoded ones.
911 + * Original table was created by Michal Zalewski <lcamtuf@coredump.cx>
915 +#include <linux/config.h>
916 +#include <linux/kernel.h>
917 +#include <linux/smp.h>
918 +#include <linux/module.h>
919 +#include <linux/skbuff.h>
920 +#include <linux/file.h>
921 +#include <linux/ip.h>
922 +#include <linux/proc_fs.h>
923 +#include <linux/fs.h>
924 +#include <linux/slab.h>
925 +#include <linux/spinlock.h>
926 +#include <linux/ctype.h>
927 +#include <linux/list.h>
929 +#include <net/sock.h>
932 +#include <linux/netfilter_ipv4/ip_tables.h>
934 +#include <linux/netfilter_ipv4/ipt_osf.h>
939 +#define log(x...) printk(KERN_INFO "ipt_osf: " x)
940 +#define loga(x...) printk(x)
942 +#define log(x...) do {} while(0)
943 +#define loga(x...) do {} while(0)
946 +#define FMATCH_WRONG 0
948 +#define FMATCH_OPT_WRONG 2
952 +#define MAXOPTSTRLEN 128
953 +#define OSFFLUSH "FLUSH"
955 +static rwlock_t osf_lock = RW_LOCK_UNLOCKED;
956 +static struct list_head finger_list;
958 +static int match(const struct sk_buff *, const struct net_device *, const struct net_device *,
959 + const void *, int, const void *, u_int16_t, int *);
960 +static int checkentry(const char *, const struct ipt_ip *, void *,
961 + unsigned int, unsigned int);
963 +static struct ipt_match osf_match = {
966 + .checkentry = &checkentry,
970 +static inline int smart_dec(unsigned long flags, unsigned char ip_ttl, unsigned char f_ttl)
972 + if (flags & IPT_OSF_SMART)
975 + return (ip_ttl == f_ttl);
979 +match(const struct sk_buff *skb,
980 + const struct net_device *in,
981 + const struct net_device *out,
982 + const void *matchinfo,
988 + struct ipt_osf_info *info = (struct ipt_osf_info *)matchinfo;
989 + struct iphdr *ip = skb->nh.iph;
990 + struct tcphdr *tcp;
991 + int fmatch = FMATCH_WRONG, fcount = 0;
992 + unsigned long totlen, optsize = 0, window;
993 + unsigned char df, *optp = NULL, *_optp = NULL;
994 + char check_WSS = 0;
995 + struct list_head *ent;
996 + struct osf_finger *f;
1001 + tcp = (struct tcphdr *)((u_int32_t *)ip + ip->ihl);
1005 + else if (tcp->ack)
1008 + totlen = ntohs(ip->tot_len);
1009 + df = ((ntohs(ip->frag_off) & IP_DF)?1:0);
1010 + window = ntohs(tcp->window);
1012 + if (tcp->doff*4 > sizeof(struct tcphdr))
1014 + _optp = optp = (char *)(tcp+1);
1015 + optsize = tcp->doff*4 - sizeof(struct tcphdr);
1019 + /* Actually we can create hash/table of all genres and search
1020 + * only in appropriate part, but here is initial variant,
1021 + * so will use slow path.
1023 + read_lock(&osf_lock);
1024 + list_for_each(ent, &finger_list)
1026 + f = list_entry(ent, struct osf_finger, flist);
1028 + if (!(info->flags & IPT_OSF_LOG) && strcmp(info->genre, f->genre))
1032 + fmatch = FMATCH_WRONG;
1034 + if (totlen == f->ss && df == f->df &&
1035 + smart_dec(info->flags, ip->ttl, f->ttl))
1037 + unsigned long foptsize;
1039 + unsigned short mss = 0;
1043 + switch (f->wss.wc)
1045 + case 0: check_WSS = 0; break;
1046 + case 'S': check_WSS = 1; break;
1047 + case 'T': check_WSS = 2; break;
1048 + case '%': check_WSS = 3; break;
1049 + default: log("Wrong fingerprint wss.wc=%d, %s - %s\n",
1050 + f->wss.wc, f->genre, f->details);
1054 + if (check_WSS == 4)
1057 + /* Check options */
1060 + for (optnum=0; optnum<f->opt_num; ++optnum)
1061 + foptsize += f->opt[optnum].length;
1064 + if (foptsize > MAX_IPOPTLEN || optsize > MAX_IPOPTLEN || optsize != foptsize)
1069 + fmatch = FMATCH_OK;
1070 + loga("\tYEP : matching without options.\n");
1071 + if ((info->flags & IPT_OSF_LOG) &&
1072 + info->loglevel == IPT_OSF_LOGLEVEL_FIRST)
1079 + for (optnum=0; optnum<f->opt_num; ++optnum)
1081 + if (f->opt[optnum].kind == (*optp))
1083 + unsigned char len = f->opt[optnum].length;
1084 + unsigned char *optend = optp + len;
1086 + fmatch = FMATCH_OK;
1088 + if (*optp == OSFOPT_MSS) /* MSS */
1089 + mss = ntohs(*(unsigned short *)(optp+2));
1093 + /* Skip kind and length fields*/
1096 + if (f->opt[optnum].wc.wc != 0)
1098 + unsigned long tmp = 0;
1100 + /* Hmmm... It looks a bit ugly. :) */
1101 + memcpy(&tmp, &f->opt[optnum].wc.val,
1102 + (len > sizeof(unsigned long)?
1103 + sizeof(unsigned long):len));
1106 + if (tmp != f->opt[optnum].wc.val)
1107 + fmatch = FMATCH_OPT_WRONG;
1114 + fmatch = FMATCH_OPT_WRONG;
1116 + if (fmatch != FMATCH_OK)
1120 + if (fmatch != FMATCH_OPT_WRONG)
1122 + fmatch = FMATCH_WRONG;
1124 + switch (check_WSS)
1127 + if (window == f->wss.val)
1128 + fmatch = FMATCH_OK;
1131 + if (window == f->wss.val*mss)
1132 + fmatch = FMATCH_OK;
1135 + if (window == f->wss.val*(mss+40))
1136 + fmatch = FMATCH_OK;
1139 + if (window % f->wss.val == 0)
1140 + fmatch = FMATCH_OK;
1146 + if (fmatch == FMATCH_OK)
1149 + log("%s [%s]: %u.%u.%u.%u:%u -> %u.%u.%u.%u:%u\n",
1150 + f->genre, f->details,
1151 + NIPQUAD(ip->saddr), ntohs(tcp->source),
1152 + NIPQUAD(ip->daddr), ntohs(tcp->dest));
1153 + if ((info->flags & IPT_OSF_LOG) &&
1154 + info->loglevel == IPT_OSF_LOGLEVEL_FIRST)
1159 + if (!fcount && (info->flags & IPT_OSF_LOG))
1161 + log("Unknown: %lu:%d:%d:%lu:", window, ip->ttl, df, totlen);
1164 + unsigned char opt[4 * 15 - sizeof(struct tcphdr)];
1165 + unsigned int i, optsize;
1167 + optsize = tcp->doff * 4 - sizeof(struct tcphdr);
1168 + if (skb_copy_bits(skb, ip->ihl*4 + sizeof(struct tcphdr),
1169 + opt, optsize) < 0)
1170 + loga("TRUNCATED");
1172 + for (i = 0; i < optsize; i++)
1173 + loga("%02X", opt[i]);
1176 + loga(" %u.%u.%u.%u:%u -> %u.%u.%u.%u:%u\n",
1177 + NIPQUAD(ip->saddr), ntohs(tcp->source),
1178 + NIPQUAD(ip->daddr), ntohs(tcp->dest));
1180 + read_unlock(&osf_lock);
1182 + return (fmatch == FMATCH_OK)?1:0;
1186 +checkentry(const char *tablename,
1187 + const struct ipt_ip *ip,
1189 + unsigned int matchsize,
1190 + unsigned int hook_mask)
1192 + if (matchsize != IPT_ALIGN(sizeof(struct ipt_osf_info)))
1194 + if (ip->proto != IPPROTO_TCP)
1200 +static char * osf_strchr(char *ptr, char c)
1204 + tmp = strchr(ptr, c);
1206 + while (tmp && tmp+1 && isspace(*(tmp+1)))
1212 +static struct osf_finger * finger_alloc(void)
1214 + struct osf_finger *f;
1216 + f = kmalloc(sizeof(struct osf_finger), GFP_KERNEL);
1218 + memset(f, 0, sizeof(struct osf_finger));
1223 +static void finger_free(struct osf_finger *f)
1225 + memset(f, 0, sizeof(struct osf_finger));
1230 +static void osf_parse_opt(struct osf_opt *opt, int *optnum, char *obuf, int olen)
1234 + unsigned long val;
1238 + while (ptr != NULL && i < olen)
1247 + ptr = osf_strchr(&obuf[i], OPTDEL);
1252 + i += (int)(ptr-&obuf[i]);
1259 + op = OSFOPT_SACKP;
1260 + ptr = osf_strchr(&obuf[i], OPTDEL);
1265 + i += (int)(ptr-&obuf[i]);
1273 + ptr = osf_strchr(&obuf[i], OPTDEL);
1278 + i += (int)(ptr-&obuf[i]);
1286 + ptr = osf_strchr(&obuf[i], OPTDEL);
1289 + switch (obuf[i+1])
1291 + case '%': wc = '%'; break;
1292 + case 'S': wc = 'S'; break;
1293 + case 'T': wc = 'T'; break;
1294 + default: wc = 0; break;
1300 + val = simple_strtoul(&obuf[i+2], NULL, 10);
1302 + val = simple_strtoul(&obuf[i+1], NULL, 10);
1303 + i += (int)(ptr-&obuf[i]);
1311 + ptr = osf_strchr(&obuf[i], OPTDEL);
1314 + if (obuf[i+1] == '%')
1319 + val = simple_strtoul(&obuf[i+2], NULL, 10);
1321 + val = simple_strtoul(&obuf[i+1], NULL, 10);
1322 + i += (int)(ptr-&obuf[i]);
1330 + ptr = osf_strchr(&obuf[i], OPTDEL);
1335 + i += (int)(ptr-&obuf[i]);
1342 + ptr = osf_strchr(&obuf[i], OPTDEL);
1346 + i += (int)(ptr-&obuf[i]);
1354 + opt[*optnum].kind = IANA_opts[op].kind;
1355 + opt[*optnum].length = IANA_opts[op].length;
1356 + opt[*optnum].wc.wc = wc;
1357 + opt[*optnum].wc.val = val;
1363 +static int osf_proc_read(char *buf, char **start, off_t off, int count, int *eof, void *data)
1365 + struct list_head *ent;
1366 + struct osf_finger *f = NULL;
1372 + read_lock_bh(&osf_lock);
1373 + list_for_each(ent, &finger_list)
1375 + f = list_entry(ent, struct osf_finger, flist);
1377 + log("%s [%s]", f->genre, f->details);
1379 + count += sprintf(buf+count, "%s - %s[%s] : %s",
1380 + f->genre, f->version,
1381 + f->subtype, f->details);
1386 + //count += sprintf(buf+count, " OPT: ");
1387 + for (i=0; i<f->opt_num; ++i)
1389 + //count += sprintf(buf+count, "%d.%c%lu; ",
1390 + // f->opt[i].kind, (f->opt[i].wc.wc)?f->opt[i].wc.wc:' ', f->opt[i].wc.val);
1391 + loga("%d.%c%lu; ",
1392 + f->opt[i].kind, (f->opt[i].wc.wc)?f->opt[i].wc.wc:' ', f->opt[i].wc.val);
1396 + count += sprintf(buf+count, "\n");
1398 + read_unlock_bh(&osf_lock);
1403 +static int osf_proc_write(struct file *file, const char *buffer, unsigned long count, void *data)
1407 + char obuf[MAXOPTSTRLEN];
1408 + struct osf_finger *finger;
1409 + struct list_head *ent, *n;
1411 + char *pbeg, *pend;
1413 + if (count == strlen(OSFFLUSH) && !strncmp(buffer, OSFFLUSH, strlen(OSFFLUSH)))
1416 + write_lock_bh(&osf_lock);
1417 + list_for_each_safe(ent, n, &finger_list)
1420 + finger = list_entry(ent, struct osf_finger, flist);
1421 + list_del(&finger->flist);
1422 + finger_free(finger);
1424 + write_unlock_bh(&osf_lock);
1426 + log("Flushed %d entries.\n", i);
1433 + for (i=0; i<count && buffer[i] != '\0'; ++i)
1434 + if (buffer[i] == ':')
1437 + if (cnt != 8 || i != count)
1439 + log("Wrong input line cnt=%d[8], len=%lu[%lu]\n",
1444 + memset(obuf, 0, sizeof(obuf));
1446 + finger = finger_alloc();
1449 + log("Failed to allocate new fingerprint entry.\n");
1453 + pbeg = (char *)buffer;
1454 + pend = osf_strchr(pbeg, OSFPDEL);
1458 + if (pbeg[0] == 'S')
1460 + finger->wss.wc = 'S';
1461 + if (pbeg[1] == '%')
1462 + finger->wss.val = simple_strtoul(pbeg+2, NULL, 10);
1463 + else if (pbeg[1] == '*')
1464 + finger->wss.val = 0;
1466 + finger->wss.val = simple_strtoul(pbeg+1, NULL, 10);
1468 + else if (pbeg[0] == 'T')
1470 + finger->wss.wc = 'T';
1471 + if (pbeg[1] == '%')
1472 + finger->wss.val = simple_strtoul(pbeg+2, NULL, 10);
1473 + else if (pbeg[1] == '*')
1474 + finger->wss.val = 0;
1476 + finger->wss.val = simple_strtoul(pbeg+1, NULL, 10);
1478 + if (isdigit(pbeg[0]))
1480 + finger->wss.wc = 0;
1481 + finger->wss.val = simple_strtoul(pbeg, NULL, 10);
1486 + pend = osf_strchr(pbeg, OSFPDEL);
1490 + finger->ttl = simple_strtoul(pbeg, NULL, 10);
1493 + pend = osf_strchr(pbeg, OSFPDEL);
1497 + finger->df = simple_strtoul(pbeg, NULL, 10);
1500 + pend = osf_strchr(pbeg, OSFPDEL);
1504 + finger->ss = simple_strtoul(pbeg, NULL, 10);
1508 + pend = osf_strchr(pbeg, OSFPDEL);
1512 + cnt = snprintf(obuf, sizeof(obuf), "%s", pbeg);
1516 + pend = osf_strchr(pbeg, OSFPDEL);
1520 + if (pbeg[0] == '@' || pbeg[0] == '*')
1521 + cnt = snprintf(finger->genre, sizeof(finger->genre), "%s", pbeg+1);
1523 + cnt = snprintf(finger->genre, sizeof(finger->genre), "%s", pbeg);
1527 + pend = osf_strchr(pbeg, OSFPDEL);
1531 + cnt = snprintf(finger->version, sizeof(finger->version), "%s", pbeg);
1535 + pend = osf_strchr(pbeg, OSFPDEL);
1539 + cnt = snprintf(finger->subtype, sizeof(finger->subtype), "%s", pbeg);
1543 + cnt = snprintf(finger->details,
1544 + ((count - (pbeg - buffer)+1) > MAXDETLEN)?MAXDETLEN:(count - (pbeg - buffer)+1),
1547 + log("%s - %s[%s] : %s\n",
1548 + finger->genre, finger->version,
1549 + finger->subtype, finger->details);
1551 + osf_parse_opt(finger->opt, &finger->opt_num, obuf, sizeof(obuf));
1554 + write_lock_bh(&osf_lock);
1555 + list_add_tail(&finger->flist, &finger_list);
1556 + write_unlock_bh(&osf_lock);
1561 +static int __init osf_init(void)
1564 + struct proc_dir_entry *p;
1566 + log("Startng OS fingerprint matching module.\n");
1568 + INIT_LIST_HEAD(&finger_list);
1570 + err = ipt_register_match(&osf_match);
1573 + log("Failed to register OS fingerprint matching module.\n");
1577 + p = create_proc_entry("sys/net/ipv4/osf", S_IFREG | 0644, NULL);
1580 + ipt_unregister_match(&osf_match);
1584 + p->write_proc = osf_proc_write;
1585 + p->read_proc = osf_proc_read;
1590 +static void __exit osf_fini(void)
1592 + struct list_head *ent, *n;
1593 + struct osf_finger *f;
1595 + remove_proc_entry("sys/net/ipv4/osf", NULL);
1596 + ipt_unregister_match(&osf_match);
1598 + list_for_each_safe(ent, n, &finger_list)
1600 + f = list_entry(ent, struct osf_finger, flist);
1601 + list_del(&f->flist);
1605 + log("OS fingerprint matching module finished.\n");
1608 +module_init(osf_init);
1609 +module_exit(osf_fini);
1611 +MODULE_LICENSE("GPL");
1612 +MODULE_AUTHOR("Evgeniy Polyakov <johnpol@2ka.mipt.ru>");
1613 +MODULE_DESCRIPTION("Passive OS fingerprint matching.");
1615 diff -Nur linux-2.6.1.org/net/ipv4/netfilter/ipt_psd.c linux-2.6.1/net/ipv4/netfilter/ipt_psd.c
1616 --- linux-2.6.1.org/net/ipv4/netfilter/ipt_psd.c 1970-01-01 01:00:00.000000000 +0100
1617 +++ linux-2.6.1/net/ipv4/netfilter/ipt_psd.c 2004-01-14 14:04:53.000000000 +0100
1620 + This is a module which is used for PSD (portscan detection)
1621 + Derived from scanlogd v2.1 written by Solar Designer <solar@false.com>
1622 + and LOG target module.
1624 + Copyright (C) 2000,2001 astaro AG
1626 + This file is distributed under the terms of the GNU General Public
1627 + License (GPL). Copies of the GPL can be obtained from:
1628 + ftp://prep.ai.mit.edu/pub/gnu/GPL
1630 + 2000-05-04 Markus Hennig <hennig@astaro.de> : initial
1631 + 2000-08-18 Dennis Koslowski <koslowski@astaro.de> : first release
1632 + 2000-12-01 Dennis Koslowski <koslowski@astaro.de> : UDP scans detection added
1633 + 2001-01-02 Dennis Koslowski <koslowski@astaro.de> : output modified
1634 + 2001-02-04 Jan Rekorajski <baggins@pld.org.pl> : converted from target to match
1637 +#include <linux/module.h>
1638 +#include <linux/skbuff.h>
1639 +#include <linux/ip.h>
1640 +#include <net/tcp.h>
1641 +#include <linux/spinlock.h>
1642 +#include <linux/netfilter_ipv4/ip_tables.h>
1643 +#include <linux/netfilter_ipv4/ipt_psd.h>
1646 +#define DEBUGP printk
1648 +#define DEBUGP(format, args...)
1651 +MODULE_LICENSE("GPL");
1652 +MODULE_AUTHOR("Dennis Koslowski <koslowski@astaro.com>");
1654 +#define HF_DADDR_CHANGING 0x01
1655 +#define HF_SPORT_CHANGING 0x02
1656 +#define HF_TOS_CHANGING 0x04
1657 +#define HF_TTL_CHANGING 0x08
1660 + * Information we keep per each target port
1663 + u_int16_t number; /* port number */
1664 + u_int8_t proto; /* protocol number */
1665 + u_int8_t and_flags; /* tcp ANDed flags */
1666 + u_int8_t or_flags; /* tcp ORed flags */
1670 + * Information we keep per each source address.
1673 + struct host *next; /* Next entry with the same hash */
1674 + clock_t timestamp; /* Last update time */
1675 + struct in_addr src_addr; /* Source address */
1676 + struct in_addr dest_addr; /* Destination address */
1677 + unsigned short src_port; /* Source port */
1678 + int count; /* Number of ports in the list */
1679 + int weight; /* Total weight of ports in the list */
1680 + struct port ports[SCAN_MAX_COUNT - 1]; /* List of ports */
1681 + unsigned char tos; /* TOS */
1682 + unsigned char ttl; /* TTL */
1683 + unsigned char flags; /* HF_ flags bitmask */
1687 + * State information.
1691 + struct host list[LIST_SIZE]; /* List of source addresses */
1692 + struct host *hash[HASH_SIZE]; /* Hash: pointers into the list */
1693 + int index; /* Oldest entry to be replaced */
1697 + * Convert an IP address into a hash table index.
1699 +static inline int hashfunc(struct in_addr addr)
1701 + unsigned int value;
1704 + value = addr.s_addr;
1708 + } while ((value >>= HASH_LOG));
1710 + return hash & (HASH_SIZE - 1);
1714 +ipt_psd_match(const struct sk_buff *pskb,
1715 + const struct net_device *in,
1716 + const struct net_device *out,
1717 + const void *matchinfo,
1720 + u_int16_t datalen,
1723 + struct iphdr *ip_hdr;
1724 + struct tcphdr *tcp_hdr;
1725 + struct in_addr addr;
1726 + u_int16_t src_port,dest_port;
1727 + u_int8_t tcp_flags, proto;
1729 + struct host *curr, *last, **head;
1730 + int hash, index, count;
1732 + /* Parameters from userspace */
1733 + const struct ipt_psd_info *psdinfo = matchinfo;
1736 + ip_hdr = pskb->nh.iph;
1738 + /* Sanity check */
1739 + if (ntohs(ip_hdr->frag_off) & IP_OFFSET) {
1740 + DEBUGP("PSD: sanity check failed\n");
1744 + /* TCP or UDP ? */
1745 + proto = ip_hdr->protocol;
1747 + if (proto != IPPROTO_TCP && proto != IPPROTO_UDP) {
1748 + DEBUGP("PSD: protocol not supported\n");
1752 + /* Get the source address, source & destination ports, and TCP flags */
1754 + addr.s_addr = ip_hdr->saddr;
1756 + tcp_hdr = (struct tcphdr*)((u_int32_t *)ip_hdr + ip_hdr->ihl);
1758 + /* Yep, it´s dirty */
1759 + src_port = tcp_hdr->source;
1760 + dest_port = tcp_hdr->dest;
1762 + if (proto == IPPROTO_TCP) {
1763 + tcp_flags = *((u_int8_t*)tcp_hdr + 13);
1769 + /* We're using IP address 0.0.0.0 for a special purpose here, so don't let
1770 + * them spoof us. [DHCP needs this feature - HW] */
1771 + if (!addr.s_addr) {
1772 + DEBUGP("PSD: spoofed source address (0.0.0.0)\n");
1776 + /* Use jiffies here not to depend on someone setting the time while we're
1777 + * running; we need to be careful with possible return value overflows. */
1780 + spin_lock(&state.lock);
1782 + /* Do we know this source address already? */
1785 + if ((curr = *(head = &state.hash[hash = hashfunc(addr)])))
1787 + if (curr->src_addr.s_addr == addr.s_addr) break;
1789 + if (curr->next) last = curr;
1790 + } while ((curr = curr->next));
1794 + /* We know this address, and the entry isn't too old. Update it. */
1795 + if (now - curr->timestamp <= (psdinfo->delay_threshold*HZ)/100 &&
1796 + time_after_eq(now, curr->timestamp)) {
1798 + /* Just update the appropriate list entry if we've seen this port already */
1799 + for (index = 0; index < curr->count; index++) {
1800 + if (curr->ports[index].number == dest_port) {
1801 + curr->ports[index].proto = proto;
1802 + curr->ports[index].and_flags &= tcp_flags;
1803 + curr->ports[index].or_flags |= tcp_flags;
1804 + goto out_no_match;
1808 + /* TCP/ACK and/or TCP/RST to a new port? This could be an outgoing connection. */
1809 + if (proto == IPPROTO_TCP && (tcp_hdr->ack || tcp_hdr->rst))
1810 + goto out_no_match;
1812 + /* Packet to a new port, and not TCP/ACK: update the timestamp */
1813 + curr->timestamp = now;
1815 + /* Logged this scan already? Then drop the packet. */
1816 + if (curr->weight >= psdinfo->weight_threshold)
1819 + /* Specify if destination address, source port, TOS or TTL are not fixed */
1820 + if (curr->dest_addr.s_addr != ip_hdr->daddr)
1821 + curr->flags |= HF_DADDR_CHANGING;
1822 + if (curr->src_port != src_port)
1823 + curr->flags |= HF_SPORT_CHANGING;
1824 + if (curr->tos != ip_hdr->tos)
1825 + curr->flags |= HF_TOS_CHANGING;
1826 + if (curr->ttl != ip_hdr->ttl)
1827 + curr->flags |= HF_TTL_CHANGING;
1829 + /* Update the total weight */
1830 + curr->weight += (ntohs(dest_port) < 1024) ?
1831 + psdinfo->lo_ports_weight : psdinfo->hi_ports_weight;
1833 + /* Got enough destination ports to decide that this is a scan? */
1834 + /* Then log it and drop the packet. */
1835 + if (curr->weight >= psdinfo->weight_threshold)
1838 + /* Remember the new port */
1839 + if (curr->count < SCAN_MAX_COUNT) {
1840 + curr->ports[curr->count].number = dest_port;
1841 + curr->ports[curr->count].proto = proto;
1842 + curr->ports[curr->count].and_flags = tcp_flags;
1843 + curr->ports[curr->count].or_flags = tcp_flags;
1847 + goto out_no_match;
1850 + /* We know this address, but the entry is outdated. Mark it unused, and
1851 + * remove from the hash table. We'll allocate a new entry instead since
1852 + * this one might get re-used too soon. */
1853 + curr->src_addr.s_addr = 0;
1855 + last->next = last->next->next;
1857 + *head = (*head)->next;
1861 + /* We don't need an ACK from a new source address */
1862 + if (proto == IPPROTO_TCP && tcp_hdr->ack)
1863 + goto out_no_match;
1865 + /* Got too many source addresses with the same hash value? Then remove the
1866 + * oldest one from the hash table, so that they can't take too much of our
1867 + * CPU time even with carefully chosen spoofed IP addresses. */
1868 + if (count >= HASH_MAX && last) last->next = NULL;
1870 + /* We're going to re-use the oldest list entry, so remove it from the hash
1871 + * table first (if it is really already in use, and isn't removed from the
1872 + * hash table already because of the HASH_MAX check above). */
1874 + /* First, find it */
1875 + if (state.list[state.index].src_addr.s_addr)
1876 + head = &state.hash[hashfunc(state.list[state.index].src_addr)];
1880 + if ((curr = *head))
1882 + if (curr == &state.list[state.index]) break;
1884 + } while ((curr = curr->next));
1886 + /* Then, remove it */
1889 + last->next = last->next->next;
1891 + *head = (*head)->next;
1894 + /* Get our list entry */
1895 + curr = &state.list[state.index++];
1896 + if (state.index >= LIST_SIZE) state.index = 0;
1898 + /* Link it into the hash table */
1899 + head = &state.hash[hash];
1900 + curr->next = *head;
1903 + /* And fill in the fields */
1904 + curr->timestamp = now;
1905 + curr->src_addr = addr;
1906 + curr->dest_addr.s_addr = ip_hdr->daddr;
1907 + curr->src_port = src_port;
1909 + curr->weight = (ntohs(dest_port) < 1024) ?
1910 + psdinfo->lo_ports_weight : psdinfo->hi_ports_weight;
1911 + curr->ports[0].number = dest_port;
1912 + curr->ports[0].proto = proto;
1913 + curr->ports[0].and_flags = tcp_flags;
1914 + curr->ports[0].or_flags = tcp_flags;
1915 + curr->tos = ip_hdr->tos;
1916 + curr->ttl = ip_hdr->ttl;
1919 + spin_unlock(&state.lock);
1923 + spin_unlock(&state.lock);
1927 +static int ipt_psd_checkentry(const char *tablename,
1928 + const struct ipt_ip *e,
1930 + unsigned int matchsize,
1931 + unsigned int hook_mask)
1933 +/* const struct ipt_psd_info *psdinfo = targinfo;*/
1935 + /* we accept TCP only */
1936 +/* if (e->ip.proto != IPPROTO_TCP) { */
1937 +/* DEBUGP("PSD: specified protocol may be TCP only\n"); */
1941 + if (matchsize != IPT_ALIGN(sizeof(struct ipt_psd_info))) {
1942 + DEBUGP("PSD: matchsize %u != %u\n",
1944 + IPT_ALIGN(sizeof(struct ipt_psd_info)));
1951 +static struct ipt_match ipt_psd_reg = {
1953 + .match = ipt_psd_match,
1954 + .checkentry = ipt_psd_checkentry,
1955 + .me = THIS_MODULE,
1958 +static int __init init(void)
1960 + if (ipt_register_match(&ipt_psd_reg))
1963 + memset(&state, 0, sizeof(state));
1965 + spin_lock_init(&(state.lock));
1967 + printk("netfilter PSD loaded - (c) astaro AG\n");
1971 +static void __exit fini(void)
1973 + ipt_unregister_match(&ipt_psd_reg);
1974 + printk("netfilter PSD unloaded - (c) astaro AG\n");
1979 diff -Nur linux-2.6.1.org/net/ipv4/netfilter/ipt_quota.c linux-2.6.1/net/ipv4/netfilter/ipt_quota.c
1980 --- linux-2.6.1.org/net/ipv4/netfilter/ipt_quota.c 1970-01-01 01:00:00.000000000 +0100
1981 +++ linux-2.6.1/net/ipv4/netfilter/ipt_quota.c 2004-01-14 14:04:22.000000000 +0100
1984 + * netfilter module to enforce network quotas
1986 + * Sam Johnston <samj@samj.net>
1988 +#include <linux/module.h>
1989 +#include <linux/skbuff.h>
1990 +#include <linux/spinlock.h>
1991 +#include <linux/interrupt.h>
1993 +#include <linux/netfilter_ipv4/ip_tables.h>
1994 +#include <linux/netfilter_ipv4/ipt_quota.h>
1996 +MODULE_LICENSE("GPL");
1998 +static spinlock_t quota_lock = SPIN_LOCK_UNLOCKED;
2001 +match(const struct sk_buff *skb,
2002 + const struct net_device *in,
2003 + const struct net_device *out,
2004 + const void *matchinfo,
2005 + int offset, const void *hdr, u_int16_t datalen, int *hotdrop)
2008 + struct ipt_quota_info *q = (struct ipt_quota_info *) matchinfo;
2010 + spin_lock_bh("a_lock);
2012 + if (q->quota >= datalen) {
2013 + /* we can afford this one */
2014 + q->quota -= datalen;
2015 + spin_unlock_bh("a_lock);
2017 +#ifdef DEBUG_IPT_QUOTA
2018 + printk("IPT Quota OK: %llu datlen %d \n", q->quota, datalen);
2023 + /* so we do not allow even small packets from now on */
2026 +#ifdef DEBUG_IPT_QUOTA
2027 + printk("IPT Quota Failed: %llu datlen %d \n", q->quota, datalen);
2030 + spin_unlock_bh("a_lock);
2035 +checkentry(const char *tablename,
2036 + const struct ipt_ip *ip,
2037 + void *matchinfo, unsigned int matchsize, unsigned int hook_mask)
2039 + /* TODO: spinlocks? sanity checks? */
2040 + if (matchsize != IPT_ALIGN(sizeof (struct ipt_quota_info)))
2046 +static struct ipt_match quota_match = {
2049 + .checkentry = &checkentry,
2050 + .me = THIS_MODULE,
2056 + return ipt_register_match("a_match);
2062 + ipt_unregister_match("a_match);
2068 diff -Nur linux-2.6.1.org/net/ipv4/netfilter/ipt_time.c linux-2.6.1/net/ipv4/netfilter/ipt_time.c
2069 --- linux-2.6.1.org/net/ipv4/netfilter/ipt_time.c 1970-01-01 01:00:00.000000000 +0100
2070 +++ linux-2.6.1/net/ipv4/netfilter/ipt_time.c 2004-01-14 14:05:44.000000000 +0100
2073 + This is a module which is used for time matching
2074 + It is using some modified code from dietlibc (localtime() function)
2075 + that you can find at http://www.fefe.de/dietlibc/
2076 + This file is distributed under the terms of the GNU General Public
2077 + License (GPL). Copies of the GPL can be obtained from: ftp://prep.ai.mit.edu/pub/gnu/GPL
2078 + 2001-05-04 Fabrice MARIE <fabrice@netfilter.org> : initial development.
2079 + 2001-21-05 Fabrice MARIE <fabrice@netfilter.org> : bug fix in the match code,
2080 + thanks to "Zeng Yu" <zengy@capitel.com.cn> for bug report.
2081 + 2001-26-09 Fabrice MARIE <fabrice@netfilter.org> : force the match to be in LOCAL_IN or PRE_ROUTING only.
2082 + 2001-30-11 Fabrice : added the possibility to use the match in FORWARD/OUTPUT with a little hack,
2083 + added Nguyen Dang Phuoc Dong <dongnd@tlnet.com.vn> patch to support timezones.
2086 +#include <linux/module.h>
2087 +#include <linux/skbuff.h>
2088 +#include <linux/netfilter_ipv4/ip_tables.h>
2089 +#include <linux/netfilter_ipv4/ipt_time.h>
2090 +#include <linux/time.h>
2092 +MODULE_AUTHOR("Fabrice MARIE <fabrice@netfilter.org>");
2093 +MODULE_DESCRIPTION("Match arrival timestamp");
2094 +MODULE_LICENSE("GPL");
2098 + int tm_sec; /* Seconds. [0-60] (1 leap second) */
2099 + int tm_min; /* Minutes. [0-59] */
2100 + int tm_hour; /* Hours. [0-23] */
2101 + int tm_mday; /* Day. [1-31] */
2102 + int tm_mon; /* Month. [0-11] */
2103 + int tm_year; /* Year - 1900. */
2104 + int tm_wday; /* Day of week. [0-6] */
2105 + int tm_yday; /* Days in year.[0-365] */
2106 + int tm_isdst; /* DST. [-1/0/1]*/
2108 + long int tm_gmtoff; /* we don't care, we count from GMT */
2109 + const char *tm_zone; /* we don't care, we count from GMT */
2113 +localtime(const time_t *timepr, struct tm *r);
2116 +match(const struct sk_buff *skb,
2117 + const struct net_device *in,
2118 + const struct net_device *out,
2119 + const void *matchinfo,
2122 + u_int16_t datalen,
2125 + const struct ipt_time_info *info = matchinfo; /* match info for rule */
2126 + struct tm currenttime; /* time human readable */
2127 + u_int8_t days_of_week[7] = {64, 32, 16, 8, 4, 2, 1};
2128 + u_int16_t packet_time;
2129 + struct timeval kerneltimeval;
2130 + time_t packet_local_time;
2132 + /* if kerneltime=1, we don't read the skb->timestamp but kernel time instead */
2133 + if (info->kerneltime)
2135 + do_gettimeofday(&kerneltimeval);
2136 + packet_local_time = kerneltimeval.tv_sec;
2139 + packet_local_time = skb->stamp.tv_sec;
2141 + /* Transform the timestamp of the packet, in a human readable form */
2142 + localtime(&packet_local_time, ¤ttime);
2144 + /* check if we match this timestamp, we start by the days... */
2145 + if ((days_of_week[currenttime.tm_wday] & info->days_match) != days_of_week[currenttime.tm_wday])
2146 + return 0; /* the day doesn't match */
2148 + /* ... check the time now */
2149 + packet_time = (currenttime.tm_hour * 60) + currenttime.tm_min;
2150 + if ((packet_time < info->time_start) || (packet_time > info->time_stop))
2153 + /* here we match ! */
2158 +checkentry(const char *tablename,
2159 + const struct ipt_ip *ip,
2161 + unsigned int matchsize,
2162 + unsigned int hook_mask)
2164 + struct ipt_time_info *info = matchinfo; /* match info for rule */
2166 + /* First, check that we are in the correct hook */
2167 + /* PRE_ROUTING, LOCAL_IN or FROWARD */
2169 + & ~((1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_LOCAL_IN) | (1 << NF_IP_FORWARD) | (1 << NF_IP_LOCAL_OUT)))
2171 + printk("ipt_time: error, only valid for PRE_ROUTING, LOCAL_IN, FORWARD and OUTPUT)\n");
2174 + /* we use the kerneltime if we are in forward or output */
2175 + info->kerneltime = 1;
2176 + if (hook_mask & ~((1 << NF_IP_FORWARD) | (1 << NF_IP_LOCAL_OUT)))
2177 + /* if not, we use the skb time */
2178 + info->kerneltime = 0;
2180 + /* Check the size */
2181 + if (matchsize != IPT_ALIGN(sizeof(struct ipt_time_info)))
2183 + /* Now check the coherence of the data ... */
2184 + if ((info->time_start > 1439) || /* 23*60+59 = 1439*/
2185 + (info->time_stop > 1439))
2187 + printk(KERN_WARNING "ipt_time: invalid argument\n");
2194 +static struct ipt_match time_match = {
2197 + .checkentry = &checkentry,
2198 + .me = THIS_MODULE,
2201 +static int __init init(void)
2203 + printk("ipt_time loading\n");
2204 + return ipt_register_match(&time_match);
2207 +static void __exit fini(void)
2209 + ipt_unregister_match(&time_match);
2210 + printk("ipt_time unloaded\n");
2217 +/* The part below is borowed and modified from dietlibc */
2219 +/* seconds per day */
2220 +#define SPD 24*60*60
2223 +localtime(const time_t *timepr, struct tm *r) {
2226 + extern struct timezone sys_tz;
2227 + const unsigned int __spm[12] =
2234 + (31+28+31+30+31+30),
2235 + (31+28+31+30+31+30+31),
2236 + (31+28+31+30+31+30+31+31),
2237 + (31+28+31+30+31+30+31+31+30),
2238 + (31+28+31+30+31+30+31+31+30+31),
2239 + (31+28+31+30+31+30+31+31+30+31+30),
2241 + register time_t work;
2243 + timep = (*timepr) - (sys_tz.tz_minuteswest * 60);
2245 + r->tm_sec=work%60; work/=60;
2246 + r->tm_min=work%60; r->tm_hour=work/60;
2248 + r->tm_wday=(4+work)%7;
2249 + for (i=1970; ; ++i) {
2250 + register time_t k= (!(i%4) && ((i%100) || !(i%400)))?366:365;
2256 + r->tm_year=i-1900;
2257 + for (i=11; i && __spm[i]>work; --i) ;
2259 + r->tm_mday=work-__spm[i]+1;
2261 diff -Nur linux-2.6.1.org/net/ipv4/netfilter/ipt_u32.c linux-2.6.1/net/ipv4/netfilter/ipt_u32.c
2262 --- linux-2.6.1.org/net/ipv4/netfilter/ipt_u32.c 1970-01-01 01:00:00.000000000 +0100
2263 +++ linux-2.6.1/net/ipv4/netfilter/ipt_u32.c 2004-01-14 14:05:13.000000000 +0100
2265 +/* Kernel module to match u32 packet content. */
2268 +U32 tests whether quantities of up to 4 bytes extracted from a packet
2269 +have specified values. The specification of what to extract is general
2270 +enough to find data at given offsets from tcp headers or payloads.
2273 + The argument amounts to a program in a small language described below.
2274 + tests := location = value | tests && location = value
2275 + value := range | value , range
2276 + range := number | number : number
2277 + a single number, n, is interpreted the same as n:n
2278 + n:m is interpreted as the range of numbers >=n and <=m
2279 + location := number | location operator number
2280 + operator := & | << | >> | @
2282 + The operators &, <<, >>, && mean the same as in c. The = is really a set
2283 + membership operator and the value syntax describes a set. The @ operator
2284 + is what allows moving to the next header and is described further below.
2286 + *** Until I can find out how to avoid it, there are some artificial limits
2287 + on the size of the tests:
2288 + - no more than 10 ='s (and 9 &&'s) in the u32 argument
2289 + - no more than 10 ranges (and 9 commas) per value
2290 + - no more than 10 numbers (and 9 operators) per location
2292 + To describe the meaning of location, imagine the following machine that
2293 + interprets it. There are three registers:
2294 + A is of type char*, initially the address of the IP header
2295 + B and C are unsigned 32 bit integers, initially zero
2297 + The instructions are:
2298 + number B = number;
2299 + C = (*(A+B)<<24)+(*(A+B+1)<<16)+(*(A+B+2)<<8)+*(A+B+3)
2300 + &number C = C&number
2301 + <<number C = C<<number
2302 + >>number C = C>>number
2303 + @number A = A+C; then do the instruction number
2304 + Any access of memory outside [skb->head,skb->end] causes the match to fail.
2305 + Otherwise the result of the computation is the final value of C.
2307 + Whitespace is allowed but not required in the tests.
2308 + However the characters that do occur there are likely to require
2309 + shell quoting, so it's a good idea to enclose the arguments in quotes.
2312 + match IP packets with total length >= 256
2313 + The IP header contains a total length field in bytes 2-3.
2314 + --u32 "0&0xFFFF=0x100:0xFFFF"
2316 + AND that with FFFF (giving bytes 2-3),
2317 + and test whether that's in the range [0x100:0xFFFF]
2319 +Example: (more realistic, hence more complicated)
2320 + match icmp packets with icmp type 0
2321 + First test that it's an icmp packet, true iff byte 9 (protocol) = 1
2322 + --u32 "6&0xFF=1 && ...
2323 + read bytes 6-9, use & to throw away bytes 6-8 and compare the result to 1
2324 + Next test that it's not a fragment.
2325 + (If so it might be part of such a packet but we can't always tell.)
2326 + n.b. This test is generally needed if you want to match anything
2327 + beyond the IP header.
2328 + The last 6 bits of byte 6 and all of byte 7 are 0 iff this is a complete
2329 + packet (not a fragment). Alternatively, you can allow first fragments
2330 + by only testing the last 5 bits of byte 6.
2331 + ... 4&0x3FFF=0 && ...
2332 + Last test: the first byte past the IP header (the type) is 0
2333 + This is where we have to use the @syntax. The length of the IP header
2334 + (IHL) in 32 bit words is stored in the right half of byte 0 of the
2336 + ... 0>>22&0x3C@0>>24=0"
2337 + The first 0 means read bytes 0-3,
2338 + >>22 means shift that 22 bits to the right. Shifting 24 bits would give
2339 + the first byte, so only 22 bits is four times that plus a few more bits.
2340 + &3C then eliminates the two extra bits on the right and the first four
2341 + bits of the first byte.
2342 + For instance, if IHL=5 then the IP header is 20 (4 x 5) bytes long.
2343 + In this case bytes 0-1 are (in binary) xxxx0101 yyzzzzzz,
2344 + >>22 gives the 10 bit value xxxx0101yy and &3C gives 010100.
2345 + @ means to use this number as a new offset into the packet, and read
2346 + four bytes starting from there. This is the first 4 bytes of the icmp
2347 + payload, of which byte 0 is the icmp type. Therefore we simply shift
2348 + the value 24 to the right to throw out all but the first byte and compare
2349 + the result with 0.
2352 + tcp payload bytes 8-12 is any of 1, 2, 5 or 8
2353 + First we test that the packet is a tcp packet (similar to icmp).
2354 + --u32 "6&0xFF=6 && ...
2355 + Next, test that it's not a fragment (same as above).
2356 + ... 0>>22&0x3C@12>>26&0x3C@8=1,2,5,8"
2357 + 0>>22&3C as above computes the number of bytes in the IP header.
2358 + @ makes this the new offset into the packet, which is the start of the
2359 + tcp header. The length of the tcp header (again in 32 bit words) is
2360 + the left half of byte 12 of the tcp header. The 12>>26&3C
2361 + computes this length in bytes (similar to the IP header before).
2362 + @ makes this the new offset, which is the start of the tcp payload.
2363 + Finally 8 reads bytes 8-12 of the payload and = checks whether the
2364 + result is any of 1, 2, 5 or 8
2367 +#include <linux/module.h>
2368 +#include <linux/skbuff.h>
2370 +#include <linux/netfilter_ipv4/ipt_u32.h>
2371 +#include <linux/netfilter_ipv4/ip_tables.h>
2373 +/* #include <asm-i386/timex.h> for timing */
2375 +MODULE_AUTHOR("Don Cohen <don@isis.cs3-inc.com>");
2376 +MODULE_DESCRIPTION("IP tables u32 matching module");
2377 +MODULE_LICENSE("GPL");
2380 +match(const struct sk_buff *skb,
2381 + const struct net_device *in,
2382 + const struct net_device *out,
2383 + const void *matchinfo,
2386 + u_int16_t datalen,
2389 + const struct ipt_u32 *data = matchinfo;
2391 + unsigned char* origbase = (char*)skb->nh.iph;
2392 + unsigned char* base = origbase;
2393 + unsigned char* head = skb->head;
2394 + unsigned char* end = skb->end;
2396 + u_int32_t pos, val;
2397 + /* unsigned long long cycles1, cycles2, cycles3, cycles4;
2398 + cycles1 = get_cycles(); */
2400 + for (testind=0; testind < data->ntests; testind++) {
2401 + base = origbase; /* reset for each test */
2402 + pos = data->tests[testind].location[0].number;
2403 + if (base+pos+3 > end || base+pos < head)
2405 + val = (base[pos]<<24) + (base[pos+1]<<16) +
2406 + (base[pos+2]<<8) + base[pos+3];
2407 + nnums = data->tests[testind].nnums;
2408 + for (i=1; i < nnums; i++) {
2409 + u_int32_t number = data->tests[testind].location[i].number;
2410 + switch (data->tests[testind].location[i].nextop) {
2412 + val = val & number;
2414 + case IPT_U32_LEFTSH:
2415 + val = val << number;
2417 + case IPT_U32_RIGHTSH:
2418 + val = val >> number;
2421 + base = base + val;
2423 + if (base+pos+3 > end || base+pos < head)
2425 + val = (base[pos]<<24) + (base[pos+1]<<16) +
2426 + (base[pos+2]<<8) + base[pos+3];
2430 + nvals = data->tests[testind].nvalues;
2431 + for (i=0; i < nvals; i++) {
2432 + if ((data->tests[testind].value[i].min <= val) &&
2433 + (val <= data->tests[testind].value[i].max)) {
2437 + if (i >= data->tests[testind].nvalues) {
2438 + /* cycles2 = get_cycles();
2439 + printk("failed %d in %d cycles\n", testind,
2440 + cycles2-cycles1); */
2444 + /* cycles2 = get_cycles();
2445 + printk("succeeded in %d cycles\n", cycles2-cycles1); */
2450 +checkentry(const char *tablename,
2451 + const struct ipt_ip *ip,
2453 + unsigned int matchsize,
2454 + unsigned int hook_mask)
2456 + if (matchsize != IPT_ALIGN(sizeof(struct ipt_u32)))
2461 +static struct ipt_match u32_match = {
2464 + .checkenrty = &checkentry,
2465 + .me = THIS_MODULE,
2468 +static int __init init(void)
2470 + return ipt_register_match(&u32_match);
2473 +static void __exit fini(void)
2475 + ipt_unregister_match(&u32_match);