1 diff -Nur linux-2.6.6-rc1.org/include/linux/netfilter_ipv4/ip_pool.h linux-2.6.6-rc1/include/linux/netfilter_ipv4/ip_pool.h
2 --- linux-2.6.6-rc1.org/include/linux/netfilter_ipv4/ip_pool.h 1970-01-01 01:00:00.000000000 +0100
3 +++ linux-2.6.6-rc1/include/linux/netfilter_ipv4/ip_pool.h 2004-04-19 10:08:36.000000000 +0200
8 +/***************************************************************************/
9 +/* This program is free software; you can redistribute it and/or modify */
10 +/* it under the terms of the GNU General Public License as published by */
11 +/* the Free Software Foundation; either version 2 of the License, or */
12 +/* (at your option) any later version. */
14 +/* This program is distributed in the hope that it will be useful, */
15 +/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
16 +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
17 +/* GNU General Public License for more details. */
19 +/* You should have received a copy of the GNU General Public License */
20 +/* along with this program; if not, write to the Free Software */
21 +/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA*/
22 +/***************************************************************************/
24 +/* A sockopt of such quality has hardly ever been seen before on the open
25 + * market! This little beauty, hardly ever used: above 64, so it's
26 + * traditionally used for firewalling, not touched (even once!) by the
27 + * 2.0, 2.2 and 2.4 kernels!
29 + * Comes with its own certificate of authenticity, valid anywhere in the
34 +#define SO_IP_POOL 81
36 +typedef int ip_pool_t; /* pool index */
37 +#define IP_POOL_NONE ((ip_pool_t)-1)
39 +struct ip_pool_request {
46 +/* NOTE: I deliberately break the first cut ippool utility. Nobody uses it. */
48 +#define IP_POOL_BAD001 0x00000010
50 +#define IP_POOL_FLUSH 0x00000011 /* req.index, no arguments */
51 +#define IP_POOL_INIT 0x00000012 /* from addr to addr2 incl. */
52 +#define IP_POOL_DESTROY 0x00000013 /* req.index, no arguments */
53 +#define IP_POOL_ADD_ADDR 0x00000014 /* add addr to pool */
54 +#define IP_POOL_DEL_ADDR 0x00000015 /* del addr from pool */
55 +#define IP_POOL_HIGH_NR 0x00000016 /* result in req.index */
56 +#define IP_POOL_LOOKUP 0x00000017 /* result in addr and addr2 */
57 +#define IP_POOL_USAGE 0x00000018 /* result in addr */
58 +#define IP_POOL_TEST_ADDR 0x00000019 /* result (0/1) returned */
62 +/* NOTE: ip_pool_match() and ip_pool_mod() expect ADDR to be host byte order */
63 +extern int ip_pool_match(ip_pool_t pool, u_int32_t addr);
64 +extern int ip_pool_mod(ip_pool_t pool, u_int32_t addr, int isdel);
68 +#endif /*_IP_POOL_H*/
69 diff -Nur linux-2.6.6-rc1.org/include/linux/netfilter_ipv4/ipt_TTL.h linux-2.6.6-rc1/include/linux/netfilter_ipv4/ipt_TTL.h
70 --- linux-2.6.6-rc1.org/include/linux/netfilter_ipv4/ipt_TTL.h 1970-01-01 01:00:00.000000000 +0100
71 +++ linux-2.6.6-rc1/include/linux/netfilter_ipv4/ipt_TTL.h 2004-04-19 10:08:28.000000000 +0200
73 +/* TTL modification module for IP tables
74 + * (C) 2000 by Harald Welte <laforge@gnumonks.org> */
85 +#define IPT_TTL_MAXMODE IPT_TTL_DEC
87 +struct ipt_TTL_info {
94 diff -Nur linux-2.6.6-rc1.org/include/linux/netfilter_ipv4/ipt_connlimit.h linux-2.6.6-rc1/include/linux/netfilter_ipv4/ipt_connlimit.h
95 --- linux-2.6.6-rc1.org/include/linux/netfilter_ipv4/ipt_connlimit.h 1970-01-01 01:00:00.000000000 +0100
96 +++ linux-2.6.6-rc1/include/linux/netfilter_ipv4/ipt_connlimit.h 2004-04-19 10:08:29.000000000 +0200
98 +#ifndef _IPT_CONNLIMIT_H
99 +#define _IPT_CONNLIMIT_H
101 +struct ipt_connlimit_data;
103 +struct ipt_connlimit_info {
107 + struct ipt_connlimit_data *data;
109 +#endif /* _IPT_CONNLIMIT_H */
110 diff -Nur linux-2.6.6-rc1.org/include/linux/netfilter_ipv4/ipt_dstlimit.h linux-2.6.6-rc1/include/linux/netfilter_ipv4/ipt_dstlimit.h
111 --- linux-2.6.6-rc1.org/include/linux/netfilter_ipv4/ipt_dstlimit.h 1970-01-01 01:00:00.000000000 +0100
112 +++ linux-2.6.6-rc1/include/linux/netfilter_ipv4/ipt_dstlimit.h 2004-04-19 10:08:30.000000000 +0200
114 +#ifndef _IPT_DSTLIMIT_H
115 +#define _IPT_DSTLIMIT_H
117 +/* timings are in milliseconds. */
118 +#define IPT_DSTLIMIT_SCALE 10000
119 +/* 1/10,000 sec period => max of 10,000/sec. Min rate is then 429490
120 + seconds, or one every 59 hours. */
122 +/* details of this structure hidden by the implementation */
123 +struct ipt_dstlimit_htable;
125 +#define IPT_DSTLIMIT_HASH_DIP 0x0001
126 +#define IPT_DSTLIMIT_HASH_DPT 0x0002
127 +#define IPT_DSTLIMIT_HASH_SIP 0x0004
129 +struct dstlimit_cfg {
130 + u_int32_t mode; /* bitmask of IPT_DSTLIMIT_HASH_* */
131 + u_int32_t avg; /* Average secs between packets * scale */
132 + u_int32_t burst; /* Period multiplier for upper limit. */
134 + /* user specified */
135 + u_int32_t size; /* how many buckets */
136 + u_int32_t max; /* max number of entries */
137 + u_int32_t gc_interval; /* gc interval */
138 + u_int32_t expire; /* when do entries expire? */
141 +struct ipt_dstlimit_info {
142 + char name [IFNAMSIZ]; /* name */
143 + struct dstlimit_cfg cfg;
144 + struct ipt_dstlimit_htable *hinfo;
146 + /* Used internally by the kernel */
149 + struct ipt_dstlimit_info *master;
152 +#endif /*_IPT_DSTLIMIT_H*/
153 diff -Nur linux-2.6.6-rc1.org/include/linux/netfilter_ipv4/ipt_fuzzy.h linux-2.6.6-rc1/include/linux/netfilter_ipv4/ipt_fuzzy.h
154 --- linux-2.6.6-rc1.org/include/linux/netfilter_ipv4/ipt_fuzzy.h 1970-01-01 01:00:00.000000000 +0100
155 +++ linux-2.6.6-rc1/include/linux/netfilter_ipv4/ipt_fuzzy.h 2004-04-19 10:08:31.000000000 +0200
157 +#ifndef _IPT_FUZZY_H
158 +#define _IPT_FUZZY_H
160 +#include <linux/param.h>
161 +#include <linux/types.h>
163 +#define MAXFUZZYRATE 10000000
164 +#define MINFUZZYRATE 3
166 +struct ipt_fuzzy_info {
167 + u_int32_t minimum_rate;
168 + u_int32_t maximum_rate;
169 + u_int32_t packets_total;
170 + u_int32_t bytes_total;
171 + u_int32_t previous_time;
172 + u_int32_t present_time;
173 + u_int32_t mean_rate;
174 + u_int8_t acceptance_rate;
177 +#endif /*_IPT_FUZZY_H*/
178 diff -Nur linux-2.6.6-rc1.org/include/linux/netfilter_ipv4/ipt_ipv4options.h linux-2.6.6-rc1/include/linux/netfilter_ipv4/ipt_ipv4options.h
179 --- linux-2.6.6-rc1.org/include/linux/netfilter_ipv4/ipt_ipv4options.h 1970-01-01 01:00:00.000000000 +0100
180 +++ linux-2.6.6-rc1/include/linux/netfilter_ipv4/ipt_ipv4options.h 2004-04-19 10:08:32.000000000 +0200
182 +#ifndef __ipt_ipv4options_h_included__
183 +#define __ipt_ipv4options_h_included__
185 +#define IPT_IPV4OPTION_MATCH_SSRR 0x01 /* For strict source routing */
186 +#define IPT_IPV4OPTION_MATCH_LSRR 0x02 /* For loose source routing */
187 +#define IPT_IPV4OPTION_DONT_MATCH_SRR 0x04 /* any source routing */
188 +#define IPT_IPV4OPTION_MATCH_RR 0x08 /* For Record route */
189 +#define IPT_IPV4OPTION_DONT_MATCH_RR 0x10
190 +#define IPT_IPV4OPTION_MATCH_TIMESTAMP 0x20 /* For timestamp request */
191 +#define IPT_IPV4OPTION_DONT_MATCH_TIMESTAMP 0x40
192 +#define IPT_IPV4OPTION_MATCH_ROUTER_ALERT 0x80 /* For router-alert */
193 +#define IPT_IPV4OPTION_DONT_MATCH_ROUTER_ALERT 0x100
194 +#define IPT_IPV4OPTION_MATCH_ANY_OPT 0x200 /* match packet with any option */
195 +#define IPT_IPV4OPTION_DONT_MATCH_ANY_OPT 0x400 /* match packet with no option */
197 +struct ipt_ipv4options_info {
202 +#endif /* __ipt_ipv4options_h_included__ */
203 diff -Nur linux-2.6.6-rc1.org/include/linux/netfilter_ipv4/ipt_mport.h linux-2.6.6-rc1/include/linux/netfilter_ipv4/ipt_mport.h
204 --- linux-2.6.6-rc1.org/include/linux/netfilter_ipv4/ipt_mport.h 1970-01-01 01:00:00.000000000 +0100
205 +++ linux-2.6.6-rc1/include/linux/netfilter_ipv4/ipt_mport.h 2004-04-19 10:08:33.000000000 +0200
207 +#ifndef _IPT_MPORT_H
208 +#define _IPT_MPORT_H
209 +#include <linux/netfilter_ipv4/ip_tables.h>
211 +#define IPT_MPORT_SOURCE (1<<0)
212 +#define IPT_MPORT_DESTINATION (1<<1)
213 +#define IPT_MPORT_EITHER (IPT_MPORT_SOURCE|IPT_MPORT_DESTINATION)
215 +#define IPT_MULTI_PORTS 15
217 +/* Must fit inside union ipt_matchinfo: 32 bytes */
218 +/* every entry in ports[] except for the last one has one bit in pflags
219 + * associated with it. If this bit is set, the port is the first port of
220 + * a portrange, with the next entry being the last.
221 + * End of list is marked with pflags bit set and port=65535.
222 + * If 14 ports are used (last one does not have a pflag), the last port
223 + * is repeated to fill the last entry in ports[] */
226 + u_int8_t flags:2; /* Type of comparison */
227 + u_int16_t pflags:14; /* Port flags */
228 + u_int16_t ports[IPT_MULTI_PORTS]; /* Ports */
230 +#endif /*_IPT_MPORT_H*/
231 diff -Nur linux-2.6.6-rc1.org/include/linux/netfilter_ipv4/ipt_nth.h linux-2.6.6-rc1/include/linux/netfilter_ipv4/ipt_nth.h
232 --- linux-2.6.6-rc1.org/include/linux/netfilter_ipv4/ipt_nth.h 1970-01-01 01:00:00.000000000 +0100
233 +++ linux-2.6.6-rc1/include/linux/netfilter_ipv4/ipt_nth.h 2004-04-19 10:08:34.000000000 +0200
238 +#include <linux/param.h>
239 +#include <linux/types.h>
241 +#ifndef IPT_NTH_NUM_COUNTERS
242 +#define IPT_NTH_NUM_COUNTERS 16
245 +struct ipt_nth_info {
253 +#endif /*_IPT_NTH_H*/
254 diff -Nur linux-2.6.6-rc1.org/include/linux/netfilter_ipv4/ipt_osf.h linux-2.6.6-rc1/include/linux/netfilter_ipv4/ipt_osf.h
255 --- linux-2.6.6-rc1.org/include/linux/netfilter_ipv4/ipt_osf.h 1970-01-01 01:00:00.000000000 +0100
256 +++ linux-2.6.6-rc1/include/linux/netfilter_ipv4/ipt_osf.h 2004-04-19 10:08:35.000000000 +0200
261 + * Copyright (c) 2003 Evgeniy Polyakov <johnpol@2ka.mipt.ru>
264 + * This program is free software; you can redistribute it and/or modify
265 + * it under the terms of the GNU General Public License as published by
266 + * the Free Software Foundation; either version 2 of the License, or
267 + * (at your option) any later version.
269 + * This program is distributed in the hope that it will be useful,
270 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
271 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
272 + * GNU General Public License for more details.
274 + * You should have received a copy of the GNU General Public License
275 + * along with this program; if not, write to the Free Software
276 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
282 +#define MAXGENRELEN 32
283 +#define MAXDETLEN 64
285 +#define IPT_OSF_GENRE 1
286 +#define IPT_OSF_SMART 2
287 +#define IPT_OSF_LOG 4
288 +#define IPT_OSF_NETLINK 8
290 +#define IPT_OSF_LOGLEVEL_ALL 0
291 +#define IPT_OSF_LOGLEVEL_FIRST 1
293 +#include <linux/list.h>
296 +#include <netinet/ip.h>
297 +#include <netinet/tcp.h>
301 + struct list_head *prev, *next;
307 + char genre[MAXGENRELEN];
309 + unsigned long flags;
311 + int invert; /* UNSUPPORTED */
320 +/* This struct represents IANA options
321 + * http://www.iana.org/assignments/tcp-parameters
325 + unsigned char kind;
326 + unsigned char length;
332 + struct list_head flist;
337 + unsigned char genre[MAXGENRELEN];
338 + unsigned char version[MAXGENRELEN], subtype[MAXGENRELEN];
340 + /* Not needed, but for consistency with original table from Michal Zalewski */
341 + unsigned char details[MAXDETLEN];
344 + struct osf_opt opt[MAX_IPOPTLEN]; /* In case it is all NOP or EOL */
348 +struct ipt_osf_nlmsg
350 + struct osf_finger f;
357 +/* Defines for IANA option kinds */
359 +#define OSFOPT_EOL 0 /* End of options */
360 +#define OSFOPT_NOP 1 /* NOP */
361 +#define OSFOPT_MSS 2 /* Maximum segment size */
362 +#define OSFOPT_WSO 3 /* Window scale option */
363 +#define OSFOPT_SACKP 4 /* SACK permitted */
364 +#define OSFOPT_SACK 5 /* SACK */
365 +#define OSFOPT_ECHO 6
366 +#define OSFOPT_ECHOREPLY 7
367 +#define OSFOPT_TS 8 /* Timestamp option */
368 +#define OSFOPT_POCP 9 /* Partial Order Connection Permitted */
369 +#define OSFOPT_POSP 10 /* Partial Order Service Profile */
370 +/* Others are not used in current OSF */
372 +static struct osf_opt IANA_opts[] =
379 + {5, 1 ,}, /* SACK length is not defined */
385 + {11, 1,}, /* CC: Suppose 1 */
386 + {12, 1,}, /* the same */
387 + {13, 1,}, /* and here too */
389 + {15, 1,}, /* TCP Alternate Checksum Data. Length is not defined */
403 +#endif /* __KERNEL__ */
405 +#endif /* _IPT_OSF_H */
406 diff -Nur linux-2.6.6-rc1.org/include/linux/netfilter_ipv4/ipt_pool.h linux-2.6.6-rc1/include/linux/netfilter_ipv4/ipt_pool.h
407 --- linux-2.6.6-rc1.org/include/linux/netfilter_ipv4/ipt_pool.h 1970-01-01 01:00:00.000000000 +0100
408 +++ linux-2.6.6-rc1/include/linux/netfilter_ipv4/ipt_pool.h 2004-04-19 10:08:36.000000000 +0200
413 +#include <linux/netfilter_ipv4/ip_pool.h>
415 +#define IPT_POOL_INV_SRC 0x00000001
416 +#define IPT_POOL_INV_DST 0x00000002
417 +#define IPT_POOL_DEL_SRC 0x00000004
418 +#define IPT_POOL_DEL_DST 0x00000008
419 +#define IPT_POOL_INV_MOD_SRC 0x00000010
420 +#define IPT_POOL_INV_MOD_DST 0x00000020
421 +#define IPT_POOL_MOD_SRC_ACCEPT 0x00000040
422 +#define IPT_POOL_MOD_DST_ACCEPT 0x00000080
423 +#define IPT_POOL_MOD_SRC_DROP 0x00000100
424 +#define IPT_POOL_MOD_DST_DROP 0x00000200
427 +struct ipt_pool_info
434 +#endif /*_IPT_POOL_H*/
435 diff -Nur linux-2.6.6-rc1.org/include/linux/netfilter_ipv4/ipt_psd.h linux-2.6.6-rc1/include/linux/netfilter_ipv4/ipt_psd.h
436 --- linux-2.6.6-rc1.org/include/linux/netfilter_ipv4/ipt_psd.h 1970-01-01 01:00:00.000000000 +0100
437 +++ linux-2.6.6-rc1/include/linux/netfilter_ipv4/ipt_psd.h 2004-04-19 10:08:37.000000000 +0200
442 +#include <linux/param.h>
443 +#include <linux/types.h>
446 + * High port numbers have a lower weight to reduce the frequency of false
447 + * positives, such as from passive mode FTP transfers.
449 +#define PORT_WEIGHT_PRIV 3
450 +#define PORT_WEIGHT_HIGH 1
453 + * Port scan detection thresholds: at least COUNT ports need to be scanned
454 + * from the same source, with no longer than DELAY ticks between ports.
456 +#define SCAN_MIN_COUNT 7
457 +#define SCAN_MAX_COUNT (SCAN_MIN_COUNT * PORT_WEIGHT_PRIV)
458 +#define SCAN_WEIGHT_THRESHOLD SCAN_MAX_COUNT
459 +#define SCAN_DELAY_THRESHOLD (HZ * 3)
462 + * Keep track of up to LIST_SIZE source addresses, using a hash table of
463 + * HASH_SIZE entries for faster lookups, but limiting hash collisions to
464 + * HASH_MAX source addresses per the same hash value.
466 +#define LIST_SIZE 0x100
468 +#define HASH_SIZE (1 << HASH_LOG)
469 +#define HASH_MAX 0x10
471 +struct ipt_psd_info {
472 + unsigned int weight_threshold;
473 + unsigned int delay_threshold;
474 + unsigned short lo_ports_weight;
475 + unsigned short hi_ports_weight;
478 +#endif /*_IPT_PSD_H*/
479 diff -Nur linux-2.6.6-rc1.org/include/linux/netfilter_ipv4/ipt_quota.h linux-2.6.6-rc1/include/linux/netfilter_ipv4/ipt_quota.h
480 --- linux-2.6.6-rc1.org/include/linux/netfilter_ipv4/ipt_quota.h 1970-01-01 01:00:00.000000000 +0100
481 +++ linux-2.6.6-rc1/include/linux/netfilter_ipv4/ipt_quota.h 2004-04-19 10:08:37.000000000 +0200
483 +#ifndef _IPT_QUOTA_H
484 +#define _IPT_QUOTA_H
486 +/* print debug info in both kernel/netfilter module & iptable library */
487 +//#define DEBUG_IPT_QUOTA
489 +struct ipt_quota_info {
493 +#endif /*_IPT_QUOTA_H*/
494 diff -Nur linux-2.6.6-rc1.org/include/linux/netfilter_ipv4/ipt_random.h linux-2.6.6-rc1/include/linux/netfilter_ipv4/ipt_random.h
495 --- linux-2.6.6-rc1.org/include/linux/netfilter_ipv4/ipt_random.h 1970-01-01 01:00:00.000000000 +0100
496 +++ linux-2.6.6-rc1/include/linux/netfilter_ipv4/ipt_random.h 2004-04-19 10:08:38.000000000 +0200
501 +#include <linux/param.h>
502 +#include <linux/types.h>
504 +struct ipt_rand_info {
508 +#endif /*_IPT_RAND_H*/
509 diff -Nur linux-2.6.6-rc1.org/include/linux/netfilter_ipv4/ipt_realm.h linux-2.6.6-rc1/include/linux/netfilter_ipv4/ipt_realm.h
510 --- linux-2.6.6-rc1.org/include/linux/netfilter_ipv4/ipt_realm.h 1970-01-01 01:00:00.000000000 +0100
511 +++ linux-2.6.6-rc1/include/linux/netfilter_ipv4/ipt_realm.h 2004-04-19 10:08:39.000000000 +0200
513 +#ifndef _IPT_REALM_H
514 +#define _IPT_REALM_H
516 +struct ipt_realm_info {
521 +#endif /*_IPT_REALM_H*/
522 diff -Nur linux-2.6.6-rc1.org/include/linux/netfilter_ipv4/ipt_sctp.h linux-2.6.6-rc1/include/linux/netfilter_ipv4/ipt_sctp.h
523 --- linux-2.6.6-rc1.org/include/linux/netfilter_ipv4/ipt_sctp.h 1970-01-01 01:00:00.000000000 +0100
524 +++ linux-2.6.6-rc1/include/linux/netfilter_ipv4/ipt_sctp.h 2004-04-19 10:08:40.000000000 +0200
526 +#ifndef _IPT_SCTP_H_
527 +#define _IPT_SCTP_H_
529 +#define IPT_SCTP_SRC_PORTS 0x01
530 +#define IPT_SCTP_DEST_PORTS 0x02
531 +#define IPT_SCTP_CHUNK_TYPES 0x04
533 +#define IPT_SCTP_VALID_FLAGS 0x07
535 +#define ELEMCOUNT(x) (sizeof(x)/sizeof(x[0]))
538 +struct ipt_sctp_flag_info {
539 + u_int8_t chunktype;
541 + u_int8_t flag_mask;
544 +#define IPT_NUM_SCTP_FLAGS 4
546 +struct ipt_sctp_info {
547 + u_int16_t dpts[2]; /* Min, Max */
548 + u_int16_t spts[2]; /* Min, Max */
550 + u_int32_t chunkmap[256 / sizeof (u_int32_t)]; /* Bit mask of chunks to be matched according to RFC 2960 */
552 +#define SCTP_CHUNK_MATCH_ANY 0x01 /* Match if any of the chunk types are present */
553 +#define SCTP_CHUNK_MATCH_ALL 0x02 /* Match if all of the chunk types are present */
554 +#define SCTP_CHUNK_MATCH_ONLY 0x04 /* Match if these are the only chunk types present */
556 + u_int32_t chunk_match_type;
557 + struct ipt_sctp_flag_info flag_info[IPT_NUM_SCTP_FLAGS];
561 + u_int32_t invflags;
564 +#define bytes(type) (sizeof(type) * 8)
566 +#define SCTP_CHUNKMAP_SET(chunkmap, type) \
568 + chunkmap[type / bytes(u_int32_t)] |= \
569 + 1 << (type % bytes(u_int32_t)); \
572 +#define SCTP_CHUNKMAP_CLEAR(chunkmap, type) \
574 + chunkmap[type / bytes(u_int32_t)] &= \
575 + ~(1 << (type % bytes(u_int32_t))); \
578 +#define SCTP_CHUNKMAP_IS_SET(chunkmap, type) \
580 + (chunkmap[type / bytes (u_int32_t)] & \
581 + (1 << (type % bytes (u_int32_t)))) ? 1: 0; \
584 +#define SCTP_CHUNKMAP_RESET(chunkmap) \
587 + for (i = 0; i < ELEMCOUNT(chunkmap); i++) \
591 +#define SCTP_CHUNKMAP_SET_ALL(chunkmap) \
594 + for (i = 0; i < ELEMCOUNT(chunkmap); i++) \
595 + chunkmap[i] = ~0; \
598 +#define SCTP_CHUNKMAP_COPY(destmap, srcmap) \
601 + for (i = 0; i < ELEMCOUNT(chunkmap); i++) \
602 + destmap[i] = srcmap[i]; \
605 +#define SCTP_CHUNKMAP_IS_CLEAR(chunkmap) \
609 + for (i = 0; i < ELEMCOUNT(chunkmap); i++) { \
610 + if (chunkmap[i]) { \
618 +#define SCTP_CHUNKMAP_IS_ALL_SET(chunkmap) \
622 + for (i = 0; i < ELEMCOUNT(chunkmap); i++) { \
623 + if (chunkmap[i] != ~0) { \
631 +#endif /* _IPT_SCTP_H_ */
633 diff -Nur linux-2.6.6-rc1.org/include/linux/netfilter_ipv4/ipt_time.h linux-2.6.6-rc1/include/linux/netfilter_ipv4/ipt_time.h
634 --- linux-2.6.6-rc1.org/include/linux/netfilter_ipv4/ipt_time.h 1970-01-01 01:00:00.000000000 +0100
635 +++ linux-2.6.6-rc1/include/linux/netfilter_ipv4/ipt_time.h 2004-04-19 10:08:41.000000000 +0200
637 +#ifndef __ipt_time_h_included__
638 +#define __ipt_time_h_included__
641 +struct ipt_time_info {
642 + u_int8_t days_match; /* 1 bit per day. -SMTWTFS */
643 + u_int16_t time_start; /* 0 < time_start < 23*60+59 = 1439 */
644 + u_int16_t time_stop; /* 0:0 < time_stat < 23:59 */
645 + u_int8_t kerneltime; /* ignore skb time (and use kerneltime) or not. */
649 +#endif /* __ipt_time_h_included__ */
650 diff -Nur linux-2.6.6-rc1.org/include/linux/netfilter_ipv4/ipt_u32.h linux-2.6.6-rc1/include/linux/netfilter_ipv4/ipt_u32.h
651 --- linux-2.6.6-rc1.org/include/linux/netfilter_ipv4/ipt_u32.h 1970-01-01 01:00:00.000000000 +0100
652 +++ linux-2.6.6-rc1/include/linux/netfilter_ipv4/ipt_u32.h 2004-04-19 10:08:46.000000000 +0200
656 +#include <linux/netfilter_ipv4/ip_tables.h>
666 +struct ipt_u32_location_element
671 +struct ipt_u32_value_element
676 +/* *** any way to allow for an arbitrary number of elements?
677 + for now I settle for a limit of 10 of each */
678 +#define U32MAXSIZE 10
682 + struct ipt_u32_location_element location[U32MAXSIZE+1];
684 + struct ipt_u32_value_element value[U32MAXSIZE+1];
690 + struct ipt_u32_test tests[U32MAXSIZE+1];
693 +#endif /*_IPT_U32_H*/
694 diff -Nur linux-2.6.6-rc1.org/include/linux/netfilter_ipv6/ip6t_HL.h linux-2.6.6-rc1/include/linux/netfilter_ipv6/ip6t_HL.h
695 --- linux-2.6.6-rc1.org/include/linux/netfilter_ipv6/ip6t_HL.h 1970-01-01 01:00:00.000000000 +0100
696 +++ linux-2.6.6-rc1/include/linux/netfilter_ipv6/ip6t_HL.h 2004-04-19 10:08:26.000000000 +0200
698 +/* Hop Limit modification module for ip6tables
699 + * Maciej Soltysiak <solt@dns.toxicfilms.tv>
700 + * Based on HW's TTL module */
711 +#define IP6T_HL_MAXMODE IP6T_HL_DEC
713 +struct ip6t_HL_info {
715 + u_int8_t hop_limit;
720 diff -Nur linux-2.6.6-rc1.org/include/linux/netfilter_ipv6/ip6t_REJECT.h linux-2.6.6-rc1/include/linux/netfilter_ipv6/ip6t_REJECT.h
721 --- linux-2.6.6-rc1.org/include/linux/netfilter_ipv6/ip6t_REJECT.h 2004-04-15 03:33:49.000000000 +0200
722 +++ linux-2.6.6-rc1/include/linux/netfilter_ipv6/ip6t_REJECT.h 2004-04-19 10:08:28.000000000 +0200
724 #define _IP6T_REJECT_H
726 enum ip6t_reject_with {
727 - IP6T_ICMP_NET_UNREACHABLE,
728 - IP6T_ICMP_HOST_UNREACHABLE,
729 - IP6T_ICMP_PROT_UNREACHABLE,
730 - IP6T_ICMP_PORT_UNREACHABLE,
731 - IP6T_ICMP_ECHOREPLY
732 + IP6T_ICMP6_NO_ROUTE,
733 + IP6T_ICMP6_ADM_PROHIBITED,
734 + IP6T_ICMP6_NOT_NEIGHBOUR,
735 + IP6T_ICMP6_ADDR_UNREACH,
736 + IP6T_ICMP6_PORT_UNREACH,
737 + IP6T_ICMP6_ECHOREPLY,
741 struct ip6t_reject_info {
742 enum ip6t_reject_with with; /* reject type */
745 -#endif /*_IPT_REJECT_H*/
746 +#endif /*_IP6T_REJECT_H*/
747 diff -Nur linux-2.6.6-rc1.org/include/linux/netfilter_ipv6/ip6t_fuzzy.h linux-2.6.6-rc1/include/linux/netfilter_ipv6/ip6t_fuzzy.h
748 --- linux-2.6.6-rc1.org/include/linux/netfilter_ipv6/ip6t_fuzzy.h 1970-01-01 01:00:00.000000000 +0100
749 +++ linux-2.6.6-rc1/include/linux/netfilter_ipv6/ip6t_fuzzy.h 2004-04-19 10:08:31.000000000 +0200
751 +#ifndef _IP6T_FUZZY_H
752 +#define _IP6T_FUZZY_H
754 +#include <linux/param.h>
755 +#include <linux/types.h>
757 +#define MAXFUZZYRATE 10000000
758 +#define MINFUZZYRATE 3
760 +struct ip6t_fuzzy_info {
761 + u_int32_t minimum_rate;
762 + u_int32_t maximum_rate;
763 + u_int32_t packets_total;
764 + u_int32_t bytes_total;
765 + u_int32_t previous_time;
766 + u_int32_t present_time;
767 + u_int32_t mean_rate;
768 + u_int8_t acceptance_rate;
771 +#endif /*_IP6T_FUZZY_H*/
772 diff -Nur linux-2.6.6-rc1.org/include/linux/netfilter_ipv6/ip6t_nth.h linux-2.6.6-rc1/include/linux/netfilter_ipv6/ip6t_nth.h
773 --- linux-2.6.6-rc1.org/include/linux/netfilter_ipv6/ip6t_nth.h 1970-01-01 01:00:00.000000000 +0100
774 +++ linux-2.6.6-rc1/include/linux/netfilter_ipv6/ip6t_nth.h 2004-04-19 10:08:34.000000000 +0200
779 +#include <linux/param.h>
780 +#include <linux/types.h>
782 +#ifndef IP6T_NTH_NUM_COUNTERS
783 +#define IP6T_NTH_NUM_COUNTERS 16
786 +struct ip6t_nth_info {
794 +#endif /*_IP6T_NTH_H*/
795 diff -Nur linux-2.6.6-rc1.org/include/linux/netfilter_ipv6/ip6t_random.h linux-2.6.6-rc1/include/linux/netfilter_ipv6/ip6t_random.h
796 --- linux-2.6.6-rc1.org/include/linux/netfilter_ipv6/ip6t_random.h 1970-01-01 01:00:00.000000000 +0100
797 +++ linux-2.6.6-rc1/include/linux/netfilter_ipv6/ip6t_random.h 2004-04-19 10:08:38.000000000 +0200
799 +#ifndef _IP6T_RAND_H
800 +#define _IP6T_RAND_H
802 +#include <linux/param.h>
803 +#include <linux/types.h>
805 +struct ip6t_rand_info {
809 +#endif /*_IP6T_RAND_H*/
810 diff -Nur linux-2.6.6-rc1.org/include/linux/skbuff.h linux-2.6.6-rc1/include/linux/skbuff.h
811 --- linux-2.6.6-rc1.org/include/linux/skbuff.h 2004-04-15 03:35:04.000000000 +0200
812 +++ linux-2.6.6-rc1/include/linux/skbuff.h 2004-04-19 10:08:24.000000000 +0200
813 @@ -1201,6 +1201,14 @@
815 atomic_inc(&nfct->master->use);
817 +static inline void nf_reset(struct sk_buff *skb)
819 + nf_conntrack_put(skb->nfct);
821 +#ifdef CONFIG_NETFILTER_DEBUG
826 #ifdef CONFIG_BRIDGE_NETFILTER
827 static inline void nf_bridge_put(struct nf_bridge_info *nf_bridge)
828 @@ -1213,9 +1221,10 @@
830 atomic_inc(&nf_bridge->use);
835 +#endif /* CONFIG_BRIDGE_NETFILTER */
836 +#else /* CONFIG_NETFILTER */
837 +static inline void nf_reset(struct sk_buff *skb) {}
838 +#endif /* CONFIG_NETFILTER */
840 #endif /* __KERNEL__ */
841 #endif /* _LINUX_SKBUFF_H */
842 diff -Nur linux-2.6.6-rc1.org/net/ipv4/ip_gre.c linux-2.6.6-rc1/net/ipv4/ip_gre.c
843 --- linux-2.6.6-rc1.org/net/ipv4/ip_gre.c 2004-04-15 03:35:20.000000000 +0200
844 +++ linux-2.6.6-rc1/net/ipv4/ip_gre.c 2004-04-19 10:08:24.000000000 +0200
846 skb->dev = tunnel->dev;
847 dst_release(skb->dst);
849 -#ifdef CONFIG_NETFILTER
850 - nf_conntrack_put(skb->nfct);
852 -#ifdef CONFIG_NETFILTER_DEBUG
857 ipgre_ecn_decapsulate(iph, skb);
859 read_unlock(&ipgre_lock);
864 -#ifdef CONFIG_NETFILTER
865 - nf_conntrack_put(skb->nfct);
867 -#ifdef CONFIG_NETFILTER_DEBUG
875 diff -Nur linux-2.6.6-rc1.org/net/ipv4/ip_input.c linux-2.6.6-rc1/net/ipv4/ip_input.c
876 --- linux-2.6.6-rc1.org/net/ipv4/ip_input.c 2004-04-15 03:33:53.000000000 +0200
877 +++ linux-2.6.6-rc1/net/ipv4/ip_input.c 2004-04-19 10:08:24.000000000 +0200
878 @@ -202,17 +202,13 @@
880 #ifdef CONFIG_NETFILTER_DEBUG
881 nf_debug_ip_local_deliver(skb);
883 #endif /*CONFIG_NETFILTER_DEBUG*/
885 __skb_pull(skb, ihl);
887 -#ifdef CONFIG_NETFILTER
888 /* Free reference early: we don't need it any more, and it may
889 hold ip_conntrack module loaded indefinitely. */
890 - nf_conntrack_put(skb->nfct);
892 -#endif /*CONFIG_NETFILTER*/
895 /* Point into the IP datagram, just past the header. */
896 skb->h.raw = skb->data;
897 diff -Nur linux-2.6.6-rc1.org/net/ipv4/ipip.c linux-2.6.6-rc1/net/ipv4/ipip.c
898 --- linux-2.6.6-rc1.org/net/ipv4/ipip.c 2004-04-15 03:36:03.000000000 +0200
899 +++ linux-2.6.6-rc1/net/ipv4/ipip.c 2004-04-19 10:08:24.000000000 +0200
901 skb->dev = tunnel->dev;
902 dst_release(skb->dst);
904 -#ifdef CONFIG_NETFILTER
905 - nf_conntrack_put(skb->nfct);
907 -#ifdef CONFIG_NETFILTER_DEBUG
912 ipip_ecn_decapsulate(iph, skb);
914 read_unlock(&ipip_lock);
916 if ((iph->ttl = tiph->ttl) == 0)
917 iph->ttl = old_iph->ttl;
919 -#ifdef CONFIG_NETFILTER
920 - nf_conntrack_put(skb->nfct);
922 -#ifdef CONFIG_NETFILTER_DEBUG
930 diff -Nur linux-2.6.6-rc1.org/net/ipv4/netfilter/Kconfig linux-2.6.6-rc1/net/ipv4/netfilter/Kconfig
931 --- linux-2.6.6-rc1.org/net/ipv4/netfilter/Kconfig 2004-04-19 09:59:32.000000000 +0200
932 +++ linux-2.6.6-rc1/net/ipv4/netfilter/Kconfig 2004-04-19 10:08:46.000000000 +0200
934 <file:Documentation/modules.txt>. If unsure, say `N'.
937 +config IP_NF_TARGET_IPV4OPTSSTRIP
938 + tristate 'IPV4OPTSSTRIP target support'
939 + depends on IP_NF_MANGLE
942 +config IP_NF_TARGET_TTL
943 + tristate 'TTL target support'
944 + depends on IP_NF_MANGLE
947 +config IP_NF_MATCH_CONNLIMIT
948 + tristate 'Connections/IP limit match support'
949 + depends on IP_NF_IPTABLES
952 +config IP_NF_MATCH_DSTLIMIT
953 + tristate 'dstlimit match support'
954 + depends on IP_NF_IPTABLES
957 +config IP_NF_MATCH_FUZZY
958 + tristate 'fuzzy match support'
959 + depends on IP_NF_IPTABLES
962 +config IP_NF_MATCH_IPV4OPTIONS
963 + tristate 'IPV4OPTIONS match support'
964 + depends on IP_NF_IPTABLES
967 +config IP_NF_MATCH_MPORT
968 + tristate 'Multiple port with ranges match support'
969 + depends on IP_NF_IPTABLES
972 +config IP_NF_MATCH_NTH
973 + tristate 'Nth match support'
974 + depends on IP_NF_IPTABLES
977 +config IP_NF_MATCH_OSF
978 + tristate 'OSF match support'
979 + depends on IP_NF_IPTABLES
982 +config IP_POOL_STATISTICS
983 + bool 'enable statistics on pool usage'
984 + depends on IP_NF_POOL!=n
987 + tristate 'IP address pool support'
988 + depends on IP_NF_IPTABLES
991 +config IP_NF_MATCH_PSD
992 + tristate 'psd match support'
993 + depends on IP_NF_IPTABLES
996 +config IP_NF_MATCH_QUOTA
997 + tristate 'quota match support'
998 + depends on IP_NF_IPTABLES
1001 +config IP_NF_MATCH_RANDOM
1002 + tristate 'random match support'
1003 + depends on IP_NF_IPTABLES
1006 +config IP_NF_MATCH_REALM
1007 + tristate 'realm match support'
1008 + depends on IP_NF_IPTABLES && NET_CLS_ROUTE
1011 +config IP_NF_MATCH_SCTP
1012 + tristate 'SCTP protocol match support'
1013 + depends on IP_NF_IPTABLES
1016 +config IP_NF_MATCH_TIME
1017 + tristate 'TIME match support'
1018 + depends on IP_NF_IPTABLES
1021 +config IP_NF_MATCH_U32
1022 + tristate 'U32 match support'
1023 + depends on IP_NF_IPTABLES
1028 diff -Nur linux-2.6.6-rc1.org/net/ipv4/netfilter/Makefile linux-2.6.6-rc1/net/ipv4/netfilter/Makefile
1029 --- linux-2.6.6-rc1.org/net/ipv4/netfilter/Makefile 2004-04-19 09:59:32.000000000 +0200
1030 +++ linux-2.6.6-rc1/net/ipv4/netfilter/Makefile 2004-04-19 10:08:46.000000000 +0200
1033 obj-$(CONFIG_IP_NF_MATCH_HELPER) += ipt_helper.o
1034 obj-$(CONFIG_IP_NF_MATCH_LIMIT) += ipt_limit.o
1035 +obj-$(CONFIG_IP_NF_MATCH_SCTP) += ipt_sctp.o
1036 +obj-$(CONFIG_IP_NF_MATCH_QUOTA) += ipt_quota.o
1037 +obj-$(CONFIG_IP_NF_MATCH_DSTLIMIT) += ipt_dstlimit.o
1038 obj-$(CONFIG_IP_NF_MATCH_MARK) += ipt_mark.o
1039 +obj-$(CONFIG_IP_NF_POOL) += ipt_pool.o ipt_POOL.o ip_pool.o
1040 obj-$(CONFIG_IP_NF_MATCH_MAC) += ipt_mac.o
1041 obj-$(CONFIG_IP_NF_MATCH_IPRANGE) += ipt_iprange.o
1043 obj-$(CONFIG_IP_NF_MATCH_PKTTYPE) += ipt_pkttype.o
1044 obj-$(CONFIG_IP_NF_MATCH_MULTIPORT) += ipt_multiport.o
1046 +obj-$(CONFIG_IP_NF_MATCH_MPORT) += ipt_mport.o
1048 obj-$(CONFIG_IP_NF_MATCH_OWNER) += ipt_owner.o
1049 obj-$(CONFIG_IP_NF_MATCH_TOS) += ipt_tos.o
1051 +obj-$(CONFIG_IP_NF_MATCH_TIME) += ipt_time.o
1054 +obj-$(CONFIG_IP_NF_MATCH_RANDOM) += ipt_random.o
1056 +obj-$(CONFIG_IP_NF_MATCH_PSD) += ipt_psd.o
1058 +obj-$(CONFIG_IP_NF_MATCH_OSF) += ipt_osf.o
1061 +obj-$(CONFIG_IP_NF_MATCH_NTH) += ipt_nth.o
1063 +obj-$(CONFIG_IP_NF_MATCH_IPV4OPTIONS) += ipt_ipv4options.o
1066 +obj-$(CONFIG_IP_NF_MATCH_FUZZY) += ipt_fuzzy.o
1068 obj-$(CONFIG_IP_NF_MATCH_RECENT) += ipt_recent.o
1070 obj-$(CONFIG_IP_NF_MATCH_ECN) += ipt_ecn.o
1073 obj-$(CONFIG_IP_NF_MATCH_LENGTH) += ipt_length.o
1075 +obj-$(CONFIG_IP_NF_MATCH_U32) += ipt_u32.o
1078 obj-$(CONFIG_IP_NF_MATCH_TTL) += ipt_ttl.o
1079 obj-$(CONFIG_IP_NF_MATCH_STATE) += ipt_state.o
1080 +obj-$(CONFIG_IP_NF_MATCH_CONNLIMIT) += ipt_connlimit.o
1081 obj-$(CONFIG_IP_NF_MATCH_CONNTRACK) += ipt_conntrack.o
1082 obj-$(CONFIG_IP_NF_MATCH_TCPMSS) += ipt_tcpmss.o
1083 +obj-$(CONFIG_IP_NF_MATCH_REALM) += ipt_realm.o
1085 obj-$(CONFIG_IP_NF_MATCH_PHYSDEV) += ipt_physdev.o
1088 obj-$(CONFIG_IP_NF_TARGET_CLASSIFY) += ipt_CLASSIFY.o
1089 obj-$(CONFIG_IP_NF_NAT_SNMP_BASIC) += ip_nat_snmp_basic.o
1090 obj-$(CONFIG_IP_NF_TARGET_LOG) += ipt_LOG.o
1091 +obj-$(CONFIG_IP_NF_TARGET_TTL) += ipt_TTL.o
1092 +obj-$(CONFIG_IP_NF_TARGET_IPV4OPTSSTRIP) += ipt_IPV4OPTSSTRIP.o
1093 obj-$(CONFIG_IP_NF_TARGET_ULOG) += ipt_ULOG.o
1094 obj-$(CONFIG_IP_NF_TARGET_TCPMSS) += ipt_TCPMSS.o
1095 obj-$(CONFIG_IP_NF_TARGET_NOTRACK) += ipt_NOTRACK.o
1096 diff -Nur linux-2.6.6-rc1.org/net/ipv4/netfilter/ip_conntrack_core.c linux-2.6.6-rc1/net/ipv4/netfilter/ip_conntrack_core.c
1097 --- linux-2.6.6-rc1.org/net/ipv4/netfilter/ip_conntrack_core.c 2004-04-19 09:59:32.000000000 +0200
1098 +++ linux-2.6.6-rc1/net/ipv4/netfilter/ip_conntrack_core.c 2004-04-19 10:08:22.000000000 +0200
1099 @@ -692,42 +692,50 @@
1100 struct ip_conntrack_expect *, tuple);
1101 READ_UNLOCK(&ip_conntrack_expect_tuple_lock);
1103 - /* If master is not in hash table yet (ie. packet hasn't left
1104 - this machine yet), how can other end know about expected?
1105 - Hence these are not the droids you are looking for (if
1106 - master ct never got confirmed, we'd hold a reference to it
1107 - and weird things would happen to future packets). */
1108 - if (expected && !is_confirmed(expected->expectant))
1111 - /* Look up the conntrack helper for master connections only */
1113 - conntrack->helper = ip_ct_find_helper(&repl_tuple);
1115 - /* If the expectation is dying, then this is a loser. */
1117 - && expected->expectant->helper->timeout
1118 - && ! del_timer(&expected->timeout))
1122 - DEBUGP("conntrack: expectation arrives ct=%p exp=%p\n",
1123 - conntrack, expected);
1124 - /* Welcome, Mr. Bond. We've been expecting you... */
1125 - IP_NF_ASSERT(master_ct(conntrack));
1126 - __set_bit(IPS_EXPECTED_BIT, &conntrack->status);
1127 - conntrack->master = expected;
1128 - expected->sibling = conntrack;
1129 - LIST_DELETE(&ip_conntrack_expect_list, expected);
1130 - expected->expectant->expecting--;
1131 - nf_conntrack_get(&master_ct(conntrack)->infos[0]);
1133 - atomic_inc(&ip_conntrack_count);
1134 + /* If master is not in hash table yet (ie. packet hasn't left
1135 + this machine yet), how can other end know about expected?
1136 + Hence these are not the droids you are looking for (if
1137 + master ct never got confirmed, we'd hold a reference to it
1138 + and weird things would happen to future packets). */
1139 + if (!is_confirmed(expected->expectant)) {
1141 + conntrack->helper = ip_ct_find_helper(&repl_tuple);
1145 + /* Expectation is dying... */
1146 + if (expected->expectant->helper->timeout
1147 + && ! del_timer(&expected->timeout)) {
1151 + DEBUGP("conntrack: expectation arrives ct=%p exp=%p\n",
1152 + conntrack, expected);
1153 + /* Welcome, Mr. Bond. We've been expecting you... */
1154 + IP_NF_ASSERT(master_ct(conntrack));
1155 + __set_bit(IPS_EXPECTED_BIT, &conntrack->status);
1156 + conntrack->master = expected;
1157 + expected->sibling = conntrack;
1158 + LIST_DELETE(&ip_conntrack_expect_list, expected);
1159 + expected->expectant->expecting--;
1160 + nf_conntrack_get(&master_ct(conntrack)->infos[0]);
1162 + /* this is a braindead... --pablo */
1163 + atomic_inc(&ip_conntrack_count);
1164 + WRITE_UNLOCK(&ip_conntrack_lock);
1166 + if (expected->expectfn)
1167 + expected->expectfn(conntrack);
1171 + conntrack->helper = ip_ct_find_helper(&repl_tuple);
1173 +end: atomic_inc(&ip_conntrack_count);
1174 WRITE_UNLOCK(&ip_conntrack_lock);
1176 - if (expected && expected->expectfn)
1177 - expected->expectfn(conntrack);
1178 - return &conntrack->tuplehash[IP_CT_DIR_ORIGINAL];
1179 +ret: return &conntrack->tuplehash[IP_CT_DIR_ORIGINAL];
1182 /* On success, returns conntrack ptr, sets skb->nfct and ctinfo */
1183 diff -Nur linux-2.6.6-rc1.org/net/ipv4/netfilter/ip_conntrack_core.c.orig linux-2.6.6-rc1/net/ipv4/netfilter/ip_conntrack_core.c.orig
1184 --- linux-2.6.6-rc1.org/net/ipv4/netfilter/ip_conntrack_core.c.orig 1970-01-01 01:00:00.000000000 +0100
1185 +++ linux-2.6.6-rc1/net/ipv4/netfilter/ip_conntrack_core.c.orig 2004-04-19 10:02:28.000000000 +0200
1187 +/* Connection state tracking for netfilter. This is separated from,
1188 + but required by, the NAT layer; it can also be used by an iptables
1191 +/* (C) 1999-2001 Paul `Rusty' Russell
1192 + * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org>
1194 + * This program is free software; you can redistribute it and/or modify
1195 + * it under the terms of the GNU General Public License version 2 as
1196 + * published by the Free Software Foundation.
1198 + * 23 Apr 2001: Harald Welte <laforge@gnumonks.org>
1199 + * - new API and handling of conntrack/nat helpers
1200 + * - now capable of multiple expectations for one master
1201 + * 16 Jul 2002: Harald Welte <laforge@gnumonks.org>
1202 + * - add usage/reference counts to ip_conntrack_expect
1203 + * - export ip_conntrack[_expect]_{find_get,put} functions
1206 +#include <linux/config.h>
1207 +#include <linux/types.h>
1208 +#include <linux/icmp.h>
1209 +#include <linux/ip.h>
1210 +#include <linux/netfilter.h>
1211 +#include <linux/netfilter_ipv4.h>
1212 +#include <linux/module.h>
1213 +#include <linux/skbuff.h>
1214 +#include <linux/proc_fs.h>
1215 +#include <linux/vmalloc.h>
1216 +#include <net/checksum.h>
1217 +#include <linux/stddef.h>
1218 +#include <linux/sysctl.h>
1219 +#include <linux/slab.h>
1220 +#include <linux/random.h>
1221 +#include <linux/jhash.h>
1222 +/* For ERR_PTR(). Yeah, I know... --RR */
1223 +#include <linux/fs.h>
1225 +/* This rwlock protects the main hash table, protocol/helper/expected
1226 + registrations, conntrack timers*/
1227 +#define ASSERT_READ_LOCK(x) MUST_BE_READ_LOCKED(&ip_conntrack_lock)
1228 +#define ASSERT_WRITE_LOCK(x) MUST_BE_WRITE_LOCKED(&ip_conntrack_lock)
1230 +#include <linux/netfilter_ipv4/ip_conntrack.h>
1231 +#include <linux/netfilter_ipv4/ip_conntrack_protocol.h>
1232 +#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
1233 +#include <linux/netfilter_ipv4/ip_conntrack_core.h>
1234 +#include <linux/netfilter_ipv4/listhelp.h>
1236 +#define IP_CONNTRACK_VERSION "2.1"
1239 +#define DEBUGP printk
1241 +#define DEBUGP(format, args...)
1244 +DECLARE_RWLOCK(ip_conntrack_lock);
1245 +DECLARE_RWLOCK(ip_conntrack_expect_tuple_lock);
1247 +void (*ip_conntrack_destroyed)(struct ip_conntrack *conntrack) = NULL;
1248 +LIST_HEAD(ip_conntrack_expect_list);
1249 +LIST_HEAD(protocol_list);
1250 +static LIST_HEAD(helpers);
1251 +unsigned int ip_conntrack_htable_size = 0;
1252 +int ip_conntrack_max;
1253 +static atomic_t ip_conntrack_count = ATOMIC_INIT(0);
1254 +struct list_head *ip_conntrack_hash;
1255 +static kmem_cache_t *ip_conntrack_cachep;
1256 +struct ip_conntrack ip_conntrack_untracked;
1258 +extern struct ip_conntrack_protocol ip_conntrack_generic_protocol;
1260 +static inline int proto_cmpfn(const struct ip_conntrack_protocol *curr,
1261 + u_int8_t protocol)
1263 + return protocol == curr->proto;
1266 +struct ip_conntrack_protocol *__ip_ct_find_proto(u_int8_t protocol)
1268 + struct ip_conntrack_protocol *p;
1270 + MUST_BE_READ_LOCKED(&ip_conntrack_lock);
1271 + p = LIST_FIND(&protocol_list, proto_cmpfn,
1272 + struct ip_conntrack_protocol *, protocol);
1274 + p = &ip_conntrack_generic_protocol;
1279 +struct ip_conntrack_protocol *ip_ct_find_proto(u_int8_t protocol)
1281 + struct ip_conntrack_protocol *p;
1283 + READ_LOCK(&ip_conntrack_lock);
1284 + p = __ip_ct_find_proto(protocol);
1285 + READ_UNLOCK(&ip_conntrack_lock);
1290 +ip_conntrack_put(struct ip_conntrack *ct)
1293 + IP_NF_ASSERT(ct->infos[0].master);
1294 + /* nf_conntrack_put wants to go via an info struct, so feed it
1296 + nf_conntrack_put(&ct->infos[0]);
1299 +static int ip_conntrack_hash_rnd_initted;
1300 +static unsigned int ip_conntrack_hash_rnd;
1303 +hash_conntrack(const struct ip_conntrack_tuple *tuple)
1306 + dump_tuple(tuple);
1308 + return (jhash_3words(tuple->src.ip,
1309 + (tuple->dst.ip ^ tuple->dst.protonum),
1310 + (tuple->src.u.all | (tuple->dst.u.all << 16)),
1311 + ip_conntrack_hash_rnd) % ip_conntrack_htable_size);
1315 +get_tuple(const struct iphdr *iph,
1316 + const struct sk_buff *skb,
1317 + unsigned int dataoff,
1318 + struct ip_conntrack_tuple *tuple,
1319 + const struct ip_conntrack_protocol *protocol)
1321 + /* Never happen */
1322 + if (iph->frag_off & htons(IP_OFFSET)) {
1323 + printk("ip_conntrack_core: Frag of proto %u.\n",
1328 + tuple->src.ip = iph->saddr;
1329 + tuple->dst.ip = iph->daddr;
1330 + tuple->dst.protonum = iph->protocol;
1332 + return protocol->pkt_to_tuple(skb, dataoff, tuple);
1336 +invert_tuple(struct ip_conntrack_tuple *inverse,
1337 + const struct ip_conntrack_tuple *orig,
1338 + const struct ip_conntrack_protocol *protocol)
1340 + inverse->src.ip = orig->dst.ip;
1341 + inverse->dst.ip = orig->src.ip;
1342 + inverse->dst.protonum = orig->dst.protonum;
1344 + return protocol->invert_tuple(inverse, orig);
1348 +/* ip_conntrack_expect helper functions */
1350 +/* Compare tuple parts depending on mask. */
1351 +static inline int expect_cmp(const struct ip_conntrack_expect *i,
1352 + const struct ip_conntrack_tuple *tuple)
1354 + MUST_BE_READ_LOCKED(&ip_conntrack_expect_tuple_lock);
1355 + return ip_ct_tuple_mask_cmp(tuple, &i->tuple, &i->mask);
1359 +destroy_expect(struct ip_conntrack_expect *exp)
1361 + DEBUGP("destroy_expect(%p) use=%d\n", exp, atomic_read(&exp->use));
1362 + IP_NF_ASSERT(atomic_read(&exp->use));
1363 + IP_NF_ASSERT(!timer_pending(&exp->timeout));
1369 +inline void ip_conntrack_expect_put(struct ip_conntrack_expect *exp)
1371 + IP_NF_ASSERT(exp);
1373 + if (atomic_dec_and_test(&exp->use)) {
1374 + /* usage count dropped to zero */
1375 + destroy_expect(exp);
1379 +static inline struct ip_conntrack_expect *
1380 +__ip_ct_expect_find(const struct ip_conntrack_tuple *tuple)
1382 + MUST_BE_READ_LOCKED(&ip_conntrack_lock);
1383 + MUST_BE_READ_LOCKED(&ip_conntrack_expect_tuple_lock);
1384 + return LIST_FIND(&ip_conntrack_expect_list, expect_cmp,
1385 + struct ip_conntrack_expect *, tuple);
1388 +/* Find a expectation corresponding to a tuple. */
1389 +struct ip_conntrack_expect *
1390 +ip_conntrack_expect_find_get(const struct ip_conntrack_tuple *tuple)
1392 + struct ip_conntrack_expect *exp;
1394 + READ_LOCK(&ip_conntrack_lock);
1395 + READ_LOCK(&ip_conntrack_expect_tuple_lock);
1396 + exp = __ip_ct_expect_find(tuple);
1398 + atomic_inc(&exp->use);
1399 + READ_UNLOCK(&ip_conntrack_expect_tuple_lock);
1400 + READ_UNLOCK(&ip_conntrack_lock);
1405 +/* remove one specific expectation from all lists and drop refcount,
1406 + * does _NOT_ delete the timer. */
1407 +static void __unexpect_related(struct ip_conntrack_expect *expect)
1409 + DEBUGP("unexpect_related(%p)\n", expect);
1410 + MUST_BE_WRITE_LOCKED(&ip_conntrack_lock);
1412 + /* we're not allowed to unexpect a confirmed expectation! */
1413 + IP_NF_ASSERT(!expect->sibling);
1415 + /* delete from global and local lists */
1416 + list_del(&expect->list);
1417 + list_del(&expect->expected_list);
1419 + /* decrement expect-count of master conntrack */
1420 + if (expect->expectant)
1421 + expect->expectant->expecting--;
1423 + ip_conntrack_expect_put(expect);
1426 +/* remove one specific expecatation from all lists, drop refcount
1427 + * and expire timer.
1428 + * This function can _NOT_ be called for confirmed expects! */
1429 +static void unexpect_related(struct ip_conntrack_expect *expect)
1431 + IP_NF_ASSERT(expect->expectant);
1432 + IP_NF_ASSERT(expect->expectant->helper);
1433 + /* if we are supposed to have a timer, but we can't delete
1434 + * it: race condition. __unexpect_related will
1435 + * be calledd by timeout function */
1436 + if (expect->expectant->helper->timeout
1437 + && !del_timer(&expect->timeout))
1440 + __unexpect_related(expect);
1443 +/* delete all unconfirmed expectations for this conntrack */
1444 +static void remove_expectations(struct ip_conntrack *ct, int drop_refcount)
1446 + struct list_head *exp_entry, *next;
1447 + struct ip_conntrack_expect *exp;
1449 + DEBUGP("remove_expectations(%p)\n", ct);
1451 + list_for_each_safe(exp_entry, next, &ct->sibling_list) {
1452 + exp = list_entry(exp_entry, struct ip_conntrack_expect,
1455 + /* we skip established expectations, as we want to delete
1456 + * the un-established ones only */
1457 + if (exp->sibling) {
1458 + DEBUGP("remove_expectations: skipping established %p of %p\n", exp->sibling, ct);
1459 + if (drop_refcount) {
1460 + /* Indicate that this expectations parent is dead */
1461 + ip_conntrack_put(exp->expectant);
1462 + exp->expectant = NULL;
1467 + IP_NF_ASSERT(list_inlist(&ip_conntrack_expect_list, exp));
1468 + IP_NF_ASSERT(exp->expectant == ct);
1470 + /* delete expectation from global and private lists */
1471 + unexpect_related(exp);
1476 +clean_from_lists(struct ip_conntrack *ct)
1478 + unsigned int ho, hr;
1480 + DEBUGP("clean_from_lists(%p)\n", ct);
1481 + MUST_BE_WRITE_LOCKED(&ip_conntrack_lock);
1483 + ho = hash_conntrack(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
1484 + hr = hash_conntrack(&ct->tuplehash[IP_CT_DIR_REPLY].tuple);
1485 + LIST_DELETE(&ip_conntrack_hash[ho], &ct->tuplehash[IP_CT_DIR_ORIGINAL]);
1486 + LIST_DELETE(&ip_conntrack_hash[hr], &ct->tuplehash[IP_CT_DIR_REPLY]);
1488 + /* Destroy all un-established, pending expectations */
1489 + remove_expectations(ct, 1);
1493 +destroy_conntrack(struct nf_conntrack *nfct)
1495 + struct ip_conntrack *ct = (struct ip_conntrack *)nfct, *master = NULL;
1496 + struct ip_conntrack_protocol *proto;
1498 + DEBUGP("destroy_conntrack(%p)\n", ct);
1499 + IP_NF_ASSERT(atomic_read(&nfct->use) == 0);
1500 + IP_NF_ASSERT(!timer_pending(&ct->timeout));
1502 + /* To make sure we don't get any weird locking issues here:
1503 + * destroy_conntrack() MUST NOT be called with a write lock
1504 + * to ip_conntrack_lock!!! -HW */
1505 + proto = ip_ct_find_proto(ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.protonum);
1506 + if (proto && proto->destroy)
1507 + proto->destroy(ct);
1509 + if (ip_conntrack_destroyed)
1510 + ip_conntrack_destroyed(ct);
1512 + WRITE_LOCK(&ip_conntrack_lock);
1513 + /* Delete us from our own list to prevent corruption later */
1514 + list_del(&ct->sibling_list);
1516 + /* Delete our master expectation */
1518 + if (ct->master->expectant) {
1519 + /* can't call __unexpect_related here,
1520 + * since it would screw up expect_list */
1521 + list_del(&ct->master->expected_list);
1522 + master = ct->master->expectant;
1524 + kfree(ct->master);
1526 + WRITE_UNLOCK(&ip_conntrack_lock);
1529 + ip_conntrack_put(master);
1531 + DEBUGP("destroy_conntrack: returning ct=%p to slab\n", ct);
1532 + kmem_cache_free(ip_conntrack_cachep, ct);
1533 + atomic_dec(&ip_conntrack_count);
1536 +static void death_by_timeout(unsigned long ul_conntrack)
1538 + struct ip_conntrack *ct = (void *)ul_conntrack;
1540 + WRITE_LOCK(&ip_conntrack_lock);
1541 + clean_from_lists(ct);
1542 + WRITE_UNLOCK(&ip_conntrack_lock);
1543 + ip_conntrack_put(ct);
1547 +conntrack_tuple_cmp(const struct ip_conntrack_tuple_hash *i,
1548 + const struct ip_conntrack_tuple *tuple,
1549 + const struct ip_conntrack *ignored_conntrack)
1551 + MUST_BE_READ_LOCKED(&ip_conntrack_lock);
1552 + return i->ctrack != ignored_conntrack
1553 + && ip_ct_tuple_equal(tuple, &i->tuple);
1556 +static struct ip_conntrack_tuple_hash *
1557 +__ip_conntrack_find(const struct ip_conntrack_tuple *tuple,
1558 + const struct ip_conntrack *ignored_conntrack)
1560 + struct ip_conntrack_tuple_hash *h;
1561 + unsigned int hash = hash_conntrack(tuple);
1563 + MUST_BE_READ_LOCKED(&ip_conntrack_lock);
1564 + h = LIST_FIND(&ip_conntrack_hash[hash],
1565 + conntrack_tuple_cmp,
1566 + struct ip_conntrack_tuple_hash *,
1567 + tuple, ignored_conntrack);
1571 +/* Find a connection corresponding to a tuple. */
1572 +struct ip_conntrack_tuple_hash *
1573 +ip_conntrack_find_get(const struct ip_conntrack_tuple *tuple,
1574 + const struct ip_conntrack *ignored_conntrack)
1576 + struct ip_conntrack_tuple_hash *h;
1578 + READ_LOCK(&ip_conntrack_lock);
1579 + h = __ip_conntrack_find(tuple, ignored_conntrack);
1581 + atomic_inc(&h->ctrack->ct_general.use);
1582 + READ_UNLOCK(&ip_conntrack_lock);
1587 +static inline struct ip_conntrack *
1588 +__ip_conntrack_get(struct nf_ct_info *nfct, enum ip_conntrack_info *ctinfo)
1590 + struct ip_conntrack *ct
1591 + = (struct ip_conntrack *)nfct->master;
1593 + /* ctinfo is the index of the nfct inside the conntrack */
1594 + *ctinfo = nfct - ct->infos;
1595 + IP_NF_ASSERT(*ctinfo >= 0 && *ctinfo < IP_CT_NUMBER);
1599 +/* Return conntrack and conntrack_info given skb->nfct->master */
1600 +struct ip_conntrack *
1601 +ip_conntrack_get(struct sk_buff *skb, enum ip_conntrack_info *ctinfo)
1604 + return __ip_conntrack_get(skb->nfct, ctinfo);
1608 +/* Confirm a connection given skb->nfct; places it in hash table */
1610 +__ip_conntrack_confirm(struct nf_ct_info *nfct)
1612 + unsigned int hash, repl_hash;
1613 + struct ip_conntrack *ct;
1614 + enum ip_conntrack_info ctinfo;
1616 + ct = __ip_conntrack_get(nfct, &ctinfo);
1618 + /* ipt_REJECT uses ip_conntrack_attach to attach related
1619 + ICMP/TCP RST packets in other direction. Actual packet
1620 + which created connection will be IP_CT_NEW or for an
1621 + expected connection, IP_CT_RELATED. */
1622 + if (CTINFO2DIR(ctinfo) != IP_CT_DIR_ORIGINAL)
1625 + hash = hash_conntrack(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
1626 + repl_hash = hash_conntrack(&ct->tuplehash[IP_CT_DIR_REPLY].tuple);
1628 + /* We're not in hash table, and we refuse to set up related
1629 + connections for unconfirmed conns. But packet copies and
1630 + REJECT will give spurious warnings here. */
1631 + /* IP_NF_ASSERT(atomic_read(&ct->ct_general.use) == 1); */
1633 + /* No external references means noone else could have
1635 + IP_NF_ASSERT(!is_confirmed(ct));
1636 + DEBUGP("Confirming conntrack %p\n", ct);
1638 + WRITE_LOCK(&ip_conntrack_lock);
1639 + /* See if there's one in the list already, including reverse:
1640 + NAT could have grabbed it without realizing, since we're
1641 + not in the hash. If there is, we lost race. */
1642 + if (!LIST_FIND(&ip_conntrack_hash[hash],
1643 + conntrack_tuple_cmp,
1644 + struct ip_conntrack_tuple_hash *,
1645 + &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple, NULL)
1646 + && !LIST_FIND(&ip_conntrack_hash[repl_hash],
1647 + conntrack_tuple_cmp,
1648 + struct ip_conntrack_tuple_hash *,
1649 + &ct->tuplehash[IP_CT_DIR_REPLY].tuple, NULL)) {
1650 + list_prepend(&ip_conntrack_hash[hash],
1651 + &ct->tuplehash[IP_CT_DIR_ORIGINAL]);
1652 + list_prepend(&ip_conntrack_hash[repl_hash],
1653 + &ct->tuplehash[IP_CT_DIR_REPLY]);
1654 + /* Timer relative to confirmation time, not original
1655 + setting time, otherwise we'd get timer wrap in
1656 + weird delay cases. */
1657 + ct->timeout.expires += jiffies;
1658 + add_timer(&ct->timeout);
1659 + atomic_inc(&ct->ct_general.use);
1660 + set_bit(IPS_CONFIRMED_BIT, &ct->status);
1661 + WRITE_UNLOCK(&ip_conntrack_lock);
1665 + WRITE_UNLOCK(&ip_conntrack_lock);
1669 +/* Returns true if a connection correspondings to the tuple (required
1672 +ip_conntrack_tuple_taken(const struct ip_conntrack_tuple *tuple,
1673 + const struct ip_conntrack *ignored_conntrack)
1675 + struct ip_conntrack_tuple_hash *h;
1677 + READ_LOCK(&ip_conntrack_lock);
1678 + h = __ip_conntrack_find(tuple, ignored_conntrack);
1679 + READ_UNLOCK(&ip_conntrack_lock);
1684 +/* Returns conntrack if it dealt with ICMP, and filled in skb fields */
1685 +struct ip_conntrack *
1686 +icmp_error_track(struct sk_buff *skb,
1687 + enum ip_conntrack_info *ctinfo,
1688 + unsigned int hooknum)
1690 + struct ip_conntrack_tuple innertuple, origtuple;
1692 + struct icmphdr icmp;
1695 + struct ip_conntrack_protocol *innerproto;
1696 + struct ip_conntrack_tuple_hash *h;
1699 + IP_NF_ASSERT(skb->nfct == NULL);
1701 + /* Not enough header? */
1702 + if (skb_copy_bits(skb, skb->nh.iph->ihl*4, &inside, sizeof(inside))!=0)
1705 + if (inside.icmp.type != ICMP_DEST_UNREACH
1706 + && inside.icmp.type != ICMP_SOURCE_QUENCH
1707 + && inside.icmp.type != ICMP_TIME_EXCEEDED
1708 + && inside.icmp.type != ICMP_PARAMETERPROB
1709 + && inside.icmp.type != ICMP_REDIRECT)
1712 + /* Ignore ICMP's containing fragments (shouldn't happen) */
1713 + if (inside.ip.frag_off & htons(IP_OFFSET)) {
1714 + DEBUGP("icmp_error_track: fragment of proto %u\n",
1715 + inside.ip.protocol);
1719 + innerproto = ip_ct_find_proto(inside.ip.protocol);
1720 + dataoff = skb->nh.iph->ihl*4 + sizeof(inside.icmp) + inside.ip.ihl*4;
1721 + /* Are they talking about one of our connections? */
1722 + if (!get_tuple(&inside.ip, skb, dataoff, &origtuple, innerproto)) {
1723 + DEBUGP("icmp_error: ! get_tuple p=%u", inside.ip.protocol);
1727 + /* Ordinarily, we'd expect the inverted tupleproto, but it's
1728 + been preserved inside the ICMP. */
1729 + if (!invert_tuple(&innertuple, &origtuple, innerproto)) {
1730 + DEBUGP("icmp_error_track: Can't invert tuple\n");
1734 + *ctinfo = IP_CT_RELATED;
1736 + h = ip_conntrack_find_get(&innertuple, NULL);
1738 + /* Locally generated ICMPs will match inverted if they
1739 + haven't been SNAT'ed yet */
1740 + /* FIXME: NAT code has to handle half-done double NAT --RR */
1741 + if (hooknum == NF_IP_LOCAL_OUT)
1742 + h = ip_conntrack_find_get(&origtuple, NULL);
1745 + DEBUGP("icmp_error_track: no match\n");
1748 + /* Reverse direction from that found */
1749 + if (DIRECTION(h) != IP_CT_DIR_REPLY)
1750 + *ctinfo += IP_CT_IS_REPLY;
1752 + if (DIRECTION(h) == IP_CT_DIR_REPLY)
1753 + *ctinfo += IP_CT_IS_REPLY;
1756 + /* Update skb to refer to this connection */
1757 + skb->nfct = &h->ctrack->infos[*ctinfo];
1761 +/* There's a small race here where we may free a just-assured
1762 + connection. Too bad: we're in trouble anyway. */
1763 +static inline int unreplied(const struct ip_conntrack_tuple_hash *i)
1765 + return !(test_bit(IPS_ASSURED_BIT, &i->ctrack->status));
1768 +static int early_drop(struct list_head *chain)
1770 + /* Traverse backwards: gives us oldest, which is roughly LRU */
1771 + struct ip_conntrack_tuple_hash *h;
1774 + READ_LOCK(&ip_conntrack_lock);
1775 + h = LIST_FIND_B(chain, unreplied, struct ip_conntrack_tuple_hash *);
1777 + atomic_inc(&h->ctrack->ct_general.use);
1778 + READ_UNLOCK(&ip_conntrack_lock);
1783 + if (del_timer(&h->ctrack->timeout)) {
1784 + death_by_timeout((unsigned long)h->ctrack);
1787 + ip_conntrack_put(h->ctrack);
1791 +static inline int helper_cmp(const struct ip_conntrack_helper *i,
1792 + const struct ip_conntrack_tuple *rtuple)
1794 + return ip_ct_tuple_mask_cmp(rtuple, &i->tuple, &i->mask);
1797 +struct ip_conntrack_helper *ip_ct_find_helper(const struct ip_conntrack_tuple *tuple)
1799 + return LIST_FIND(&helpers, helper_cmp,
1800 + struct ip_conntrack_helper *,
1804 +/* Allocate a new conntrack: we return -ENOMEM if classification
1805 + failed due to stress. Otherwise it really is unclassifiable. */
1806 +static struct ip_conntrack_tuple_hash *
1807 +init_conntrack(const struct ip_conntrack_tuple *tuple,
1808 + struct ip_conntrack_protocol *protocol,
1809 + struct sk_buff *skb)
1811 + struct ip_conntrack *conntrack;
1812 + struct ip_conntrack_tuple repl_tuple;
1814 + struct ip_conntrack_expect *expected;
1816 + static unsigned int drop_next;
1818 + if (!ip_conntrack_hash_rnd_initted) {
1819 + get_random_bytes(&ip_conntrack_hash_rnd, 4);
1820 + ip_conntrack_hash_rnd_initted = 1;
1823 + hash = hash_conntrack(tuple);
1825 + if (ip_conntrack_max &&
1826 + atomic_read(&ip_conntrack_count) >= ip_conntrack_max) {
1827 + /* Try dropping from random chain, or else from the
1828 + chain about to put into (in case they're trying to
1829 + bomb one hash chain). */
1830 + unsigned int next = (drop_next++)%ip_conntrack_htable_size;
1832 + if (!early_drop(&ip_conntrack_hash[next])
1833 + && !early_drop(&ip_conntrack_hash[hash])) {
1834 + if (net_ratelimit())
1835 + printk(KERN_WARNING
1836 + "ip_conntrack: table full, dropping"
1838 + return ERR_PTR(-ENOMEM);
1842 + if (!invert_tuple(&repl_tuple, tuple, protocol)) {
1843 + DEBUGP("Can't invert tuple.\n");
1847 + conntrack = kmem_cache_alloc(ip_conntrack_cachep, GFP_ATOMIC);
1849 + DEBUGP("Can't allocate conntrack.\n");
1850 + return ERR_PTR(-ENOMEM);
1853 + memset(conntrack, 0, sizeof(*conntrack));
1854 + atomic_set(&conntrack->ct_general.use, 1);
1855 + conntrack->ct_general.destroy = destroy_conntrack;
1856 + conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple = *tuple;
1857 + conntrack->tuplehash[IP_CT_DIR_ORIGINAL].ctrack = conntrack;
1858 + conntrack->tuplehash[IP_CT_DIR_REPLY].tuple = repl_tuple;
1859 + conntrack->tuplehash[IP_CT_DIR_REPLY].ctrack = conntrack;
1860 + for (i=0; i < IP_CT_NUMBER; i++)
1861 + conntrack->infos[i].master = &conntrack->ct_general;
1863 + if (!protocol->new(conntrack, skb)) {
1864 + kmem_cache_free(ip_conntrack_cachep, conntrack);
1867 + /* Don't set timer yet: wait for confirmation */
1868 + init_timer(&conntrack->timeout);
1869 + conntrack->timeout.data = (unsigned long)conntrack;
1870 + conntrack->timeout.function = death_by_timeout;
1872 + INIT_LIST_HEAD(&conntrack->sibling_list);
1874 + WRITE_LOCK(&ip_conntrack_lock);
1875 + /* Need finding and deleting of expected ONLY if we win race */
1876 + READ_LOCK(&ip_conntrack_expect_tuple_lock);
1877 + expected = LIST_FIND(&ip_conntrack_expect_list, expect_cmp,
1878 + struct ip_conntrack_expect *, tuple);
1879 + READ_UNLOCK(&ip_conntrack_expect_tuple_lock);
1881 + /* If master is not in hash table yet (ie. packet hasn't left
1882 + this machine yet), how can other end know about expected?
1883 + Hence these are not the droids you are looking for (if
1884 + master ct never got confirmed, we'd hold a reference to it
1885 + and weird things would happen to future packets). */
1886 + if (expected && !is_confirmed(expected->expectant))
1889 + /* Look up the conntrack helper for master connections only */
1891 + conntrack->helper = ip_ct_find_helper(&repl_tuple);
1893 + /* If the expectation is dying, then this is a loser. */
1895 + && expected->expectant->helper->timeout
1896 + && ! del_timer(&expected->timeout))
1900 + DEBUGP("conntrack: expectation arrives ct=%p exp=%p\n",
1901 + conntrack, expected);
1902 + /* Welcome, Mr. Bond. We've been expecting you... */
1903 + IP_NF_ASSERT(master_ct(conntrack));
1904 + __set_bit(IPS_EXPECTED_BIT, &conntrack->status);
1905 + conntrack->master = expected;
1906 + expected->sibling = conntrack;
1907 + LIST_DELETE(&ip_conntrack_expect_list, expected);
1908 + expected->expectant->expecting--;
1909 + nf_conntrack_get(&master_ct(conntrack)->infos[0]);
1911 + atomic_inc(&ip_conntrack_count);
1912 + WRITE_UNLOCK(&ip_conntrack_lock);
1914 + if (expected && expected->expectfn)
1915 + expected->expectfn(conntrack);
1916 + return &conntrack->tuplehash[IP_CT_DIR_ORIGINAL];
1919 +/* On success, returns conntrack ptr, sets skb->nfct and ctinfo */
1920 +static inline struct ip_conntrack *
1921 +resolve_normal_ct(struct sk_buff *skb,
1922 + struct ip_conntrack_protocol *proto,
1924 + unsigned int hooknum,
1925 + enum ip_conntrack_info *ctinfo)
1927 + struct ip_conntrack_tuple tuple;
1928 + struct ip_conntrack_tuple_hash *h;
1930 + IP_NF_ASSERT((skb->nh.iph->frag_off & htons(IP_OFFSET)) == 0);
1932 + if (!get_tuple(skb->nh.iph, skb, skb->nh.iph->ihl*4, &tuple, proto))
1935 + /* look for tuple match */
1936 + h = ip_conntrack_find_get(&tuple, NULL);
1938 + h = init_conntrack(&tuple, proto, skb);
1945 + /* It exists; we have (non-exclusive) reference. */
1946 + if (DIRECTION(h) == IP_CT_DIR_REPLY) {
1947 + *ctinfo = IP_CT_ESTABLISHED + IP_CT_IS_REPLY;
1948 + /* Please set reply bit if this packet OK */
1951 + /* Once we've had two way comms, always ESTABLISHED. */
1952 + if (test_bit(IPS_SEEN_REPLY_BIT, &h->ctrack->status)) {
1953 + DEBUGP("ip_conntrack_in: normal packet for %p\n",
1955 + *ctinfo = IP_CT_ESTABLISHED;
1956 + } else if (test_bit(IPS_EXPECTED_BIT, &h->ctrack->status)) {
1957 + DEBUGP("ip_conntrack_in: related packet for %p\n",
1959 + *ctinfo = IP_CT_RELATED;
1961 + DEBUGP("ip_conntrack_in: new packet for %p\n",
1963 + *ctinfo = IP_CT_NEW;
1967 + skb->nfct = &h->ctrack->infos[*ctinfo];
1971 +/* Netfilter hook itself. */
1972 +unsigned int ip_conntrack_in(unsigned int hooknum,
1973 + struct sk_buff **pskb,
1974 + const struct net_device *in,
1975 + const struct net_device *out,
1976 + int (*okfn)(struct sk_buff *))
1978 + struct ip_conntrack *ct;
1979 + enum ip_conntrack_info ctinfo;
1980 + struct ip_conntrack_protocol *proto;
1984 + /* Never happen */
1985 + if ((*pskb)->nh.iph->frag_off & htons(IP_OFFSET)) {
1986 + if (net_ratelimit()) {
1987 + printk(KERN_ERR "ip_conntrack_in: Frag of proto %u (hook=%u)\n",
1988 + (*pskb)->nh.iph->protocol, hooknum);
1993 + /* FIXME: Do this right please. --RR */
1994 + (*pskb)->nfcache |= NFC_UNKNOWN;
1996 +/* Doesn't cover locally-generated broadcast, so not worth it. */
1998 + /* Ignore broadcast: no `connection'. */
1999 + if ((*pskb)->pkt_type == PACKET_BROADCAST) {
2000 + printk("Broadcast packet!\n");
2002 + } else if (((*pskb)->nh.iph->daddr & htonl(0x000000FF))
2003 + == htonl(0x000000FF)) {
2004 + printk("Should bcast: %u.%u.%u.%u->%u.%u.%u.%u (sk=%p, ptype=%u)\n",
2005 + NIPQUAD((*pskb)->nh.iph->saddr),
2006 + NIPQUAD((*pskb)->nh.iph->daddr),
2007 + (*pskb)->sk, (*pskb)->pkt_type);
2011 + /* Previously seen (loopback or untracked)? Ignore. */
2012 + if ((*pskb)->nfct)
2015 + proto = ip_ct_find_proto((*pskb)->nh.iph->protocol);
2017 + /* It may be an icmp error... */
2018 + if ((*pskb)->nh.iph->protocol == IPPROTO_ICMP
2019 + && icmp_error_track(*pskb, &ctinfo, hooknum))
2022 + if (!(ct = resolve_normal_ct(*pskb, proto,&set_reply,hooknum,&ctinfo)))
2023 + /* Not valid part of a connection */
2027 + /* Too stressed to deal. */
2030 + IP_NF_ASSERT((*pskb)->nfct);
2032 + ret = proto->packet(ct, *pskb, ctinfo);
2035 + nf_conntrack_put((*pskb)->nfct);
2036 + (*pskb)->nfct = NULL;
2040 + if (ret != NF_DROP && ct->helper) {
2041 + ret = ct->helper->help(*pskb, ct, ctinfo);
2044 + nf_conntrack_put((*pskb)->nfct);
2045 + (*pskb)->nfct = NULL;
2050 + set_bit(IPS_SEEN_REPLY_BIT, &ct->status);
2055 +int invert_tuplepr(struct ip_conntrack_tuple *inverse,
2056 + const struct ip_conntrack_tuple *orig)
2058 + return invert_tuple(inverse, orig, ip_ct_find_proto(orig->dst.protonum));
2061 +static inline int resent_expect(const struct ip_conntrack_expect *i,
2062 + const struct ip_conntrack_tuple *tuple,
2063 + const struct ip_conntrack_tuple *mask)
2065 + DEBUGP("resent_expect\n");
2066 + DEBUGP(" tuple: "); DUMP_TUPLE(&i->tuple);
2067 + DEBUGP("ct_tuple: "); DUMP_TUPLE(&i->ct_tuple);
2068 + DEBUGP("test tuple: "); DUMP_TUPLE(tuple);
2069 + return (((i->ct_tuple.dst.protonum == 0 && ip_ct_tuple_equal(&i->tuple, tuple))
2070 + || (i->ct_tuple.dst.protonum && ip_ct_tuple_equal(&i->ct_tuple, tuple)))
2071 + && ip_ct_tuple_equal(&i->mask, mask));
2074 +/* Would two expected things clash? */
2075 +static inline int expect_clash(const struct ip_conntrack_expect *i,
2076 + const struct ip_conntrack_tuple *tuple,
2077 + const struct ip_conntrack_tuple *mask)
2079 + /* Part covered by intersection of masks must be unequal,
2080 + otherwise they clash */
2081 + struct ip_conntrack_tuple intersect_mask
2082 + = { { i->mask.src.ip & mask->src.ip,
2083 + { i->mask.src.u.all & mask->src.u.all } },
2084 + { i->mask.dst.ip & mask->dst.ip,
2085 + { i->mask.dst.u.all & mask->dst.u.all },
2086 + i->mask.dst.protonum & mask->dst.protonum } };
2088 + return ip_ct_tuple_mask_cmp(&i->tuple, tuple, &intersect_mask);
2091 +inline void ip_conntrack_unexpect_related(struct ip_conntrack_expect *expect)
2093 + WRITE_LOCK(&ip_conntrack_lock);
2094 + unexpect_related(expect);
2095 + WRITE_UNLOCK(&ip_conntrack_lock);
2098 +static void expectation_timed_out(unsigned long ul_expect)
2100 + struct ip_conntrack_expect *expect = (void *) ul_expect;
2102 + DEBUGP("expectation %p timed out\n", expect);
2103 + WRITE_LOCK(&ip_conntrack_lock);
2104 + __unexpect_related(expect);
2105 + WRITE_UNLOCK(&ip_conntrack_lock);
2108 +struct ip_conntrack_expect *
2109 +ip_conntrack_expect_alloc()
2111 + struct ip_conntrack_expect *new;
2113 + new = (struct ip_conntrack_expect *)
2114 + kmalloc(sizeof(struct ip_conntrack_expect), GFP_ATOMIC);
2116 + DEBUGP("expect_related: OOM allocating expect\n");
2120 + /* tuple_cmp compares whole union, we have to initialized cleanly */
2121 + memset(new, 0, sizeof(struct ip_conntrack_expect));
2127 +ip_conntrack_expect_insert(struct ip_conntrack_expect *new,
2128 + struct ip_conntrack *related_to)
2130 + DEBUGP("new expectation %p of conntrack %p\n", new, related_to);
2131 + new->expectant = related_to;
2132 + new->sibling = NULL;
2133 + atomic_set(&new->use, 1);
2135 + /* add to expected list for this connection */
2136 + list_add(&new->expected_list, &related_to->sibling_list);
2137 + /* add to global list of expectations */
2139 + list_prepend(&ip_conntrack_expect_list, &new->list);
2140 + /* add and start timer if required */
2141 + if (related_to->helper->timeout) {
2142 + init_timer(&new->timeout);
2143 + new->timeout.data = (unsigned long)new;
2144 + new->timeout.function = expectation_timed_out;
2145 + new->timeout.expires = jiffies +
2146 + related_to->helper->timeout * HZ;
2147 + add_timer(&new->timeout);
2149 + related_to->expecting++;
2152 +/* Add a related connection. */
2153 +int ip_conntrack_expect_related(struct ip_conntrack_expect *expect,
2154 + struct ip_conntrack *related_to)
2156 + struct ip_conntrack_expect *old;
2159 + WRITE_LOCK(&ip_conntrack_lock);
2160 + /* Because of the write lock, no reader can walk the lists,
2161 + * so there is no need to use the tuple lock too */
2163 + DEBUGP("ip_conntrack_expect_related %p\n", related_to);
2164 + DEBUGP("tuple: "); DUMP_TUPLE(&expect->tuple);
2165 + DEBUGP("mask: "); DUMP_TUPLE(&expect->mask);
2167 + old = LIST_FIND(&ip_conntrack_expect_list, resent_expect,
2168 + struct ip_conntrack_expect *, &expect->tuple,
2171 + /* Helper private data may contain offsets but no pointers
2172 + pointing into the payload - otherwise we should have to copy
2173 + the data filled out by the helper over the old one */
2174 + DEBUGP("expect_related: resent packet\n");
2175 + if (related_to->helper->timeout) {
2176 + if (!del_timer(&old->timeout)) {
2177 + /* expectation is dying. Fall through */
2180 + old->timeout.expires = jiffies +
2181 + related_to->helper->timeout * HZ;
2182 + add_timer(&old->timeout);
2186 + WRITE_UNLOCK(&ip_conntrack_lock);
2190 + } else if (related_to->helper->max_expected &&
2191 + related_to->expecting >= related_to->helper->max_expected) {
2192 + struct list_head *cur_item;
2194 + if (!(related_to->helper->flags &
2195 + IP_CT_HELPER_F_REUSE_EXPECT)) {
2196 + WRITE_UNLOCK(&ip_conntrack_lock);
2197 + if (net_ratelimit())
2198 + printk(KERN_WARNING
2199 + "ip_conntrack: max number of expected "
2200 + "connections %i of %s reached for "
2201 + "%u.%u.%u.%u->%u.%u.%u.%u\n",
2202 + related_to->helper->max_expected,
2203 + related_to->helper->name,
2204 + NIPQUAD(related_to->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip),
2205 + NIPQUAD(related_to->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip));
2209 + DEBUGP("ip_conntrack: max number of expected "
2210 + "connections %i of %s reached for "
2211 + "%u.%u.%u.%u->%u.%u.%u.%u, reusing\n",
2212 + related_to->helper->max_expected,
2213 + related_to->helper->name,
2214 + NIPQUAD(related_to->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip),
2215 + NIPQUAD(related_to->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip));
2217 + /* choose the the oldest expectation to evict */
2218 + list_for_each(cur_item, &related_to->sibling_list) {
2219 + struct ip_conntrack_expect *cur;
2221 + cur = list_entry(cur_item,
2222 + struct ip_conntrack_expect,
2224 + if (cur->sibling == NULL) {
2230 + /* (!old) cannot happen, since related_to->expecting is the
2231 + * number of unconfirmed expects */
2232 + IP_NF_ASSERT(old);
2234 + /* newnat14 does not reuse the real allocated memory
2235 + * structures but rather unexpects the old and
2236 + * allocates a new. unexpect_related will decrement
2237 + * related_to->expecting.
2239 + unexpect_related(old);
2241 + } else if (LIST_FIND(&ip_conntrack_expect_list, expect_clash,
2242 + struct ip_conntrack_expect *, &expect->tuple,
2244 + WRITE_UNLOCK(&ip_conntrack_lock);
2245 + DEBUGP("expect_related: busy!\n");
2251 +out: ip_conntrack_expect_insert(expect, related_to);
2253 + WRITE_UNLOCK(&ip_conntrack_lock);
2258 +/* Change tuple in an existing expectation */
2259 +int ip_conntrack_change_expect(struct ip_conntrack_expect *expect,
2260 + struct ip_conntrack_tuple *newtuple)
2264 + MUST_BE_READ_LOCKED(&ip_conntrack_lock);
2265 + WRITE_LOCK(&ip_conntrack_expect_tuple_lock);
2267 + DEBUGP("change_expect:\n");
2268 + DEBUGP("exp tuple: "); DUMP_TUPLE(&expect->tuple);
2269 + DEBUGP("exp mask: "); DUMP_TUPLE(&expect->mask);
2270 + DEBUGP("newtuple: "); DUMP_TUPLE(newtuple);
2271 + if (expect->ct_tuple.dst.protonum == 0) {
2272 + /* Never seen before */
2273 + DEBUGP("change expect: never seen before\n");
2274 + if (!ip_ct_tuple_equal(&expect->tuple, newtuple)
2275 + && LIST_FIND(&ip_conntrack_expect_list, expect_clash,
2276 + struct ip_conntrack_expect *, newtuple, &expect->mask)) {
2277 + /* Force NAT to find an unused tuple */
2280 + memcpy(&expect->ct_tuple, &expect->tuple, sizeof(expect->tuple));
2281 + memcpy(&expect->tuple, newtuple, sizeof(expect->tuple));
2285 + /* Resent packet */
2286 + DEBUGP("change expect: resent packet\n");
2287 + if (ip_ct_tuple_equal(&expect->tuple, newtuple)) {
2290 + /* Force NAT to choose again the same port */
2294 + WRITE_UNLOCK(&ip_conntrack_expect_tuple_lock);
2299 +/* Alter reply tuple (maybe alter helper). If it's already taken,
2300 + return 0 and don't do alteration. */
2301 +int ip_conntrack_alter_reply(struct ip_conntrack *conntrack,
2302 + const struct ip_conntrack_tuple *newreply)
2304 + WRITE_LOCK(&ip_conntrack_lock);
2305 + if (__ip_conntrack_find(newreply, conntrack)) {
2306 + WRITE_UNLOCK(&ip_conntrack_lock);
2309 + /* Should be unconfirmed, so not in hash table yet */
2310 + IP_NF_ASSERT(!is_confirmed(conntrack));
2312 + DEBUGP("Altering reply tuple of %p to ", conntrack);
2313 + DUMP_TUPLE(newreply);
2315 + conntrack->tuplehash[IP_CT_DIR_REPLY].tuple = *newreply;
2316 + if (!conntrack->master)
2317 + conntrack->helper = LIST_FIND(&helpers, helper_cmp,
2318 + struct ip_conntrack_helper *,
2320 + WRITE_UNLOCK(&ip_conntrack_lock);
2325 +int ip_conntrack_helper_register(struct ip_conntrack_helper *me)
2327 + WRITE_LOCK(&ip_conntrack_lock);
2328 + list_prepend(&helpers, me);
2329 + WRITE_UNLOCK(&ip_conntrack_lock);
2334 +static inline int unhelp(struct ip_conntrack_tuple_hash *i,
2335 + const struct ip_conntrack_helper *me)
2337 + if (i->ctrack->helper == me) {
2338 + /* Get rid of any expected. */
2339 + remove_expectations(i->ctrack, 0);
2340 + /* And *then* set helper to NULL */
2341 + i->ctrack->helper = NULL;
2346 +void ip_conntrack_helper_unregister(struct ip_conntrack_helper *me)
2350 + /* Need write lock here, to delete helper. */
2351 + WRITE_LOCK(&ip_conntrack_lock);
2352 + LIST_DELETE(&helpers, me);
2354 + /* Get rid of expecteds, set helpers to NULL. */
2355 + for (i = 0; i < ip_conntrack_htable_size; i++)
2356 + LIST_FIND_W(&ip_conntrack_hash[i], unhelp,
2357 + struct ip_conntrack_tuple_hash *, me);
2358 + WRITE_UNLOCK(&ip_conntrack_lock);
2360 + /* Someone could be still looking at the helper in a bh. */
2361 + synchronize_net();
2364 +/* Refresh conntrack for this many jiffies. */
2365 +void ip_ct_refresh(struct ip_conntrack *ct, unsigned long extra_jiffies)
2367 + IP_NF_ASSERT(ct->timeout.data == (unsigned long)ct);
2369 + /* If not in hash table, timer will not be active yet */
2370 + if (!is_confirmed(ct))
2371 + ct->timeout.expires = extra_jiffies;
2373 + WRITE_LOCK(&ip_conntrack_lock);
2374 + /* Need del_timer for race avoidance (may already be dying). */
2375 + if (del_timer(&ct->timeout)) {
2376 + ct->timeout.expires = jiffies + extra_jiffies;
2377 + add_timer(&ct->timeout);
2379 + WRITE_UNLOCK(&ip_conntrack_lock);
2383 +/* Returns new sk_buff, or NULL */
2385 +ip_ct_gather_frags(struct sk_buff *skb)
2387 + struct sock *sk = skb->sk;
2388 +#ifdef CONFIG_NETFILTER_DEBUG
2389 + unsigned int olddebug = skb->nf_debug;
2396 + local_bh_disable();
2397 + skb = ip_defrag(skb);
2398 + local_bh_enable();
2407 + skb_set_owner_w(skb, sk);
2411 + ip_send_check(skb->nh.iph);
2412 + skb->nfcache |= NFC_ALTERED;
2413 +#ifdef CONFIG_NETFILTER_DEBUG
2414 + /* Packet path as if nothing had happened. */
2415 + skb->nf_debug = olddebug;
2420 +/* Used by ipt_REJECT. */
2421 +static void ip_conntrack_attach(struct sk_buff *nskb, struct nf_ct_info *nfct)
2423 + struct ip_conntrack *ct;
2424 + enum ip_conntrack_info ctinfo;
2426 + ct = __ip_conntrack_get(nfct, &ctinfo);
2428 + /* This ICMP is in reverse direction to the packet which
2430 + if (CTINFO2DIR(ctinfo) == IP_CT_DIR_ORIGINAL)
2431 + ctinfo = IP_CT_RELATED + IP_CT_IS_REPLY;
2433 + ctinfo = IP_CT_RELATED;
2435 + /* Attach new skbuff, and increment count */
2436 + nskb->nfct = &ct->infos[ctinfo];
2437 + atomic_inc(&ct->ct_general.use);
2441 +do_kill(const struct ip_conntrack_tuple_hash *i,
2442 + int (*kill)(const struct ip_conntrack *i, void *data),
2445 + return kill(i->ctrack, data);
2448 +/* Bring out ya dead! */
2449 +static struct ip_conntrack_tuple_hash *
2450 +get_next_corpse(int (*kill)(const struct ip_conntrack *i, void *data),
2451 + void *data, unsigned int *bucket)
2453 + struct ip_conntrack_tuple_hash *h = NULL;
2455 + READ_LOCK(&ip_conntrack_lock);
2456 + for (; !h && *bucket < ip_conntrack_htable_size; (*bucket)++) {
2457 + h = LIST_FIND(&ip_conntrack_hash[*bucket], do_kill,
2458 + struct ip_conntrack_tuple_hash *, kill, data);
2461 + atomic_inc(&h->ctrack->ct_general.use);
2462 + READ_UNLOCK(&ip_conntrack_lock);
2468 +ip_ct_selective_cleanup(int (*kill)(const struct ip_conntrack *i, void *data),
2471 + struct ip_conntrack_tuple_hash *h;
2472 + unsigned int bucket = 0;
2474 + while ((h = get_next_corpse(kill, data, &bucket)) != NULL) {
2475 + /* Time to push up daises... */
2476 + if (del_timer(&h->ctrack->timeout))
2477 + death_by_timeout((unsigned long)h->ctrack);
2478 + /* ... else the timer will get him soon. */
2480 + ip_conntrack_put(h->ctrack);
2484 +/* Fast function for those who don't want to parse /proc (and I don't
2486 +/* Reversing the socket's dst/src point of view gives us the reply
2489 +getorigdst(struct sock *sk, int optval, void *user, int *len)
2491 + struct inet_opt *inet = inet_sk(sk);
2492 + struct ip_conntrack_tuple_hash *h;
2493 + struct ip_conntrack_tuple tuple;
2495 + IP_CT_TUPLE_U_BLANK(&tuple);
2496 + tuple.src.ip = inet->rcv_saddr;
2497 + tuple.src.u.tcp.port = inet->sport;
2498 + tuple.dst.ip = inet->daddr;
2499 + tuple.dst.u.tcp.port = inet->dport;
2500 + tuple.dst.protonum = IPPROTO_TCP;
2502 + /* We only do TCP at the moment: is there a better way? */
2503 + if (strcmp(sk->sk_prot->name, "TCP")) {
2504 + DEBUGP("SO_ORIGINAL_DST: Not a TCP socket\n");
2505 + return -ENOPROTOOPT;
2508 + if ((unsigned int) *len < sizeof(struct sockaddr_in)) {
2509 + DEBUGP("SO_ORIGINAL_DST: len %u not %u\n",
2510 + *len, sizeof(struct sockaddr_in));
2514 + h = ip_conntrack_find_get(&tuple, NULL);
2516 + struct sockaddr_in sin;
2518 + sin.sin_family = AF_INET;
2519 + sin.sin_port = h->ctrack->tuplehash[IP_CT_DIR_ORIGINAL]
2520 + .tuple.dst.u.tcp.port;
2521 + sin.sin_addr.s_addr = h->ctrack->tuplehash[IP_CT_DIR_ORIGINAL]
2524 + DEBUGP("SO_ORIGINAL_DST: %u.%u.%u.%u %u\n",
2525 + NIPQUAD(sin.sin_addr.s_addr), ntohs(sin.sin_port));
2526 + ip_conntrack_put(h->ctrack);
2527 + if (copy_to_user(user, &sin, sizeof(sin)) != 0)
2532 + DEBUGP("SO_ORIGINAL_DST: Can't find %u.%u.%u.%u/%u-%u.%u.%u.%u/%u.\n",
2533 + NIPQUAD(tuple.src.ip), ntohs(tuple.src.u.tcp.port),
2534 + NIPQUAD(tuple.dst.ip), ntohs(tuple.dst.u.tcp.port));
2538 +static struct nf_sockopt_ops so_getorigdst = {
2540 + .get_optmin = SO_ORIGINAL_DST,
2541 + .get_optmax = SO_ORIGINAL_DST+1,
2542 + .get = &getorigdst,
2545 +static int kill_all(const struct ip_conntrack *i, void *data)
2550 +/* Mishearing the voices in his head, our hero wonders how he's
2551 + supposed to kill the mall. */
2552 +void ip_conntrack_cleanup(void)
2554 + ip_ct_attach = NULL;
2555 + /* This makes sure all current packets have passed through
2556 + netfilter framework. Roll on, two-stage module
2558 + synchronize_net();
2560 + i_see_dead_people:
2561 + ip_ct_selective_cleanup(kill_all, NULL);
2562 + if (atomic_read(&ip_conntrack_count) != 0) {
2564 + goto i_see_dead_people;
2567 + kmem_cache_destroy(ip_conntrack_cachep);
2568 + vfree(ip_conntrack_hash);
2569 + nf_unregister_sockopt(&so_getorigdst);
2572 +static int hashsize;
2573 +MODULE_PARM(hashsize, "i");
2575 +int __init ip_conntrack_init(void)
2580 + /* Idea from tcp.c: use 1/16384 of memory. On i386: 32MB
2581 + * machine has 256 buckets. >= 1GB machines have 8192 buckets. */
2583 + ip_conntrack_htable_size = hashsize;
2585 + ip_conntrack_htable_size
2586 + = (((num_physpages << PAGE_SHIFT) / 16384)
2587 + / sizeof(struct list_head));
2588 + if (num_physpages > (1024 * 1024 * 1024 / PAGE_SIZE))
2589 + ip_conntrack_htable_size = 8192;
2590 + if (ip_conntrack_htable_size < 16)
2591 + ip_conntrack_htable_size = 16;
2593 + ip_conntrack_max = 8 * ip_conntrack_htable_size;
2595 + printk("ip_conntrack version %s (%u buckets, %d max)"
2596 + " - %Zd bytes per conntrack\n", IP_CONNTRACK_VERSION,
2597 + ip_conntrack_htable_size, ip_conntrack_max,
2598 + sizeof(struct ip_conntrack));
2600 + ret = nf_register_sockopt(&so_getorigdst);
2602 + printk(KERN_ERR "Unable to register netfilter socket option\n");
2606 + ip_conntrack_hash = vmalloc(sizeof(struct list_head)
2607 + * ip_conntrack_htable_size);
2608 + if (!ip_conntrack_hash) {
2609 + printk(KERN_ERR "Unable to create ip_conntrack_hash\n");
2610 + goto err_unreg_sockopt;
2613 + ip_conntrack_cachep = kmem_cache_create("ip_conntrack",
2614 + sizeof(struct ip_conntrack), 0,
2615 + SLAB_HWCACHE_ALIGN, NULL, NULL);
2616 + if (!ip_conntrack_cachep) {
2617 + printk(KERN_ERR "Unable to create ip_conntrack slab cache\n");
2618 + goto err_free_hash;
2620 + /* Don't NEED lock here, but good form anyway. */
2621 + WRITE_LOCK(&ip_conntrack_lock);
2622 + /* Sew in builtin protocols. */
2623 + list_append(&protocol_list, &ip_conntrack_protocol_tcp);
2624 + list_append(&protocol_list, &ip_conntrack_protocol_udp);
2625 + list_append(&protocol_list, &ip_conntrack_protocol_icmp);
2626 + WRITE_UNLOCK(&ip_conntrack_lock);
2628 + for (i = 0; i < ip_conntrack_htable_size; i++)
2629 + INIT_LIST_HEAD(&ip_conntrack_hash[i]);
2631 + /* For use by ipt_REJECT */
2632 + ip_ct_attach = ip_conntrack_attach;
2634 + /* Set up fake conntrack:
2635 + - to never be deleted, not in any hashes */
2636 + atomic_set(&ip_conntrack_untracked.ct_general.use, 1);
2637 + /* - and look it like as a confirmed connection */
2638 + set_bit(IPS_CONFIRMED_BIT, &ip_conntrack_untracked.status);
2639 + /* - and prepare the ctinfo field for REJECT & NAT. */
2640 + ip_conntrack_untracked.infos[IP_CT_NEW].master =
2641 + ip_conntrack_untracked.infos[IP_CT_RELATED].master =
2642 + ip_conntrack_untracked.infos[IP_CT_RELATED + IP_CT_IS_REPLY].master =
2643 + &ip_conntrack_untracked.ct_general;
2648 + vfree(ip_conntrack_hash);
2650 + nf_unregister_sockopt(&so_getorigdst);
2654 diff -Nur linux-2.6.6-rc1.org/net/ipv4/netfilter/ip_pool.c linux-2.6.6-rc1/net/ipv4/netfilter/ip_pool.c
2655 --- linux-2.6.6-rc1.org/net/ipv4/netfilter/ip_pool.c 1970-01-01 01:00:00.000000000 +0100
2656 +++ linux-2.6.6-rc1/net/ipv4/netfilter/ip_pool.c 2004-04-19 10:08:36.000000000 +0200
2658 +/* Kernel module for IP pool management */
2660 +#include <linux/module.h>
2661 +#include <linux/ip.h>
2662 +#include <linux/skbuff.h>
2663 +#include <linux/netfilter_ipv4/ip_tables.h>
2664 +#include <linux/netfilter_ipv4/ip_pool.h>
2665 +#include <linux/errno.h>
2666 +#include <asm/uaccess.h>
2667 +#include <asm/bitops.h>
2668 +#include <linux/interrupt.h>
2669 +#include <linux/spinlock.h>
2674 +#define DP(format, args...)
2677 +MODULE_LICENSE("GPL");
2680 +static int nr_pool = NR_POOL;/* overwrite this when loading module */
2683 + u_int32_t first_ip; /* host byte order, included in range */
2684 + u_int32_t last_ip; /* host byte order, included in range */
2685 + void *members; /* the bitmap proper */
2686 + int nr_use; /* total nr. of tests through this */
2687 + int nr_match; /* total nr. of matches through this */
2691 +static struct ip_pool *POOL;
2693 +static inline struct ip_pool *lookup(ip_pool_t index)
2695 + if (index < 0 || index >= nr_pool) {
2696 + DP("ip_pool:lookup: bad index %d\n", index);
2699 + return POOL+index;
2702 +int ip_pool_match(ip_pool_t index, u_int32_t addr)
2704 + struct ip_pool *pool = lookup(index);
2707 + if (!pool || !pool->members)
2709 + read_lock_bh(&pool->lock);
2710 + if (pool->members) {
2711 + if (addr >= pool->first_ip && addr <= pool->last_ip) {
2712 + addr -= pool->first_ip;
2713 + if (test_bit(addr, pool->members)) {
2715 +#ifdef CONFIG_IP_POOL_STATISTICS
2720 +#ifdef CONFIG_IP_POOL_STATISTICS
2724 + read_unlock_bh(&pool->lock);
2727 +EXPORT_SYMBOL(ip_pool_match);
2729 +static int pool_change(ip_pool_t index, u_int32_t addr, int isdel)
2731 + struct ip_pool *pool;
2734 + pool = lookup(index);
2735 + if ( !pool || !pool->members
2736 + || addr < pool->first_ip || addr > pool->last_ip)
2738 + read_lock_bh(&pool->lock);
2739 + if (pool->members && addr >= pool->first_ip && addr <= pool->last_ip) {
2740 + addr -= pool->first_ip;
2742 + ? (0 != test_and_clear_bit(addr, pool->members))
2743 + : (0 != test_and_set_bit(addr, pool->members));
2745 + read_unlock_bh(&pool->lock);
2749 +int ip_pool_mod(ip_pool_t index, u_int32_t addr, int isdel)
2751 + int res = pool_change(index,addr,isdel);
2753 + if (!isdel) res = !res;
2756 +EXPORT_SYMBOL(ip_pool_mod);
2758 +static inline int bitmap_bytes(u_int32_t a, u_int32_t b)
2760 + return 4*((((b-a+8)/8)+3)/4);
2763 +static inline int poolbytes(ip_pool_t index)
2765 + struct ip_pool *pool = lookup(index);
2767 + return pool ? bitmap_bytes(pool->first_ip, pool->last_ip) : 0;
2770 +static int setpool(
2776 + struct ip_pool_request req;
2778 + DP("ip_pool:setpool: optval=%d, user=%p, len=%d\n", optval, user, len);
2779 + if (!capable(CAP_NET_ADMIN))
2781 + if (optval != SO_IP_POOL)
2783 + if (len != sizeof(req))
2785 + if (copy_from_user(&req, user, sizeof(req)) != 0)
2787 + printk("obsolete op - upgrade your ippool(8) utility.\n");
2791 +static int getpool(
2797 + struct ip_pool_request req;
2798 + struct ip_pool *pool;
2804 + DP("ip_pool:getpool: optval=%d, user=%p\n", optval, user);
2805 + if (!capable(CAP_NET_ADMIN))
2807 + if (optval != SO_IP_POOL)
2809 + if (*len != sizeof(req)) {
2812 + if (copy_from_user(&req, user, sizeof(req)) != 0)
2814 + DP("ip_pool:getpool op=%d, index=%d\n", req.op, req.index);
2815 + if (req.op < IP_POOL_BAD001) {
2816 + printk("obsolete op - upgrade your ippool(8) utility.\n");
2820 + case IP_POOL_HIGH_NR:
2821 + DP("ip_pool HIGH_NR\n");
2822 + req.index = IP_POOL_NONE;
2823 + for (i=0; i<nr_pool; i++)
2824 + if (POOL[i].members)
2826 + return copy_to_user(user, &req, sizeof(req));
2827 + case IP_POOL_LOOKUP:
2828 + DP("ip_pool LOOKUP\n");
2829 + pool = lookup(req.index);
2832 + if (!pool->members)
2834 + req.addr = htonl(pool->first_ip);
2835 + req.addr2 = htonl(pool->last_ip);
2836 + return copy_to_user(user, &req, sizeof(req));
2837 + case IP_POOL_USAGE:
2838 + DP("ip_pool USE\n");
2839 + pool = lookup(req.index);
2842 + if (!pool->members)
2844 + req.addr = pool->nr_use;
2845 + req.addr2 = pool->nr_match;
2846 + return copy_to_user(user, &req, sizeof(req));
2847 + case IP_POOL_TEST_ADDR:
2848 + DP("ip_pool TEST 0x%08x\n", req.addr);
2849 + pool = lookup(req.index);
2853 + read_lock_bh(&pool->lock);
2854 + if (!pool->members) {
2855 + DP("ip_pool TEST_ADDR no members in pool\n");
2857 + goto unlock_and_return_res;
2859 + req.addr = ntohl(req.addr);
2860 + if (req.addr < pool->first_ip) {
2861 + DP("ip_pool TEST_ADDR address < pool bounds\n");
2863 + goto unlock_and_return_res;
2865 + if (req.addr > pool->last_ip) {
2866 + DP("ip_pool TEST_ADDR address > pool bounds\n");
2868 + goto unlock_and_return_res;
2870 + req.addr = (0 != test_bit((req.addr - pool->first_ip),
2872 + read_unlock_bh(&pool->lock);
2873 + return copy_to_user(user, &req, sizeof(req));
2874 + case IP_POOL_FLUSH:
2875 + DP("ip_pool FLUSH not yet implemented.\n");
2877 + case IP_POOL_DESTROY:
2878 + DP("ip_pool DESTROY not yet implemented.\n");
2880 + case IP_POOL_INIT:
2881 + DP("ip_pool INIT 0x%08x-0x%08x\n", req.addr, req.addr2);
2882 + pool = lookup(req.index);
2885 + req.addr = ntohl(req.addr);
2886 + req.addr2 = ntohl(req.addr2);
2887 + if (req.addr > req.addr2) {
2888 + DP("ip_pool INIT bad ip range\n");
2891 + newbytes = bitmap_bytes(req.addr, req.addr2);
2892 + newmembers = kmalloc(newbytes, GFP_KERNEL);
2893 + if (!newmembers) {
2894 + DP("ip_pool INIT out of mem for %d bytes\n", newbytes);
2897 + memset(newmembers, 0, newbytes);
2898 + write_lock_bh(&pool->lock);
2899 + if (pool->members) {
2900 + DP("ip_pool INIT pool %d exists\n", req.index);
2901 + kfree(newmembers);
2903 + goto unlock_and_return_res;
2905 + pool->first_ip = req.addr;
2906 + pool->last_ip = req.addr2;
2908 + pool->nr_match = 0;
2909 + pool->members = newmembers;
2910 + write_unlock_bh(&pool->lock);
2912 + case IP_POOL_ADD_ADDR:
2913 + DP("ip_pool ADD_ADDR 0x%08x\n", req.addr);
2914 + req.addr = pool_change(req.index, ntohl(req.addr), 0);
2915 + return copy_to_user(user, &req, sizeof(req));
2916 + case IP_POOL_DEL_ADDR:
2917 + DP("ip_pool DEL_ADDR 0x%08x\n", req.addr);
2918 + req.addr = pool_change(req.index, ntohl(req.addr), 1);
2919 + return copy_to_user(user, &req, sizeof(req));
2921 + DP("ip_pool:getpool bad op %d\n", req.op);
2926 +unlock_and_return_res:
2928 + read_unlock_bh(&pool->lock);
2932 +static struct nf_sockopt_ops so_pool
2933 += { { NULL, NULL }, PF_INET,
2934 + SO_IP_POOL, SO_IP_POOL+1, &setpool,
2935 + SO_IP_POOL, SO_IP_POOL+1, &getpool,
2938 +MODULE_PARM(nr_pool, "i");
2940 +static int __init init(void)
2945 + if (nr_pool < 1) {
2946 + printk("ip_pool module init: bad nr_pool %d\n", nr_pool);
2949 + POOL = kmalloc(nr_pool * sizeof(*POOL), GFP_KERNEL);
2951 + printk("ip_pool module init: out of memory for nr_pool %d\n",
2955 + for (i=0; i<nr_pool; i++) {
2956 + POOL[i].first_ip = 0;
2957 + POOL[i].last_ip = 0;
2958 + POOL[i].members = 0;
2959 + POOL[i].nr_use = 0;
2960 + POOL[i].nr_match = 0;
2961 + POOL[i].lock = RW_LOCK_UNLOCKED;
2963 + res = nf_register_sockopt(&so_pool);
2964 + DP("ip_pool:init %d pools, result %d\n", nr_pool, res);
2972 +static void __exit fini(void)
2976 + DP("ip_pool:fini BYEBYE\n");
2977 + nf_unregister_sockopt(&so_pool);
2978 + for (i=0; i<nr_pool; i++) {
2979 + if (POOL[i].members) {
2980 + kfree(POOL[i].members);
2981 + POOL[i].members = 0;
2986 + DP("ip_pool:fini these are the famous last words\n");
2992 diff -Nur linux-2.6.6-rc1.org/net/ipv4/netfilter/ip_tables.c linux-2.6.6-rc1/net/ipv4/netfilter/ip_tables.c
2993 --- linux-2.6.6-rc1.org/net/ipv4/netfilter/ip_tables.c 2004-04-15 03:34:03.000000000 +0200
2994 +++ linux-2.6.6-rc1/net/ipv4/netfilter/ip_tables.c 2004-04-19 10:08:25.000000000 +0200
2995 @@ -1716,9 +1716,9 @@
2998 #ifdef CONFIG_PROC_FS
2999 -static inline int print_name(const char *i,
3000 - off_t start_offset, char *buffer, int length,
3001 - off_t *pos, unsigned int *count)
3002 +static int print_name(const char *i,
3003 + off_t start_offset, char *buffer, int length,
3004 + off_t *pos, unsigned int *count)
3006 if ((*count)++ >= start_offset) {
3007 unsigned int namelen;
3008 @@ -1752,6 +1752,15 @@
3012 +static inline int print_target(const struct ipt_target *t,
3013 + off_t start_offset, char *buffer, int length,
3014 + off_t *pos, unsigned int *count)
3016 + if (t != &ipt_standard_target && t != &ipt_error_target)
3018 + return print_name((char *)t, start_offset, buffer, length, pos, count);
3021 static int ipt_get_targets(char *buffer, char **start, off_t offset, int length)
3024 @@ -1760,7 +1769,7 @@
3025 if (down_interruptible(&ipt_mutex) != 0)
3028 - LIST_FIND(&ipt_target, print_name, void *,
3029 + LIST_FIND(&ipt_target, print_target, struct ipt_target *,
3030 offset, buffer, length, &pos, &count);
3033 diff -Nur linux-2.6.6-rc1.org/net/ipv4/netfilter/ipt_IPV4OPTSSTRIP.c linux-2.6.6-rc1/net/ipv4/netfilter/ipt_IPV4OPTSSTRIP.c
3034 --- linux-2.6.6-rc1.org/net/ipv4/netfilter/ipt_IPV4OPTSSTRIP.c 1970-01-01 01:00:00.000000000 +0100
3035 +++ linux-2.6.6-rc1/net/ipv4/netfilter/ipt_IPV4OPTSSTRIP.c 2004-04-19 10:08:26.000000000 +0200
3038 + * Strip all IP options in the IP packet header.
3040 + * (C) 2001 by Fabrice MARIE <fabrice@netfilter.org>
3041 + * This software is distributed under GNU GPL v2, 1991
3044 +#include <linux/module.h>
3045 +#include <linux/skbuff.h>
3046 +#include <linux/ip.h>
3047 +#include <net/checksum.h>
3049 +#include <linux/netfilter_ipv4/ip_tables.h>
3051 +MODULE_AUTHOR("Fabrice MARIE <fabrice@netfilter.org>");
3052 +MODULE_DESCRIPTION("Strip all options in IPv4 packets");
3053 +MODULE_LICENSE("GPL");
3055 +static unsigned int
3056 +target(struct sk_buff **pskb,
3057 + const struct net_device *in,
3058 + const struct net_device *out,
3059 + unsigned int hooknum,
3060 + const void *targinfo,
3063 + struct iphdr *iph;
3064 + struct sk_buff *skb;
3065 + struct ip_options *opt;
3066 + unsigned char *optiph;
3069 + if (!skb_ip_make_writable(pskb, (*pskb)->len))
3073 + iph = (*pskb)->nh.iph;
3074 + optiph = skb->nh.raw;
3075 + l = ((struct ip_options *)(&(IPCB(skb)->opt)))->optlen;
3077 + /* if no options in packet then nothing to clear. */
3078 + if (iph->ihl * 4 == sizeof(struct iphdr))
3079 + return IPT_CONTINUE;
3081 + /* else clear all options */
3082 + memset(&(IPCB(skb)->opt), 0, sizeof(struct ip_options));
3083 + memset(optiph+sizeof(struct iphdr), IPOPT_NOOP, l);
3084 + opt = &(IPCB(skb)->opt);
3088 + skb->nfcache |= NFC_ALTERED;
3090 + return IPT_CONTINUE;
3094 +checkentry(const char *tablename,
3095 + const struct ipt_entry *e,
3097 + unsigned int targinfosize,
3098 + unsigned int hook_mask)
3100 + if (strcmp(tablename, "mangle")) {
3101 + printk(KERN_WARNING "IPV4OPTSSTRIP: can only be called from \"mangle\" table, not \"%s\"\n", tablename);
3104 + /* nothing else to check because no parameters */
3108 +static struct ipt_target ipt_ipv4optsstrip_reg = {
3109 + .name = "IPV4OPTSSTRIP",
3111 + .checkentry = checkentry,
3112 + .me = THIS_MODULE };
3114 +static int __init init(void)
3116 + return ipt_register_target(&ipt_ipv4optsstrip_reg);
3119 +static void __exit fini(void)
3121 + ipt_unregister_target(&ipt_ipv4optsstrip_reg);
3126 diff -Nur linux-2.6.6-rc1.org/net/ipv4/netfilter/ipt_POOL.c linux-2.6.6-rc1/net/ipv4/netfilter/ipt_POOL.c
3127 --- linux-2.6.6-rc1.org/net/ipv4/netfilter/ipt_POOL.c 1970-01-01 01:00:00.000000000 +0100
3128 +++ linux-2.6.6-rc1/net/ipv4/netfilter/ipt_POOL.c 2004-04-19 10:08:36.000000000 +0200
3130 +/* ipt_POOL.c - netfilter target to manipulate IP pools
3132 + * This target can be used almost everywhere. It acts on some specified
3133 + * IP pool, adding or deleting some IP address in the pool. The address
3134 + * can be either the source (--addsrc, --delsrc), or destination (--add/deldst)
3135 + * of the packet under inspection.
3137 + * The target normally returns IPT_CONTINUE.
3140 +#include <linux/types.h>
3141 +#include <linux/ip.h>
3142 +#include <linux/timer.h>
3143 +#include <linux/module.h>
3144 +#include <linux/netfilter.h>
3145 +#include <linux/netdevice.h>
3146 +#include <linux/if.h>
3147 +#include <linux/inetdevice.h>
3148 +#include <net/protocol.h>
3149 +#include <net/checksum.h>
3150 +#include <linux/netfilter_ipv4.h>
3151 +#include <linux/netfilter_ipv4/ip_nat_rule.h>
3152 +#include <linux/netfilter_ipv4/ipt_pool.h>
3155 +#define DEBUGP printk
3157 +#define DEBUGP(format, args...)
3160 +/*** NOTE NOTE NOTE NOTE ***
3162 +** By sheer luck, I get away with using the "struct ipt_pool_info", as defined
3163 +** in <linux/netfilter_ipv4/ipt_pool.h>, both as the match and target info.
3164 +** Here, in the target implementation, ipt_pool_info.src, if not IP_POOL_NONE,
3165 +** is modified for the source IP address of the packet under inspection.
3166 +** The same way, the ipt_pool_info.dst pool is modified for the destination.
3168 +** The address is added to the pool normally. However, if IPT_POOL_DEL_dir
3169 +** flag is set in ipt_pool_info.flags, the address is deleted from the pool.
3171 +** If a modification was done to the pool, we possibly return ACCEPT or DROP,
3172 +** if the right IPT_POOL_MOD_dir_ACCEPT or _MOD_dir_DROP flags are set.
3173 +** The IPT_POOL_INV_MOD_dir flag inverts the sense of the check (i.e. the
3174 +** ACCEPT and DROP flags are evaluated when the pool was not modified.)
3178 +do_check(const char *tablename,
3179 + const struct ipt_entry *e,
3181 + unsigned int targinfosize,
3182 + unsigned int hook_mask)
3184 + const struct ipt_pool_info *ipi = targinfo;
3186 + if (targinfosize != IPT_ALIGN(sizeof(*ipi))) {
3187 + DEBUGP("POOL_check: size %u.\n", targinfosize);
3190 + DEBUGP("ipt_POOL:do_check(%d,%d,%d)\n",ipi->src,ipi->dst,ipi->flags);
3194 +static unsigned int
3195 +do_target(struct sk_buff **pskb,
3196 + unsigned int hooknum,
3197 + const struct net_device *in,
3198 + const struct net_device *out,
3199 + const void *targinfo,
3202 + const struct ipt_pool_info *ipi = targinfo;
3204 + unsigned int verdict = IPT_CONTINUE;
3206 + if (ipi->src != IP_POOL_NONE) {
3207 + modified = ip_pool_mod(ipi->src, ntohl((*pskb)->nh.iph->saddr),
3208 + ipi->flags & IPT_POOL_DEL_SRC);
3209 + if (!!modified ^ !!(ipi->flags & IPT_POOL_INV_MOD_SRC)) {
3210 + if (ipi->flags & IPT_POOL_MOD_SRC_ACCEPT)
3211 + verdict = NF_ACCEPT;
3212 + else if (ipi->flags & IPT_POOL_MOD_SRC_DROP)
3213 + verdict = NF_DROP;
3216 + if (verdict == IPT_CONTINUE && ipi->dst != IP_POOL_NONE) {
3217 + modified = ip_pool_mod(ipi->dst, ntohl((*pskb)->nh.iph->daddr),
3218 + ipi->flags & IPT_POOL_DEL_DST);
3219 + if (!!modified ^ !!(ipi->flags & IPT_POOL_INV_MOD_DST)) {
3220 + if (ipi->flags & IPT_POOL_MOD_DST_ACCEPT)
3221 + verdict = NF_ACCEPT;
3222 + else if (ipi->flags & IPT_POOL_MOD_DST_DROP)
3223 + verdict = NF_DROP;
3229 +static struct ipt_target pool_reg
3230 += { { NULL, NULL }, "POOL", do_target, do_check, NULL, THIS_MODULE };
3232 +static int __init init(void)
3234 + DEBUGP("init ipt_POOL\n");
3235 + return ipt_register_target(&pool_reg);
3238 +static void __exit fini(void)
3240 + DEBUGP("fini ipt_POOL\n");
3241 + ipt_unregister_target(&pool_reg);
3246 diff -Nur linux-2.6.6-rc1.org/net/ipv4/netfilter/ipt_TTL.c linux-2.6.6-rc1/net/ipv4/netfilter/ipt_TTL.c
3247 --- linux-2.6.6-rc1.org/net/ipv4/netfilter/ipt_TTL.c 1970-01-01 01:00:00.000000000 +0100
3248 +++ linux-2.6.6-rc1/net/ipv4/netfilter/ipt_TTL.c 2004-04-19 10:08:28.000000000 +0200
3250 +/* TTL modification target for IP tables
3251 + * (C) 2000 by Harald Welte <laforge@gnumonks.org>
3253 + * Version: $Revision$
3255 + * This software is distributed under the terms of GNU GPL
3258 +#include <linux/module.h>
3259 +#include <linux/skbuff.h>
3260 +#include <linux/ip.h>
3261 +#include <net/checksum.h>
3263 +#include <linux/netfilter_ipv4/ip_tables.h>
3264 +#include <linux/netfilter_ipv4/ipt_TTL.h>
3266 +MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
3267 +MODULE_DESCRIPTION("IP tables TTL modification module");
3268 +MODULE_LICENSE("GPL");
3270 +static unsigned int
3271 +ipt_ttl_target(struct sk_buff **pskb, const struct net_device *in,
3272 + const struct net_device *out, unsigned int hooknum,
3273 + const void *targinfo, void *userinfo)
3275 + struct iphdr *iph;
3276 + const struct ipt_TTL_info *info = targinfo;
3277 + u_int16_t diffs[2];
3280 + if (!skb_ip_make_writable(pskb, (*pskb)->len))
3283 + iph = (*pskb)->nh.iph;
3285 + switch (info->mode) {
3287 + new_ttl = info->ttl;
3290 + new_ttl = iph->ttl + info->ttl;
3291 + if (new_ttl > 255)
3295 + new_ttl = iph->ttl + info->ttl;
3300 + new_ttl = iph->ttl;
3304 + if (new_ttl != iph->ttl) {
3305 + diffs[0] = htons(((unsigned)iph->ttl) << 8) ^ 0xFFFF;
3306 + iph->ttl = new_ttl;
3307 + diffs[1] = htons(((unsigned)iph->ttl) << 8);
3308 + iph->check = csum_fold(csum_partial((char *)diffs,
3310 + iph->check^0xFFFF));
3311 + (*pskb)->nfcache |= NFC_ALTERED;
3314 + return IPT_CONTINUE;
3317 +static int ipt_ttl_checkentry(const char *tablename,
3318 + const struct ipt_entry *e,
3320 + unsigned int targinfosize,
3321 + unsigned int hook_mask)
3323 + struct ipt_TTL_info *info = targinfo;
3325 + if (targinfosize != IPT_ALIGN(sizeof(struct ipt_TTL_info))) {
3326 + printk(KERN_WARNING "TTL: targinfosize %u != %Zu\n",
3328 + IPT_ALIGN(sizeof(struct ipt_TTL_info)));
3332 + if (strcmp(tablename, "mangle")) {
3333 + printk(KERN_WARNING "TTL: can only be called from \"mangle\" table, not \"%s\"\n", tablename);
3337 + if (info->mode > IPT_TTL_MAXMODE) {
3338 + printk(KERN_WARNING "TTL: invalid or unknown Mode %u\n",
3343 + if ((info->mode != IPT_TTL_SET) && (info->ttl == 0)) {
3344 + printk(KERN_WARNING "TTL: increment/decrement doesn't make sense with value 0\n");
3351 +static struct ipt_target ipt_TTL = {
3353 + .target = ipt_ttl_target,
3354 + .checkentry = ipt_ttl_checkentry,
3358 +static int __init init(void)
3360 + return ipt_register_target(&ipt_TTL);
3363 +static void __exit fini(void)
3365 + ipt_unregister_target(&ipt_TTL);
3370 diff -Nur linux-2.6.6-rc1.org/net/ipv4/netfilter/ipt_connlimit.c linux-2.6.6-rc1/net/ipv4/netfilter/ipt_connlimit.c
3371 --- linux-2.6.6-rc1.org/net/ipv4/netfilter/ipt_connlimit.c 1970-01-01 01:00:00.000000000 +0100
3372 +++ linux-2.6.6-rc1/net/ipv4/netfilter/ipt_connlimit.c 2004-04-19 10:08:29.000000000 +0200
3375 + * netfilter module to limit the number of parallel tcp
3376 + * connections per IP address.
3377 + * (c) 2000 Gerd Knorr <kraxel@bytesex.org>
3378 + * Nov 2002: Martin Bene <martin.bene@icomedias.com>:
3379 + * only ignore TIME_WAIT or gone connections
3383 + * Kernel module to match connection tracking information.
3384 + * GPL (C) 1999 Rusty Russell (rusty@rustcorp.com.au).
3386 +#include <linux/module.h>
3387 +#include <linux/skbuff.h>
3388 +#include <linux/list.h>
3389 +#include <linux/netfilter_ipv4/ip_conntrack.h>
3390 +#include <linux/netfilter_ipv4/ip_conntrack_core.h>
3391 +#include <linux/netfilter_ipv4/ip_conntrack_tcp.h>
3392 +#include <linux/netfilter_ipv4/ip_tables.h>
3393 +#include <linux/netfilter_ipv4/ipt_connlimit.h>
3397 +MODULE_LICENSE("GPL");
3399 +/* we'll save the tuples of all connections we care about */
3400 +struct ipt_connlimit_conn
3402 + struct list_head list;
3403 + struct ip_conntrack_tuple tuple;
3406 +struct ipt_connlimit_data {
3408 + struct list_head iphash[256];
3411 +static int ipt_iphash(u_int32_t addr)
3415 + hash = addr & 0xff;
3416 + hash ^= (addr >> 8) & 0xff;
3417 + hash ^= (addr >> 16) & 0xff;
3418 + hash ^= (addr >> 24) & 0xff;
3422 +static int count_them(struct ipt_connlimit_data *data,
3423 + u_int32_t addr, u_int32_t mask,
3424 + struct ip_conntrack *ct)
3427 + const static char *tcp[] = { "none", "established", "syn_sent", "syn_recv",
3428 + "fin_wait", "time_wait", "close", "close_wait",
3429 + "last_ack", "listen" };
3431 + int addit = 1, matches = 0;
3432 + struct ip_conntrack_tuple tuple;
3433 + struct ip_conntrack_tuple_hash *found;
3434 + struct ipt_connlimit_conn *conn;
3435 + struct list_head *hash,*lh;
3437 + spin_lock(&data->lock);
3438 + tuple = ct->tuplehash[0].tuple;
3439 + hash = &data->iphash[ipt_iphash(addr & mask)];
3441 + /* check the saved connections */
3442 + for (lh = hash->next; lh != hash; lh = lh->next) {
3443 + conn = list_entry(lh,struct ipt_connlimit_conn,list);
3444 + found = ip_conntrack_find_get(&conn->tuple,ct);
3445 + if (0 == memcmp(&conn->tuple,&tuple,sizeof(tuple)) &&
3447 + found->ctrack->proto.tcp.state != TCP_CONNTRACK_TIME_WAIT) {
3448 + /* Just to be sure we have it only once in the list.
3449 + We should'nt see tuples twice unless someone hooks this
3450 + into a table without "-p tcp --syn" */
3454 + printk("ipt_connlimit [%d]: src=%u.%u.%u.%u:%d dst=%u.%u.%u.%u:%d %s\n",
3455 + ipt_iphash(addr & mask),
3456 + NIPQUAD(conn->tuple.src.ip), ntohs(conn->tuple.src.u.tcp.port),
3457 + NIPQUAD(conn->tuple.dst.ip), ntohs(conn->tuple.dst.u.tcp.port),
3458 + (NULL != found) ? tcp[found->ctrack->proto.tcp.state] : "gone");
3460 + if (NULL == found) {
3461 + /* this one is gone */
3463 + list_del(lh->next);
3467 + if (found->ctrack->proto.tcp.state == TCP_CONNTRACK_TIME_WAIT) {
3468 + /* we don't care about connections which are
3469 + closed already -> ditch it */
3471 + list_del(lh->next);
3473 + nf_conntrack_put(&found->ctrack->infos[0]);
3476 + if ((addr & mask) == (conn->tuple.src.ip & mask)) {
3477 + /* same source IP address -> be counted! */
3480 + nf_conntrack_put(&found->ctrack->infos[0]);
3483 + /* save the new connection in our list */
3485 + printk("ipt_connlimit [%d]: src=%u.%u.%u.%u:%d dst=%u.%u.%u.%u:%d new\n",
3486 + ipt_iphash(addr & mask),
3487 + NIPQUAD(tuple.src.ip), ntohs(tuple.src.u.tcp.port),
3488 + NIPQUAD(tuple.dst.ip), ntohs(tuple.dst.u.tcp.port));
3490 + conn = kmalloc(sizeof(*conn),GFP_ATOMIC);
3493 + memset(conn,0,sizeof(*conn));
3494 + INIT_LIST_HEAD(&conn->list);
3495 + conn->tuple = tuple;
3496 + list_add(&conn->list,hash);
3499 + spin_unlock(&data->lock);
3504 +match(const struct sk_buff *skb,
3505 + const struct net_device *in,
3506 + const struct net_device *out,
3507 + const void *matchinfo,
3511 + const struct ipt_connlimit_info *info = matchinfo;
3512 + int connections, match;
3513 + struct ip_conntrack *ct;
3514 + enum ip_conntrack_info ctinfo;
3516 + ct = ip_conntrack_get((struct sk_buff *)skb, &ctinfo);
3518 + printk("ipt_connlimit: Oops: invalid ct state ?\n");
3522 + connections = count_them(info->data,skb->nh.iph->saddr,info->mask,ct);
3523 + if (-1 == connections) {
3524 + printk("ipt_connlimit: Hmm, kmalloc failed :-(\n");
3525 + *hotdrop = 1; /* let's free some memory :-) */
3528 + match = (info->inverse) ? (connections <= info->limit) : (connections > info->limit);
3530 + printk("ipt_connlimit: src=%u.%u.%u.%u mask=%u.%u.%u.%u "
3531 + "connections=%d limit=%d match=%s\n",
3532 + NIPQUAD(skb->nh.iph->saddr), NIPQUAD(info->mask),
3533 + connections, info->limit, match ? "yes" : "no");
3539 +static int check(const char *tablename,
3540 + const struct ipt_ip *ip,
3542 + unsigned int matchsize,
3543 + unsigned int hook_mask)
3545 + struct ipt_connlimit_info *info = matchinfo;
3549 + if (matchsize != IPT_ALIGN(sizeof(struct ipt_connlimit_info)))
3552 + /* refuse anything but tcp */
3553 + if (ip->proto != IPPROTO_TCP)
3556 + /* init private data */
3557 + info->data = kmalloc(sizeof(struct ipt_connlimit_data),GFP_KERNEL);
3558 + spin_lock_init(&(info->data->lock));
3559 + for (i = 0; i < 256; i++)
3560 + INIT_LIST_HEAD(&(info->data->iphash[i]));
3565 +static void destroy(void *matchinfo, unsigned int matchinfosize)
3567 + struct ipt_connlimit_info *info = matchinfo;
3568 + struct ipt_connlimit_conn *conn;
3569 + struct list_head *hash;
3573 + for (i = 0; i < 256; i++) {
3574 + hash = &(info->data->iphash[i]);
3575 + while (hash != hash->next) {
3576 + conn = list_entry(hash->next,struct ipt_connlimit_conn,list);
3577 + list_del(hash->next);
3581 + kfree(info->data);
3584 +static struct ipt_match connlimit_match = {
3585 + .name = "connlimit",
3587 + .checkentry = &check,
3588 + .destroy = &destroy,
3592 +static int __init init(void)
3594 + return ipt_register_match(&connlimit_match);
3597 +static void __exit fini(void)
3599 + ipt_unregister_match(&connlimit_match);
3604 diff -Nur linux-2.6.6-rc1.org/net/ipv4/netfilter/ipt_dstlimit.c linux-2.6.6-rc1/net/ipv4/netfilter/ipt_dstlimit.c
3605 --- linux-2.6.6-rc1.org/net/ipv4/netfilter/ipt_dstlimit.c 1970-01-01 01:00:00.000000000 +0100
3606 +++ linux-2.6.6-rc1/net/ipv4/netfilter/ipt_dstlimit.c 2004-04-19 10:08:30.000000000 +0200
3608 +/* iptables match extension to limit the number of packets per second
3609 + * seperately for each destination.
3611 + * (C) 2003 by Harald Welte <laforge@netfilter.org>
3615 + * Development of this code was funded by Astaro AG, http://www.astaro.com/
3617 + * based on ipt_limit.c by:
3618 + * Jérôme de Vivie <devivie@info.enserb.u-bordeaux.fr>
3619 + * Hervé Eychenne <eychenne@info.enserb.u-bordeaux.fr>
3620 + * Rusty Russell <rusty@rustcorp.com.au>
3622 + * The general idea is to create a hash table for every dstip and have a
3623 + * seperate limit counter per tuple. This way you can do something like 'limit
3624 + * the number of syn packets for each of my internal addresses.
3626 + * Ideally this would just be implemented as a general 'hash' match, which would
3627 + * allow us to attach any iptables target to it's hash buckets. But this is
3628 + * not possible in the current iptables architecture. As always, pkttables for
3629 + * 2.7.x will help ;)
3631 +#include <linux/module.h>
3632 +#include <linux/skbuff.h>
3633 +#include <linux/spinlock.h>
3634 +#include <linux/random.h>
3635 +#include <linux/jhash.h>
3636 +#include <linux/slab.h>
3637 +#include <linux/vmalloc.h>
3638 +#include <linux/tcp.h>
3639 +#include <linux/udp.h>
3640 +#include <linux/proc_fs.h>
3641 +#include <linux/seq_file.h>
3643 +#define ASSERT_READ_LOCK(x)
3644 +#define ASSERT_WRITE_LOCK(x)
3645 +#include <linux/netfilter_ipv4/lockhelp.h>
3646 +#include <linux/netfilter_ipv4/listhelp.h>
3648 +#include <linux/netfilter_ipv4/ip_tables.h>
3649 +#include <linux/netfilter_ipv4/ipt_dstlimit.h>
3651 +/* FIXME: this is just for IP_NF_ASSERRT */
3652 +#include <linux/netfilter_ipv4/ip_conntrack.h>
3654 +#define MS2JIFFIES(x) ((x*HZ)/1000)
3656 +MODULE_LICENSE("GPL");
3657 +MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
3658 +MODULE_DESCRIPTION("iptables match for limiting per destination");
3660 +/* need to declare this at the top */
3661 +static struct proc_dir_entry *dstlimit_procdir;
3662 +static struct file_operations dl_file_ops;
3664 +/* hash table crap */
3666 +struct dsthash_dst {
3672 +struct dsthash_ent {
3673 + /* static / read-only parts in the beginning */
3674 + struct list_head list;
3675 + struct dsthash_dst dst;
3677 + /* modified structure members in the end */
3678 + unsigned long expires; /* precalculated expiry time */
3680 + unsigned long prev; /* last modification */
3682 + u_int32_t credit_cap, cost;
3686 +struct ipt_dstlimit_htable {
3687 + struct list_head list; /* global list of all htables */
3690 + struct dstlimit_cfg cfg; /* config */
3692 + /* used internally */
3693 + spinlock_t lock; /* lock for list_head */
3694 + u_int32_t rnd; /* random seed for hash */
3695 + struct timer_list timer; /* timer for gc */
3696 + atomic_t count; /* number entries in table */
3698 + /* seq_file stuff */
3699 + struct proc_dir_entry *pde;
3701 + struct list_head hash[0]; /* hashtable itself */
3704 +DECLARE_RWLOCK(dstlimit_lock); /* protects htables list */
3705 +static LIST_HEAD(dstlimit_htables);
3706 +static kmem_cache_t *dstlimit_cachep;
3708 +static inline int dst_cmp(const struct dsthash_ent *ent, struct dsthash_dst *b)
3710 + return (ent->dst.dst_ip == b->dst_ip
3711 + && ent->dst.port == b->port
3712 + && ent->dst.src_ip == b->src_ip);
3715 +static inline u_int32_t
3716 +hash_dst(const struct ipt_dstlimit_htable *ht, const struct dsthash_dst *dst)
3718 + return (jhash_3words(dst->dst_ip, dst->port,
3719 + dst->src_ip, ht->rnd) % ht->cfg.size);
3722 +static inline struct dsthash_ent *
3723 +__dsthash_find(const struct ipt_dstlimit_htable *ht, struct dsthash_dst *dst)
3725 + struct dsthash_ent *ent;
3726 + u_int32_t hash = hash_dst(ht, dst);
3727 + MUST_BE_LOCKED(&ht->lock);
3728 + ent = LIST_FIND(&ht->hash[hash], dst_cmp, struct dsthash_ent *, dst);
3732 +/* allocate dsthash_ent, initialize dst, put in htable and lock it */
3733 +static struct dsthash_ent *
3734 +__dsthash_alloc_init(struct ipt_dstlimit_htable *ht, struct dsthash_dst *dst)
3736 + struct dsthash_ent *ent;
3738 + /* initialize hash with random val at the time we allocate
3739 + * the first hashtable entry */
3741 + get_random_bytes(&ht->rnd, 4);
3743 + if (ht->cfg.max &&
3744 + atomic_read(&ht->count) >= ht->cfg.max) {
3745 + /* FIXME: do something. question is what.. */
3746 + if (net_ratelimit())
3747 + printk(KERN_WARNING
3748 + "ipt_dstlimit: max count of %u reached\n",
3753 + ent = kmem_cache_alloc(dstlimit_cachep, GFP_ATOMIC);
3755 + if (net_ratelimit())
3757 + "ipt_dstlimit: can't allocate dsthash_ent\n");
3761 + atomic_inc(&ht->count);
3763 + ent->dst.dst_ip = dst->dst_ip;
3764 + ent->dst.port = dst->port;
3765 + ent->dst.src_ip = dst->src_ip;
3767 + list_add(&ent->list, &ht->hash[hash_dst(ht, dst)]);
3773 +__dsthash_free(struct ipt_dstlimit_htable *ht, struct dsthash_ent *ent)
3775 + MUST_BE_LOCKED(&ht->lock);
3777 + list_del(&ent->list);
3778 + kmem_cache_free(dstlimit_cachep, ent);
3779 + atomic_dec(&ht->count);
3781 +static void htable_gc(unsigned long htlong);
3783 +static int htable_create(struct ipt_dstlimit_info *minfo)
3786 + unsigned int size;
3787 + struct ipt_dstlimit_htable *hinfo;
3789 + if (minfo->cfg.size)
3790 + size = minfo->cfg.size;
3792 + size = (((num_physpages << PAGE_SHIFT) / 16384)
3793 + / sizeof(struct list_head));
3794 + if (num_physpages > (1024 * 1024 * 1024 / PAGE_SIZE))
3799 + /* FIXME: don't use vmalloc() here or anywhere else -HW */
3800 + hinfo = vmalloc(sizeof(struct ipt_dstlimit_htable)
3801 + + (sizeof(struct list_head) * size));
3803 + printk(KERN_ERR "ipt_dstlimit: Unable to create hashtable\n");
3806 + minfo->hinfo = hinfo;
3808 + /* copy match config into hashtable config */
3809 + memcpy(&hinfo->cfg, &minfo->cfg, sizeof(hinfo->cfg));
3810 + hinfo->cfg.size = size;
3811 + if (!hinfo->cfg.max)
3812 + hinfo->cfg.max = 8 * hinfo->cfg.size;
3813 + else if (hinfo->cfg.max < hinfo->cfg.size)
3814 + hinfo->cfg.max = hinfo->cfg.size;
3816 + for (i = 0; i < hinfo->cfg.size; i++)
3817 + INIT_LIST_HEAD(&hinfo->hash[i]);
3819 + atomic_set(&hinfo->count, 0);
3820 + atomic_set(&hinfo->use, 1);
3822 + hinfo->lock = SPIN_LOCK_UNLOCKED;
3823 + hinfo->pde = create_proc_entry(minfo->name, 0, dstlimit_procdir);
3824 + if (!hinfo->pde) {
3828 + hinfo->pde->proc_fops = &dl_file_ops;
3829 + hinfo->pde->data = hinfo;
3831 + init_timer(&hinfo->timer);
3832 + hinfo->timer.expires = jiffies + MS2JIFFIES(hinfo->cfg.gc_interval);
3833 + hinfo->timer.data = (unsigned long )hinfo;
3834 + hinfo->timer.function = htable_gc;
3835 + add_timer(&hinfo->timer);
3837 + WRITE_LOCK(&dstlimit_lock);
3838 + list_add(&hinfo->list, &dstlimit_htables);
3839 + WRITE_UNLOCK(&dstlimit_lock);
3844 +static int select_all(struct ipt_dstlimit_htable *ht, struct dsthash_ent *he)
3849 +static int select_gc(struct ipt_dstlimit_htable *ht, struct dsthash_ent *he)
3851 + return (jiffies >= he->expires);
3854 +static void htable_selective_cleanup(struct ipt_dstlimit_htable *ht,
3855 + int (*select)(struct ipt_dstlimit_htable *ht,
3856 + struct dsthash_ent *he))
3860 + IP_NF_ASSERT(ht->cfg.size && ht->cfg.max);
3862 + /* lock hash table and iterate over it */
3863 + LOCK_BH(&ht->lock);
3864 + for (i = 0; i < ht->cfg.size; i++) {
3865 + struct dsthash_ent *dh, *n;
3866 + list_for_each_entry_safe(dh, n, &ht->hash[i], list) {
3867 + if ((*select)(ht, dh))
3868 + __dsthash_free(ht, dh);
3871 + UNLOCK_BH(&ht->lock);
3874 +/* hash table garbage collector, run by timer */
3875 +static void htable_gc(unsigned long htlong)
3877 + struct ipt_dstlimit_htable *ht = (struct ipt_dstlimit_htable *)htlong;
3879 + htable_selective_cleanup(ht, select_gc);
3881 + /* re-add the timer accordingly */
3882 + ht->timer.expires = jiffies + MS2JIFFIES(ht->cfg.gc_interval);
3883 + add_timer(&ht->timer);
3886 +static void htable_destroy(struct ipt_dstlimit_htable *hinfo)
3888 + /* remove timer, if it is pending */
3889 + if (timer_pending(&hinfo->timer))
3890 + del_timer(&hinfo->timer);
3892 + /* remove proc entry */
3893 + remove_proc_entry(hinfo->pde->name, dstlimit_procdir);
3895 + htable_selective_cleanup(hinfo, select_all);
3899 +static struct ipt_dstlimit_htable *htable_find_get(char *name)
3901 + struct ipt_dstlimit_htable *hinfo;
3903 + READ_LOCK(&dstlimit_lock);
3904 + list_for_each_entry(hinfo, &dstlimit_htables, list) {
3905 + if (!strcmp(name, hinfo->pde->name)) {
3906 + atomic_inc(&hinfo->use);
3907 + READ_UNLOCK(&dstlimit_lock);
3911 + READ_UNLOCK(&dstlimit_lock);
3916 +static void htable_put(struct ipt_dstlimit_htable *hinfo)
3918 + if (atomic_dec_and_test(&hinfo->use)) {
3919 + WRITE_LOCK(&dstlimit_lock);
3920 + list_del(&hinfo->list);
3921 + WRITE_UNLOCK(&dstlimit_lock);
3922 + htable_destroy(hinfo);
3927 +/* The algorithm used is the Simple Token Bucket Filter (TBF)
3928 + * see net/sched/sch_tbf.c in the linux source tree
3931 +/* Rusty: This is my (non-mathematically-inclined) understanding of
3932 + this algorithm. The `average rate' in jiffies becomes your initial
3933 + amount of credit `credit' and the most credit you can ever have
3934 + `credit_cap'. The `peak rate' becomes the cost of passing the
3937 + `prev' tracks the last packet hit: you gain one credit per jiffy.
3938 + If you get credit balance more than this, the extra credit is
3939 + discarded. Every time the match passes, you lose `cost' credits;
3940 + if you don't have that many, the test fails.
3942 + See Alexey's formal explanation in net/sched/sch_tbf.c.
3944 + To get the maximum range, we multiply by this factor (ie. you get N
3945 + credits per jiffy). We want to allow a rate as low as 1 per day
3946 + (slowest userspace tool allows), which means
3947 + CREDITS_PER_JIFFY*HZ*60*60*24 < 2^32 ie.
3949 +#define MAX_CPJ (0xFFFFFFFF / (HZ*60*60*24))
3951 +/* Repeated shift and or gives us all 1s, final shift and add 1 gives
3952 + * us the power of 2 below the theoretical max, so GCC simply does a
3954 +#define _POW2_BELOW2(x) ((x)|((x)>>1))
3955 +#define _POW2_BELOW4(x) (_POW2_BELOW2(x)|_POW2_BELOW2((x)>>2))
3956 +#define _POW2_BELOW8(x) (_POW2_BELOW4(x)|_POW2_BELOW4((x)>>4))
3957 +#define _POW2_BELOW16(x) (_POW2_BELOW8(x)|_POW2_BELOW8((x)>>8))
3958 +#define _POW2_BELOW32(x) (_POW2_BELOW16(x)|_POW2_BELOW16((x)>>16))
3959 +#define POW2_BELOW32(x) ((_POW2_BELOW32(x)>>1) + 1)
3961 +#define CREDITS_PER_JIFFY POW2_BELOW32(MAX_CPJ)
3963 +/* Precision saver. */
3964 +static inline u_int32_t
3965 +user2credits(u_int32_t user)
3967 + /* If multiplying would overflow... */
3968 + if (user > 0xFFFFFFFF / (HZ*CREDITS_PER_JIFFY))
3969 + /* Divide first. */
3970 + return (user / IPT_DSTLIMIT_SCALE) * HZ * CREDITS_PER_JIFFY;
3972 + return (user * HZ * CREDITS_PER_JIFFY) / IPT_DSTLIMIT_SCALE;
3975 +static inline void rateinfo_recalc(struct dsthash_ent *dh, unsigned long now)
3977 + dh->rateinfo.credit += (now - xchg(&dh->rateinfo.prev, now))
3978 + * CREDITS_PER_JIFFY;
3979 + if (dh->rateinfo.credit > dh->rateinfo.credit_cap)
3980 + dh->rateinfo.credit = dh->rateinfo.credit_cap;
3984 +dstlimit_match(const struct sk_buff *skb,
3985 + const struct net_device *in,
3986 + const struct net_device *out,
3987 + const void *matchinfo,
3991 + struct ipt_dstlimit_info *r =
3992 + ((struct ipt_dstlimit_info *)matchinfo)->u.master;
3993 + struct ipt_dstlimit_htable *hinfo = r->hinfo;
3994 + unsigned long now = jiffies;
3995 + struct dsthash_ent *dh;
3996 + struct dsthash_dst dst;
3998 + memset(&dst, 0, sizeof(dst));
4000 + /* dest ip is always in hash */
4001 + dst.dst_ip = skb->nh.iph->daddr;
4003 + /* source ip only if respective hashmode, otherwise set to
4005 + if (hinfo->cfg.mode & IPT_DSTLIMIT_HASH_SIP)
4006 + dst.src_ip = skb->nh.iph->saddr;
4008 + /* dest port only if respective mode */
4009 + if (hinfo->cfg.mode & IPT_DSTLIMIT_HASH_DPT) {
4012 + /* Must not be a fragment. */
4016 + /* Must be big enough to read ports (both UDP and TCP have
4017 + them at the start). */
4018 + if (skb_copy_bits(skb, skb->nh.iph->ihl*4, ports, sizeof(ports)) < 0) {
4019 + /* We've been asked to examine this packet, and we
4020 + can't. Hence, no choice but to drop. */
4025 + switch (skb->nh.iph->protocol) {
4026 + struct tcphdr *th;
4027 + struct udphdr *uh;
4029 + th = (void *)skb->nh.iph+skb->nh.iph->ihl*4;
4030 + dst.port = th->dest;
4033 + uh = (void *)skb->nh.iph+skb->nh.iph->ihl*4;
4034 + dst.port = uh->dest;
4041 + LOCK_BH(&hinfo->lock);
4042 + dh = __dsthash_find(hinfo, &dst);
4044 + dh = __dsthash_alloc_init(hinfo, &dst);
4047 + /* enomem... don't match == DROP */
4048 + if (net_ratelimit())
4049 + printk(KERN_ERR "%s: ENOMEM\n", __FUNCTION__);
4050 + UNLOCK_BH(&hinfo->lock);
4054 + dh->expires = jiffies + MS2JIFFIES(hinfo->cfg.expire);
4056 + dh->rateinfo.prev = jiffies;
4057 + dh->rateinfo.credit = user2credits(hinfo->cfg.avg *
4058 + hinfo->cfg.burst);
4059 + dh->rateinfo.credit_cap = user2credits(hinfo->cfg.avg *
4060 + hinfo->cfg.burst);
4061 + dh->rateinfo.cost = user2credits(hinfo->cfg.avg);
4063 + UNLOCK_BH(&hinfo->lock);
4067 + /* update expiration timeout */
4068 + dh->expires = now + MS2JIFFIES(hinfo->cfg.expire);
4070 + rateinfo_recalc(dh, now);
4071 + if (dh->rateinfo.credit >= dh->rateinfo.cost) {
4072 + /* We're underlimit. */
4073 + dh->rateinfo.credit -= dh->rateinfo.cost;
4074 + UNLOCK_BH(&hinfo->lock);
4078 + UNLOCK_BH(&hinfo->lock);
4080 + /* default case: we're overlimit, thus don't match */
4085 +dstlimit_checkentry(const char *tablename,
4086 + const struct ipt_ip *ip,
4088 + unsigned int matchsize,
4089 + unsigned int hook_mask)
4091 + struct ipt_dstlimit_info *r = matchinfo;
4093 + if (matchsize != IPT_ALIGN(sizeof(struct ipt_dstlimit_info)))
4096 + /* Check for overflow. */
4097 + if (r->cfg.burst == 0
4098 + || user2credits(r->cfg.avg * r->cfg.burst) <
4099 + user2credits(r->cfg.avg)) {
4100 + printk(KERN_ERR "ipt_dstlimit: Overflow, try lower: %u/%u\n",
4101 + r->cfg.avg, r->cfg.burst);
4105 + if (r->cfg.mode == 0
4106 + || r->cfg.mode > (IPT_DSTLIMIT_HASH_DPT
4107 + |IPT_DSTLIMIT_HASH_DIP
4108 + |IPT_DSTLIMIT_HASH_SIP))
4111 + if (!r->cfg.gc_interval)
4114 + if (!r->cfg.expire)
4117 + r->hinfo = htable_find_get(r->name);
4118 + if (!r->hinfo && (htable_create(r) != 0)) {
4122 + /* Ugly hack: For SMP, we only want to use one set */
4129 +dstlimit_destroy(void *matchinfo, unsigned int matchsize)
4131 + struct ipt_dstlimit_info *r = (struct ipt_dstlimit_info *) matchinfo;
4133 + htable_put(r->hinfo);
4136 +static struct ipt_match ipt_dstlimit = {
4137 + .list = { .prev = NULL, .next = NULL },
4138 + .name = "dstlimit",
4139 + .match = dstlimit_match,
4140 + .checkentry = dstlimit_checkentry,
4141 + .destroy = dstlimit_destroy,
4147 +static void *dl_seq_start(struct seq_file *s, loff_t *pos)
4149 + struct proc_dir_entry *pde = s->private;
4150 + struct ipt_dstlimit_htable *htable = pde->data;
4151 + unsigned int *bucket;
4153 + LOCK_BH(&htable->lock);
4154 + if (*pos >= htable->cfg.size)
4157 + bucket = kmalloc(sizeof(unsigned int), GFP_KERNEL);
4159 + return ERR_PTR(-ENOMEM);
4165 +static void *dl_seq_next(struct seq_file *s, void *v, loff_t *pos)
4167 + struct proc_dir_entry *pde = s->private;
4168 + struct ipt_dstlimit_htable *htable = pde->data;
4169 + unsigned int *bucket = (unsigned int *)v;
4171 + *pos = ++(*bucket);
4172 + if (*pos >= htable->cfg.size) {
4179 +static void dl_seq_stop(struct seq_file *s, void *v)
4181 + struct proc_dir_entry *pde = s->private;
4182 + struct ipt_dstlimit_htable *htable = pde->data;
4183 + unsigned int *bucket = (unsigned int *)v;
4187 + UNLOCK_BH(&htable->lock);
4190 +static inline int dl_seq_real_show(struct dsthash_ent *ent, struct seq_file *s)
4192 + /* recalculate to show accurate numbers */
4193 + rateinfo_recalc(ent, jiffies);
4195 + return seq_printf(s, "%ld %u.%u.%u.%u->%u.%u.%u.%u:%u %u %u %u\n",
4196 + (ent->expires - jiffies)/HZ,
4197 + NIPQUAD(ent->dst.src_ip),
4198 + NIPQUAD(ent->dst.dst_ip), ntohs(ent->dst.port),
4199 + ent->rateinfo.credit, ent->rateinfo.credit_cap,
4200 + ent->rateinfo.cost);
4203 +static int dl_seq_show(struct seq_file *s, void *v)
4205 + struct proc_dir_entry *pde = s->private;
4206 + struct ipt_dstlimit_htable *htable = pde->data;
4207 + unsigned int *bucket = (unsigned int *)v;
4209 + if (LIST_FIND_W(&htable->hash[*bucket], dl_seq_real_show,
4210 + struct dsthash_ent *, s)) {
4211 + /* buffer was filled and unable to print that tuple */
4217 +static struct seq_operations dl_seq_ops = {
4218 + .start = dl_seq_start,
4219 + .next = dl_seq_next,
4220 + .stop = dl_seq_stop,
4221 + .show = dl_seq_show
4224 +static int dl_proc_open(struct inode *inode, struct file *file)
4226 + int ret = seq_open(file, &dl_seq_ops);
4229 + struct seq_file *sf = file->private_data;
4230 + sf->private = PDE(inode);
4235 +static struct file_operations dl_file_ops = {
4236 + .owner = THIS_MODULE,
4237 + .open = dl_proc_open,
4239 + .llseek = seq_lseek,
4240 + .release = seq_release
4243 +static int init_or_fini(int fini)
4250 + if (ipt_register_match(&ipt_dstlimit)) {
4252 + goto cleanup_nothing;
4255 + /* FIXME: do we really want HWCACHE_ALIGN since our objects are
4256 + * quite small ? */
4257 + dstlimit_cachep = kmem_cache_create("ipt_dstlimit",
4258 + sizeof(struct dsthash_ent), 0,
4259 + SLAB_HWCACHE_ALIGN, NULL, NULL);
4260 + if (!dstlimit_cachep) {
4261 + printk(KERN_ERR "Unable to create ipt_dstlimit slab cache\n");
4263 + goto cleanup_unreg_match;
4266 + dstlimit_procdir = proc_mkdir("ipt_dstlimit", proc_net);
4267 + if (!dstlimit_procdir) {
4268 + printk(KERN_ERR "Unable to create proc dir entry\n");
4270 + goto cleanup_free_slab;
4276 + remove_proc_entry("ipt_dstlimit", proc_net);
4278 + kmem_cache_destroy(dstlimit_cachep);
4279 +cleanup_unreg_match:
4280 + ipt_unregister_match(&ipt_dstlimit);
4286 +static int __init init(void)
4288 + return init_or_fini(0);
4291 +static void __exit fini(void)
4298 diff -Nur linux-2.6.6-rc1.org/net/ipv4/netfilter/ipt_fuzzy.c linux-2.6.6-rc1/net/ipv4/netfilter/ipt_fuzzy.c
4299 --- linux-2.6.6-rc1.org/net/ipv4/netfilter/ipt_fuzzy.c 1970-01-01 01:00:00.000000000 +0100
4300 +++ linux-2.6.6-rc1/net/ipv4/netfilter/ipt_fuzzy.c 2004-04-19 10:08:31.000000000 +0200
4303 + * This module implements a simple TSK FLC
4304 + * (Takagi-Sugeno-Kang Fuzzy Logic Controller) that aims
4305 + * to limit , in an adaptive and flexible way , the packet rate crossing
4306 + * a given stream . It serves as an initial and very simple (but effective)
4307 + * example of how Fuzzy Logic techniques can be applied to defeat DoS attacks.
4308 + * As a matter of fact , Fuzzy Logic can help us to insert any "behavior"
4309 + * into our code in a precise , adaptive and efficient manner.
4310 + * The goal is very similar to that of "limit" match , but using techniques of
4311 + * Fuzzy Control , that allow us to shape the transfer functions precisely ,
4312 + * avoiding over and undershoots - and stuff like that .
4315 + * 2002-08-10 Hime Aguiar e Oliveira Jr. <hime@engineer.com> : Initial version.
4316 + * 2002-08-17 : Changed to eliminate floating point operations .
4317 + * 2002-08-23 : Coding style changes .
4320 +#include <linux/module.h>
4321 +#include <linux/skbuff.h>
4322 +#include <linux/ip.h>
4323 +#include <linux/random.h>
4324 +#include <net/tcp.h>
4325 +#include <linux/spinlock.h>
4326 +#include <linux/netfilter_ipv4/ip_tables.h>
4327 +#include <linux/netfilter_ipv4/ipt_fuzzy.h>
4330 + Packet Acceptance Rate - LOW and Packet Acceptance Rate - HIGH
4331 + Expressed in percentage
4334 +#define PAR_LOW 1/100
4337 +static spinlock_t fuzzy_lock = SPIN_LOCK_UNLOCKED ;
4339 +MODULE_AUTHOR("Hime Aguiar e Oliveira Junior <hime@engineer.com>");
4340 +MODULE_DESCRIPTION("IP tables Fuzzy Logic Controller match module");
4341 +MODULE_LICENSE("GPL");
4343 +static u_int8_t mf_high(u_int32_t tx,u_int32_t mini,u_int32_t maxi)
4351 + return ( (100*(tx-mini)) / (maxi-mini) );
4354 +static u_int8_t mf_low(u_int32_t tx,u_int32_t mini,u_int32_t maxi)
4362 + return ( (100*( maxi - tx )) / ( maxi - mini ) );
4366 +ipt_fuzzy_match(const struct sk_buff *pskb,
4367 + const struct net_device *in,
4368 + const struct net_device *out,
4369 + const void *matchinfo,
4373 + /* From userspace */
4375 + struct ipt_fuzzy_info *info = (struct ipt_fuzzy_info *) matchinfo;
4377 + u_int8_t random_number;
4378 + unsigned long amount;
4379 + u_int8_t howhigh, howlow;
4382 + spin_lock_bh(&fuzzy_lock); /* Rise the lock */
4384 + info->bytes_total += pskb->len;
4385 + info->packets_total++;
4387 + info->present_time = jiffies;
4389 + if (info->present_time >= info->previous_time)
4390 + amount = info->present_time - info->previous_time;
4392 + /* There was a transition : I choose to re-sample
4393 + and keep the old acceptance rate...
4397 + info->previous_time = info->present_time;
4398 + info->bytes_total = info->packets_total = 0;
4401 + if (amount > HZ/10) /* More than 100 ms elapsed ... */
4404 + info->mean_rate = (u_int32_t) ((HZ*info->packets_total) \
4407 + info->previous_time = info->present_time;
4408 + info->bytes_total = info->packets_total = 0;
4410 + howhigh = mf_high(info->mean_rate,info->minimum_rate,info->maximum_rate);
4411 + howlow = mf_low(info->mean_rate,info->minimum_rate,info->maximum_rate);
4413 + info->acceptance_rate = (u_int8_t) \
4414 + (howhigh*PAR_LOW + PAR_HIGH*howlow);
4416 + /* In fact , the above defuzzification would require a denominator
4417 + proportional to (howhigh+howlow) but , in this particular case ,
4418 + that expression is constant .
4419 + An imediate consequence is that it isn't necessary to call
4420 + both mf_high and mf_low - but to keep things understandable ,
4425 + spin_unlock_bh(&fuzzy_lock); /* Release the lock */
4428 + if ( info->acceptance_rate < 100 )
4430 + get_random_bytes((void *)(&random_number), 1);
4432 + /* If within the acceptance , it can pass => don't match */
4433 + if (random_number <= (255 * info->acceptance_rate) / 100)
4436 + return 1; /* It can't pass ( It matches ) */
4439 + return 0; /* acceptance_rate == 100 % => Everything passes ... */
4444 +ipt_fuzzy_checkentry(const char *tablename,
4445 + const struct ipt_ip *e,
4447 + unsigned int matchsize,
4448 + unsigned int hook_mask)
4451 + const struct ipt_fuzzy_info *info = matchinfo;
4453 + if (matchsize != IPT_ALIGN(sizeof(struct ipt_fuzzy_info))) {
4454 + printk("ipt_fuzzy: matchsize %u != %u\n", matchsize,
4455 + IPT_ALIGN(sizeof(struct ipt_fuzzy_info)));
4459 + if ((info->minimum_rate < MINFUZZYRATE ) || (info->maximum_rate > MAXFUZZYRATE)
4460 + || (info->minimum_rate >= info->maximum_rate )) {
4461 + printk("ipt_fuzzy: BAD limits , please verify !!!\n");
4468 +static struct ipt_match ipt_fuzzy_reg = {
4470 + .match = ipt_fuzzy_match,
4471 + .checkentry = ipt_fuzzy_checkentry,
4475 +static int __init init(void)
4477 + return ipt_register_match(&ipt_fuzzy_reg);
4480 +static void __exit fini(void)
4482 + ipt_unregister_match(&ipt_fuzzy_reg);
4487 diff -Nur linux-2.6.6-rc1.org/net/ipv4/netfilter/ipt_helper.c linux-2.6.6-rc1/net/ipv4/netfilter/ipt_helper.c
4488 --- linux-2.6.6-rc1.org/net/ipv4/netfilter/ipt_helper.c 2004-04-15 03:35:20.000000000 +0200
4489 +++ linux-2.6.6-rc1/net/ipv4/netfilter/ipt_helper.c 2004-04-19 10:08:23.000000000 +0200
4491 struct ip_conntrack_expect *exp;
4492 struct ip_conntrack *ct;
4493 enum ip_conntrack_info ctinfo;
4495 + int ret = info->invert;
4497 ct = ip_conntrack_get((struct sk_buff *)skb, &ctinfo);
4499 DEBUGP("ipt_helper: Eek! invalid conntrack?\n");
4505 DEBUGP("ipt_helper: conntrack %p has no master\n", ct);
4512 DEBUGP("master's name = %s , info->name = %s\n",
4513 exp->expectant->helper->name, info->name);
4515 - ret = !strncmp(exp->expectant->helper->name, info->name,
4516 - strlen(exp->expectant->helper->name)) ^ info->invert;
4517 + ret ^= !strncmp(exp->expectant->helper->name, info->name,
4518 + strlen(exp->expectant->helper->name));
4520 READ_UNLOCK(&ip_conntrack_lock);
4524 static int __init init(void)
4526 - need_ip_conntrack();
4527 return ipt_register_match(&helper_match);
4530 diff -Nur linux-2.6.6-rc1.org/net/ipv4/netfilter/ipt_ipv4options.c linux-2.6.6-rc1/net/ipv4/netfilter/ipt_ipv4options.c
4531 --- linux-2.6.6-rc1.org/net/ipv4/netfilter/ipt_ipv4options.c 1970-01-01 01:00:00.000000000 +0100
4532 +++ linux-2.6.6-rc1/net/ipv4/netfilter/ipt_ipv4options.c 2004-04-19 10:08:32.000000000 +0200
4535 + This is a module which is used to match ipv4 options.
4536 + This file is distributed under the terms of the GNU General Public
4537 + License (GPL). Copies of the GPL can be obtained from:
4538 + ftp://prep.ai.mit.edu/pub/gnu/GPL
4540 + 11-mars-2001 Fabrice MARIE <fabrice@netfilter.org> : initial development.
4541 + 12-july-2001 Fabrice MARIE <fabrice@netfilter.org> : added router-alert otions matching. Fixed a bug with no-srr
4542 + 12-august-2001 Imran Patel <ipatel@crosswinds.net> : optimization of the match.
4543 + 18-november-2001 Fabrice MARIE <fabrice@netfilter.org> : added [!] 'any' option match.
4544 + 19-february-2004 Harald Welte <laforge@netfilter.org> : merge with 2.6.x
4547 +#include <linux/module.h>
4548 +#include <linux/skbuff.h>
4549 +#include <net/ip.h>
4551 +#include <linux/netfilter_ipv4/ip_tables.h>
4552 +#include <linux/netfilter_ipv4/ipt_ipv4options.h>
4554 +MODULE_LICENSE("GPL");
4555 +MODULE_AUTHOR("Fabrice Marie <fabrice@netfilter.org>");
4558 +match(const struct sk_buff *skb,
4559 + const struct net_device *in,
4560 + const struct net_device *out,
4561 + const void *matchinfo,
4565 + const struct ipt_ipv4options_info *info = matchinfo; /* match info for rule */
4566 + const struct iphdr *iph = skb->nh.iph;
4567 + const struct ip_options *opt;
4569 + if (iph->ihl * 4 == sizeof(struct iphdr)) {
4570 + /* No options, so we match only the "DONTs" and the "IGNOREs" */
4572 + if (((info->options & IPT_IPV4OPTION_MATCH_ANY_OPT) == IPT_IPV4OPTION_MATCH_ANY_OPT) ||
4573 + ((info->options & IPT_IPV4OPTION_MATCH_SSRR) == IPT_IPV4OPTION_MATCH_SSRR) ||
4574 + ((info->options & IPT_IPV4OPTION_MATCH_LSRR) == IPT_IPV4OPTION_MATCH_LSRR) ||
4575 + ((info->options & IPT_IPV4OPTION_MATCH_RR) == IPT_IPV4OPTION_MATCH_RR) ||
4576 + ((info->options & IPT_IPV4OPTION_MATCH_TIMESTAMP) == IPT_IPV4OPTION_MATCH_TIMESTAMP) ||
4577 + ((info->options & IPT_IPV4OPTION_MATCH_ROUTER_ALERT) == IPT_IPV4OPTION_MATCH_ROUTER_ALERT))
4582 + if ((info->options & IPT_IPV4OPTION_MATCH_ANY_OPT) == IPT_IPV4OPTION_MATCH_ANY_OPT)
4583 + /* there are options, and we don't need to care which one */
4586 + if ((info->options & IPT_IPV4OPTION_DONT_MATCH_ANY_OPT) == IPT_IPV4OPTION_DONT_MATCH_ANY_OPT)
4587 + /* there are options but we don't want any ! */
4592 + opt = &(IPCB(skb)->opt);
4594 + /* source routing */
4595 + if ((info->options & IPT_IPV4OPTION_MATCH_SSRR) == IPT_IPV4OPTION_MATCH_SSRR) {
4596 + if (!((opt->srr) & (opt->is_strictroute)))
4599 + else if ((info->options & IPT_IPV4OPTION_MATCH_LSRR) == IPT_IPV4OPTION_MATCH_LSRR) {
4600 + if (!((opt->srr) & (!opt->is_strictroute)))
4603 + else if ((info->options & IPT_IPV4OPTION_DONT_MATCH_SRR) == IPT_IPV4OPTION_DONT_MATCH_SRR) {
4607 + /* record route */
4608 + if ((info->options & IPT_IPV4OPTION_MATCH_RR) == IPT_IPV4OPTION_MATCH_RR) {
4612 + else if ((info->options & IPT_IPV4OPTION_DONT_MATCH_RR) == IPT_IPV4OPTION_DONT_MATCH_RR) {
4617 + if ((info->options & IPT_IPV4OPTION_MATCH_TIMESTAMP) == IPT_IPV4OPTION_MATCH_TIMESTAMP) {
4621 + else if ((info->options & IPT_IPV4OPTION_DONT_MATCH_TIMESTAMP) == IPT_IPV4OPTION_DONT_MATCH_TIMESTAMP) {
4625 + /* router-alert option */
4626 + if ((info->options & IPT_IPV4OPTION_MATCH_ROUTER_ALERT) == IPT_IPV4OPTION_MATCH_ROUTER_ALERT) {
4627 + if (!opt->router_alert)
4630 + else if ((info->options & IPT_IPV4OPTION_DONT_MATCH_ROUTER_ALERT) == IPT_IPV4OPTION_DONT_MATCH_ROUTER_ALERT) {
4631 + if (opt->router_alert)
4640 +checkentry(const char *tablename,
4641 + const struct ipt_ip *ip,
4643 + unsigned int matchsize,
4644 + unsigned int hook_mask)
4646 + const struct ipt_ipv4options_info *info = matchinfo; /* match info for rule */
4647 + /* Check the size */
4648 + if (matchsize != IPT_ALIGN(sizeof(struct ipt_ipv4options_info)))
4650 + /* Now check the coherence of the data ... */
4651 + if (((info->options & IPT_IPV4OPTION_MATCH_ANY_OPT) == IPT_IPV4OPTION_MATCH_ANY_OPT) &&
4652 + (((info->options & IPT_IPV4OPTION_DONT_MATCH_SRR) == IPT_IPV4OPTION_DONT_MATCH_SRR) ||
4653 + ((info->options & IPT_IPV4OPTION_DONT_MATCH_RR) == IPT_IPV4OPTION_DONT_MATCH_RR) ||
4654 + ((info->options & IPT_IPV4OPTION_DONT_MATCH_TIMESTAMP) == IPT_IPV4OPTION_DONT_MATCH_TIMESTAMP) ||
4655 + ((info->options & IPT_IPV4OPTION_DONT_MATCH_ROUTER_ALERT) == IPT_IPV4OPTION_DONT_MATCH_ROUTER_ALERT) ||
4656 + ((info->options & IPT_IPV4OPTION_DONT_MATCH_ANY_OPT) == IPT_IPV4OPTION_DONT_MATCH_ANY_OPT)))
4657 + return 0; /* opposites */
4658 + if (((info->options & IPT_IPV4OPTION_DONT_MATCH_ANY_OPT) == IPT_IPV4OPTION_DONT_MATCH_ANY_OPT) &&
4659 + (((info->options & IPT_IPV4OPTION_MATCH_LSRR) == IPT_IPV4OPTION_MATCH_LSRR) ||
4660 + ((info->options & IPT_IPV4OPTION_MATCH_SSRR) == IPT_IPV4OPTION_MATCH_SSRR) ||
4661 + ((info->options & IPT_IPV4OPTION_MATCH_RR) == IPT_IPV4OPTION_MATCH_RR) ||
4662 + ((info->options & IPT_IPV4OPTION_MATCH_TIMESTAMP) == IPT_IPV4OPTION_MATCH_TIMESTAMP) ||
4663 + ((info->options & IPT_IPV4OPTION_MATCH_ROUTER_ALERT) == IPT_IPV4OPTION_MATCH_ROUTER_ALERT) ||
4664 + ((info->options & IPT_IPV4OPTION_MATCH_ANY_OPT) == IPT_IPV4OPTION_MATCH_ANY_OPT)))
4665 + return 0; /* opposites */
4666 + if (((info->options & IPT_IPV4OPTION_MATCH_SSRR) == IPT_IPV4OPTION_MATCH_SSRR) &&
4667 + ((info->options & IPT_IPV4OPTION_MATCH_LSRR) == IPT_IPV4OPTION_MATCH_LSRR))
4668 + return 0; /* cannot match in the same time loose and strict source routing */
4669 + if ((((info->options & IPT_IPV4OPTION_MATCH_SSRR) == IPT_IPV4OPTION_MATCH_SSRR) ||
4670 + ((info->options & IPT_IPV4OPTION_MATCH_LSRR) == IPT_IPV4OPTION_MATCH_LSRR)) &&
4671 + ((info->options & IPT_IPV4OPTION_DONT_MATCH_SRR) == IPT_IPV4OPTION_DONT_MATCH_SRR))
4672 + return 0; /* opposites */
4673 + if (((info->options & IPT_IPV4OPTION_MATCH_RR) == IPT_IPV4OPTION_MATCH_RR) &&
4674 + ((info->options & IPT_IPV4OPTION_DONT_MATCH_RR) == IPT_IPV4OPTION_DONT_MATCH_RR))
4675 + return 0; /* opposites */
4676 + if (((info->options & IPT_IPV4OPTION_MATCH_TIMESTAMP) == IPT_IPV4OPTION_MATCH_TIMESTAMP) &&
4677 + ((info->options & IPT_IPV4OPTION_DONT_MATCH_TIMESTAMP) == IPT_IPV4OPTION_DONT_MATCH_TIMESTAMP))
4678 + return 0; /* opposites */
4679 + if (((info->options & IPT_IPV4OPTION_MATCH_ROUTER_ALERT) == IPT_IPV4OPTION_MATCH_ROUTER_ALERT) &&
4680 + ((info->options & IPT_IPV4OPTION_DONT_MATCH_ROUTER_ALERT) == IPT_IPV4OPTION_DONT_MATCH_ROUTER_ALERT))
4681 + return 0; /* opposites */
4683 + /* everything looks ok. */
4687 +static struct ipt_match ipv4options_match = {
4688 + .name = "ipv4options",
4690 + .checkentry = checkentry,
4694 +static int __init init(void)
4696 + return ipt_register_match(&ipv4options_match);
4699 +static void __exit fini(void)
4701 + ipt_unregister_match(&ipv4options_match);
4706 diff -Nur linux-2.6.6-rc1.org/net/ipv4/netfilter/ipt_mport.c linux-2.6.6-rc1/net/ipv4/netfilter/ipt_mport.c
4707 --- linux-2.6.6-rc1.org/net/ipv4/netfilter/ipt_mport.c 1970-01-01 01:00:00.000000000 +0100
4708 +++ linux-2.6.6-rc1/net/ipv4/netfilter/ipt_mport.c 2004-04-19 10:08:33.000000000 +0200
4710 +/* Kernel module to match one of a list of TCP/UDP ports: ports are in
4711 + the same place so we can treat them as equal. */
4712 +#include <linux/module.h>
4713 +#include <linux/types.h>
4714 +#include <linux/udp.h>
4715 +#include <linux/skbuff.h>
4717 +#include <linux/netfilter_ipv4/ipt_mport.h>
4718 +#include <linux/netfilter_ipv4/ip_tables.h>
4720 +MODULE_LICENSE("GPL");
4723 +#define duprintf(format, args...) printk(format , ## args)
4725 +#define duprintf(format, args...)
4728 +/* Returns 1 if the port is matched by the test, 0 otherwise. */
4730 +ports_match(const struct ipt_mport *minfo, u_int16_t src, u_int16_t dst)
4734 + u_int16_t pflags = minfo->pflags;
4735 + for (i=0, m=1; i<IPT_MULTI_PORTS; i++, m<<=1) {
4739 + && minfo->ports[i] == 65535)
4742 + s = minfo->ports[i];
4745 + e = minfo->ports[++i];
4750 + if (minfo->flags & IPT_MPORT_SOURCE
4751 + && src >= s && src <= e)
4754 + if (minfo->flags & IPT_MPORT_DESTINATION
4755 + && dst >= s && dst <= e)
4763 +match(const struct sk_buff *skb,
4764 + const struct net_device *in,
4765 + const struct net_device *out,
4766 + const void *matchinfo,
4771 + const struct ipt_mport *minfo = matchinfo;
4776 + /* Must be big enough to read ports (both UDP and TCP have
4777 + them at the start). */
4778 + if (skb_copy_bits(skb, skb->nh.iph->ihl*4, ports, sizeof(ports)) < 0) {
4779 + /* We've been asked to examine this packet, and we
4780 + can't. Hence, no choice but to drop. */
4781 + duprintf("ipt_multiport:"
4782 + " Dropping evil offset=0 tinygram.\n");
4787 + return ports_match(minfo, ntohs(ports[0]), ntohs(ports[1]));
4790 +/* Called when user tries to insert an entry of this type. */
4792 +checkentry(const char *tablename,
4793 + const struct ipt_ip *ip,
4795 + unsigned int matchsize,
4796 + unsigned int hook_mask)
4798 + if (matchsize != IPT_ALIGN(sizeof(struct ipt_mport)))
4801 + /* Must specify proto == TCP/UDP, no unknown flags or bad count */
4802 + return (ip->proto == IPPROTO_TCP || ip->proto == IPPROTO_UDP)
4803 + && !(ip->invflags & IPT_INV_PROTO)
4804 + && matchsize == IPT_ALIGN(sizeof(struct ipt_mport));
4807 +static struct ipt_match mport_match = {
4810 + .checkentry = &checkentry,
4814 +static int __init init(void)
4816 + return ipt_register_match(&mport_match);
4819 +static void __exit fini(void)
4821 + ipt_unregister_match(&mport_match);
4826 diff -Nur linux-2.6.6-rc1.org/net/ipv4/netfilter/ipt_nth.c linux-2.6.6-rc1/net/ipv4/netfilter/ipt_nth.c
4827 --- linux-2.6.6-rc1.org/net/ipv4/netfilter/ipt_nth.c 1970-01-01 01:00:00.000000000 +0100
4828 +++ linux-2.6.6-rc1/net/ipv4/netfilter/ipt_nth.c 2004-04-19 10:08:34.000000000 +0200
4831 + This is a module which is used for match support for every Nth packet
4832 + This file is distributed under the terms of the GNU General Public
4833 + License (GPL). Copies of the GPL can be obtained from:
4834 + ftp://prep.ai.mit.edu/pub/gnu/GPL
4836 + 2001-07-18 Fabrice MARIE <fabrice@netfilter.org> : initial implementation.
4837 + 2001-09-20 Richard Wagner (rwagner@cloudnet.com)
4838 + * added support for multiple counters
4839 + * added support for matching on individual packets
4840 + in the counter cycle
4841 + 2004-02-19 Harald Welte <laforge@netfilter.org>
4846 +#include <linux/module.h>
4847 +#include <linux/skbuff.h>
4848 +#include <linux/ip.h>
4849 +#include <net/tcp.h>
4850 +#include <linux/spinlock.h>
4851 +#include <linux/netfilter_ipv4/ip_tables.h>
4852 +#include <linux/netfilter_ipv4/ipt_nth.h>
4854 +MODULE_LICENSE("GPL");
4855 +MODULE_AUTHOR("Fabrice Marie <fabrice@netfilter.org>");
4858 + * State information.
4865 +static struct state states[IPT_NTH_NUM_COUNTERS];
4868 +ipt_nth_match(const struct sk_buff *pskb,
4869 + const struct net_device *in,
4870 + const struct net_device *out,
4871 + const void *matchinfo,
4875 + /* Parameters from userspace */
4876 + const struct ipt_nth_info *info = matchinfo;
4877 + unsigned counter = info->counter;
4878 + if((counter < 0) || (counter >= IPT_NTH_NUM_COUNTERS))
4880 + printk(KERN_WARNING "nth: invalid counter %u. counter between 0 and %u\n", counter, IPT_NTH_NUM_COUNTERS-1);
4884 + spin_lock(&states[counter].lock);
4886 + /* Are we matching every nth packet?*/
4887 + if (info->packet == 0xFF)
4889 + /* We're matching every nth packet and only every nth packet*/
4890 + /* Do we match or invert match? */
4891 + if (info->not == 0)
4893 + if (states[counter].number == 0)
4895 + ++states[counter].number;
4898 + if (states[counter].number >= info->every)
4899 + states[counter].number = 0; /* reset the counter */
4901 + ++states[counter].number;
4906 + if (states[counter].number == 0)
4908 + ++states[counter].number;
4911 + if (states[counter].number >= info->every)
4912 + states[counter].number = 0;
4914 + ++states[counter].number;
4920 + /* We're using the --packet, so there must be a rule for every value */
4921 + if (states[counter].number == info->packet)
4923 + /* only increment the counter when a match happens */
4924 + if (states[counter].number >= info->every)
4925 + states[counter].number = 0; /* reset the counter */
4927 + ++states[counter].number;
4936 + spin_unlock(&states[counter].lock);
4940 + spin_unlock(&states[counter].lock);
4945 +ipt_nth_checkentry(const char *tablename,
4946 + const struct ipt_ip *e,
4948 + unsigned int matchsize,
4949 + unsigned int hook_mask)
4951 + /* Parameters from userspace */
4952 + const struct ipt_nth_info *info = matchinfo;
4953 + unsigned counter = info->counter;
4954 + if((counter < 0) || (counter >= IPT_NTH_NUM_COUNTERS))
4956 + printk(KERN_WARNING "nth: invalid counter %u. counter between 0 and %u\n", counter, IPT_NTH_NUM_COUNTERS-1);
4960 + if (matchsize != IPT_ALIGN(sizeof(struct ipt_nth_info))) {
4961 + printk("nth: matchsize %u != %u\n", matchsize,
4962 + IPT_ALIGN(sizeof(struct ipt_nth_info)));
4966 + states[counter].number = info->startat;
4971 +static struct ipt_match ipt_nth_reg = {
4973 + .match = ipt_nth_match,
4974 + .checkentry = ipt_nth_checkentry,
4978 +static int __init init(void)
4982 + memset(&states, 0, sizeof(states));
4983 + for (counter = 0; counter < IPT_NTH_NUM_COUNTERS; counter++)
4984 + spin_lock_init(&(states[counter].lock));
4986 + return ipt_register_match(&ipt_nth_reg);
4989 +static void __exit fini(void)
4991 + ipt_unregister_match(&ipt_nth_reg);
4996 diff -Nur linux-2.6.6-rc1.org/net/ipv4/netfilter/ipt_osf.c linux-2.6.6-rc1/net/ipv4/netfilter/ipt_osf.c
4997 --- linux-2.6.6-rc1.org/net/ipv4/netfilter/ipt_osf.c 1970-01-01 01:00:00.000000000 +0100
4998 +++ linux-2.6.6-rc1/net/ipv4/netfilter/ipt_osf.c 2004-04-19 10:08:35.000000000 +0200
5003 + * Copyright (c) 2003 Evgeniy Polyakov <johnpol@2ka.mipt.ru>
5006 + * This program is free software; you can redistribute it and/or modify
5007 + * it under the terms of the GNU General Public License as published by
5008 + * the Free Software Foundation; either version 2 of the License, or
5009 + * (at your option) any later version.
5011 + * This program is distributed in the hope that it will be useful,
5012 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
5013 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
5014 + * GNU General Public License for more details.
5016 + * You should have received a copy of the GNU General Public License
5017 + * along with this program; if not, write to the Free Software
5018 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
5022 + * OS fingerprint matching module.
5023 + * It simply compares various parameters from SYN packet with
5024 + * some hardcoded ones.
5026 + * Original table was created by Michal Zalewski <lcamtuf@coredump.cx>
5030 +#include <linux/config.h>
5031 +#include <linux/kernel.h>
5032 +#include <linux/types.h>
5033 +#include <linux/string.h>
5034 +#include <linux/smp.h>
5035 +#include <linux/module.h>
5036 +#include <linux/skbuff.h>
5037 +#include <linux/file.h>
5038 +#include <linux/ip.h>
5039 +#include <linux/proc_fs.h>
5040 +#include <linux/fs.h>
5041 +#include <linux/slab.h>
5042 +#include <linux/spinlock.h>
5043 +#include <linux/ctype.h>
5044 +#include <linux/list.h>
5045 +#include <linux/if.h>
5046 +#include <linux/tcp.h>
5048 +#include <net/sock.h>
5049 +#include <net/ip.h>
5051 +#include <linux/netfilter_ipv4/ip_tables.h>
5053 +#include <linux/netfilter_ipv4/ipt_osf.h>
5058 +#define log(x...) printk(KERN_INFO "ipt_osf: " x)
5059 +#define loga(x...) printk(x)
5061 +#define log(x...) do {} while(0)
5062 +#define loga(x...) do {} while(0)
5065 +#define FMATCH_WRONG 0
5066 +#define FMATCH_OK 1
5067 +#define FMATCH_OPT_WRONG 2
5070 +#define OSFPDEL ':'
5071 +#define MAXOPTSTRLEN 128
5072 +#define OSFFLUSH "FLUSH"
5074 +static rwlock_t osf_lock = RW_LOCK_UNLOCKED;
5075 +static spinlock_t ipt_osf_netlink_lock = SPIN_LOCK_UNLOCKED;
5076 +static struct list_head finger_list;
5077 +static int match(const struct sk_buff *, const struct net_device *, const struct net_device *,
5078 + const void *, int,
5079 + const void *, u_int16_t,
5081 +static int checkentry(const char *, const struct ipt_ip *, void *,
5082 + unsigned int, unsigned int);
5084 +static unsigned long seq, ipt_osf_groups = 1;
5085 +static struct sock *nts;
5087 +static struct ipt_match osf_match =
5097 +static void ipt_osf_nlsend(struct osf_finger *f, const struct sk_buff *sk)
5099 + unsigned int size;
5100 + struct sk_buff *skb;
5101 + struct ipt_osf_nlmsg *data;
5102 + struct nlmsghdr *nlh;
5104 + size = NLMSG_SPACE(sizeof(struct ipt_osf_nlmsg));
5106 + skb = alloc_skb(size, GFP_ATOMIC);
5109 + log("skb_alloc() failed.\n");
5113 + nlh = NLMSG_PUT(skb, 0, seq++, NLMSG_DONE, size - sizeof(*nlh));
5115 + data = (struct ipt_osf_nlmsg *)NLMSG_DATA(nlh);
5117 + memcpy(&data->f, f, sizeof(struct osf_finger));
5118 + memcpy(&data->ip, sk->nh.iph, sizeof(struct iphdr));
5119 + memcpy(&data->tcp, (struct tcphdr *)((u_int32_t *)sk->nh.iph + sk->nh.iph->ihl), sizeof(struct tcphdr));
5121 + NETLINK_CB(skb).dst_groups = ipt_osf_groups;
5122 + netlink_broadcast(nts, skb, 0, ipt_osf_groups, GFP_ATOMIC);
5128 +static inline int smart_dec(const struct sk_buff *skb, unsigned long flags, unsigned char f_ttl)
5130 + struct iphdr *ip = skb->nh.iph;
5132 + if (flags & IPT_OSF_SMART)
5134 + struct in_device *in_dev = in_dev_get(skb->dev);
5138 + if (inet_ifa_match(ip->saddr, ifa))
5140 + in_dev_put(in_dev);
5141 + return (ip->ttl == f_ttl);
5144 + endfor_ifa(in_dev);
5146 + in_dev_put(in_dev);
5147 + return (ip->ttl <= f_ttl);
5150 + return (ip->ttl == f_ttl);
5154 +match(const struct sk_buff *skb, const struct net_device *in, const struct net_device *out,
5155 + const void *matchinfo, int offset,
5156 + const void *hdr, u_int16_t datalen,
5159 + struct ipt_osf_info *info = (struct ipt_osf_info *)matchinfo;
5160 + struct iphdr *ip = skb->nh.iph;
5161 + struct tcphdr *tcp;
5162 + int fmatch = FMATCH_WRONG, fcount = 0;
5163 + unsigned long totlen, optsize = 0, window;
5164 + unsigned char df, *optp = NULL, *_optp = NULL;
5165 + char check_WSS = 0;
5166 + struct list_head *ent;
5167 + struct osf_finger *f;
5172 + tcp = (struct tcphdr *)((u_int32_t *)ip + ip->ihl);
5177 + totlen = ntohs(ip->tot_len);
5178 + df = ((ntohs(ip->frag_off) & IP_DF)?1:0);
5179 + window = ntohs(tcp->window);
5181 + if (tcp->doff*4 > sizeof(struct tcphdr))
5183 + _optp = optp = (char *)(tcp+1);
5184 + optsize = tcp->doff*4 - sizeof(struct tcphdr);
5188 + /* Actually we can create hash/table of all genres and search
5189 + * only in appropriate part, but here is initial variant,
5190 + * so will use slow path.
5192 + read_lock(&osf_lock);
5193 + list_for_each(ent, &finger_list)
5195 + f = list_entry(ent, struct osf_finger, flist);
5197 + if (!(info->flags & IPT_OSF_LOG) && strcmp(info->genre, f->genre))
5201 + fmatch = FMATCH_WRONG;
5203 + if (totlen == f->ss && df == f->df &&
5204 + smart_dec(skb, info->flags, f->ttl))
5206 + unsigned long foptsize;
5208 + unsigned short mss = 0;
5212 + switch (f->wss.wc)
5214 + case 0: check_WSS = 0; break;
5215 + case 'S': check_WSS = 1; break;
5216 + case 'T': check_WSS = 2; break;
5217 + case '%': check_WSS = 3; break;
5218 + default: log("Wrong fingerprint wss.wc=%d, %s - %s\n",
5219 + f->wss.wc, f->genre, f->details);
5223 + if (check_WSS == 4)
5226 + /* Check options */
5229 + for (optnum=0; optnum<f->opt_num; ++optnum)
5230 + foptsize += f->opt[optnum].length;
5233 + if (foptsize > MAX_IPOPTLEN || optsize > MAX_IPOPTLEN || optsize != foptsize)
5238 + fmatch = FMATCH_OK;
5239 + loga("\tYEP : matching without options.\n");
5240 + if ((info->flags & IPT_OSF_LOG) &&
5241 + info->loglevel == IPT_OSF_LOGLEVEL_FIRST)
5248 + for (optnum=0; optnum<f->opt_num; ++optnum)
5250 + if (f->opt[optnum].kind == (*optp))
5252 + unsigned char len = f->opt[optnum].length;
5253 + unsigned char *optend = optp + len;
5254 + int loop_cont = 0;
5256 + fmatch = FMATCH_OK;
5262 + mss = ntohs(*(unsigned short *)(optp+2));
5277 + /* Skip kind and length fields*/
5280 + if (f->opt[optnum].wc.val != 0)
5282 + unsigned long tmp = 0;
5284 + /* Hmmm... It looks a bit ugly. :) */
5285 + memcpy(&tmp, optp,
5286 + (len > sizeof(unsigned long)?
5287 + sizeof(unsigned long):len));
5288 + /* 2 + 2: optlen(2 bytes) +
5289 + * kind(1 byte) + length(1 byte) */
5295 + if (f->opt[optnum].wc.wc == '%')
5297 + if ((tmp % f->opt[optnum].wc.val) != 0)
5298 + fmatch = FMATCH_OPT_WRONG;
5300 + else if (tmp != f->opt[optnum].wc.val)
5301 + fmatch = FMATCH_OPT_WRONG;
5308 + fmatch = FMATCH_OPT_WRONG;
5310 + if (fmatch != FMATCH_OK)
5314 + if (fmatch != FMATCH_OPT_WRONG)
5316 + fmatch = FMATCH_WRONG;
5318 + switch (check_WSS)
5321 + if (f->wss.val == 0 || window == f->wss.val)
5322 + fmatch = FMATCH_OK;
5325 +/* Lurked in OpenBSD */
5326 +#define SMART_MSS 1460
5327 + if (window == f->wss.val*mss ||
5328 + window == f->wss.val*SMART_MSS)
5329 + fmatch = FMATCH_OK;
5332 + if (window == f->wss.val*(mss+40) ||
5333 + window == f->wss.val*(SMART_MSS+40))
5334 + fmatch = FMATCH_OK;
5337 + if ((window % f->wss.val) == 0)
5338 + fmatch = FMATCH_OK;
5344 + if (fmatch == FMATCH_OK)
5347 + log("%s [%s:%s:%s] : %u.%u.%u.%u:%u -> %u.%u.%u.%u:%u hops=%d\n",
5348 + f->genre, f->version,
5349 + f->subtype, f->details,
5350 + NIPQUAD(ip->saddr), ntohs(tcp->source),
5351 + NIPQUAD(ip->daddr), ntohs(tcp->dest),
5352 + f->ttl - ip->ttl);
5353 + if (info->flags & IPT_OSF_NETLINK)
5355 + spin_lock_bh(&ipt_osf_netlink_lock);
5356 + ipt_osf_nlsend(f, skb);
5357 + spin_unlock_bh(&ipt_osf_netlink_lock);
5359 + if ((info->flags & IPT_OSF_LOG) &&
5360 + info->loglevel == IPT_OSF_LOGLEVEL_FIRST)
5365 + if (!fcount && (info->flags & (IPT_OSF_LOG | IPT_OSF_NETLINK)))
5367 + unsigned char opt[4 * 15 - sizeof(struct tcphdr)];
5368 + unsigned int i, optsize;
5369 + struct osf_finger fg;
5371 + memset(&fg, 0, sizeof(fg));
5373 + if ((info->flags & IPT_OSF_LOG))
5374 + log("Unknown: %lu:%d:%d:%lu:", window, ip->ttl, df, totlen);
5377 + optsize = tcp->doff * 4 - sizeof(struct tcphdr);
5378 + if (skb_copy_bits(skb, ip->ihl*4 + sizeof(struct tcphdr),
5379 + opt, optsize) < 0)
5381 + if (info->flags & IPT_OSF_LOG)
5382 + loga("TRUNCATED");
5383 + if (info->flags & IPT_OSF_NETLINK)
5384 + strcpy(fg.details, "TRUNCATED");
5388 + for (i = 0; i < optsize; i++)
5390 + if (info->flags & IPT_OSF_LOG)
5391 + loga("%02X", opt[i]);
5393 + if (info->flags & IPT_OSF_NETLINK)
5394 + memcpy(fg.details, opt, MAXDETLEN);
5397 + if ((info->flags & IPT_OSF_LOG))
5398 + loga(" %u.%u.%u.%u:%u -> %u.%u.%u.%u:%u\n",
5399 + NIPQUAD(ip->saddr), ntohs(tcp->source),
5400 + NIPQUAD(ip->daddr), ntohs(tcp->dest));
5402 + if (info->flags & IPT_OSF_NETLINK)
5404 + fg.wss.val = window;
5408 + strncpy(fg.genre, "Unknown", MAXGENRELEN);
5410 + spin_lock_bh(&ipt_osf_netlink_lock);
5411 + ipt_osf_nlsend(&fg, skb);
5412 + spin_unlock_bh(&ipt_osf_netlink_lock);
5416 + read_unlock(&osf_lock);
5418 + return (fmatch == FMATCH_OK)?1:0;
5422 +checkentry(const char *tablename,
5423 + const struct ipt_ip *ip,
5425 + unsigned int matchsize,
5426 + unsigned int hook_mask)
5428 + if (matchsize != IPT_ALIGN(sizeof(struct ipt_osf_info)))
5430 + if (ip->proto != IPPROTO_TCP)
5436 +static char * osf_strchr(char *ptr, char c)
5440 + tmp = strchr(ptr, c);
5442 + while (tmp && tmp+1 && isspace(*(tmp+1)))
5448 +static struct osf_finger * finger_alloc(void)
5450 + struct osf_finger *f;
5452 + f = kmalloc(sizeof(struct osf_finger), GFP_KERNEL);
5454 + memset(f, 0, sizeof(struct osf_finger));
5459 +static void finger_free(struct osf_finger *f)
5461 + memset(f, 0, sizeof(struct osf_finger));
5466 +static void osf_parse_opt(struct osf_opt *opt, int *optnum, char *obuf, int olen)
5470 + unsigned long val;
5474 + while (ptr != NULL && i < olen)
5483 + ptr = osf_strchr(&obuf[i], OPTDEL);
5488 + i += (int)(ptr-&obuf[i]);
5495 + op = OSFOPT_SACKP;
5496 + ptr = osf_strchr(&obuf[i], OPTDEL);
5501 + i += (int)(ptr-&obuf[i]);
5509 + ptr = osf_strchr(&obuf[i], OPTDEL);
5514 + i += (int)(ptr-&obuf[i]);
5522 + ptr = osf_strchr(&obuf[i], OPTDEL);
5525 + switch (obuf[i+1])
5527 + case '%': wc = '%'; break;
5528 + case 'S': wc = 'S'; break;
5529 + case 'T': wc = 'T'; break;
5530 + default: wc = 0; break;
5536 + val = simple_strtoul(&obuf[i+2], NULL, 10);
5538 + val = simple_strtoul(&obuf[i+1], NULL, 10);
5539 + i += (int)(ptr-&obuf[i]);
5547 + ptr = osf_strchr(&obuf[i], OPTDEL);
5550 + if (obuf[i+1] == '%')
5555 + val = simple_strtoul(&obuf[i+2], NULL, 10);
5557 + val = simple_strtoul(&obuf[i+1], NULL, 10);
5558 + i += (int)(ptr-&obuf[i]);
5566 + ptr = osf_strchr(&obuf[i], OPTDEL);
5571 + i += (int)(ptr-&obuf[i]);
5578 + ptr = osf_strchr(&obuf[i], OPTDEL);
5582 + i += (int)(ptr-&obuf[i]);
5590 + opt[*optnum].kind = IANA_opts[op].kind;
5591 + opt[*optnum].length = IANA_opts[op].length;
5592 + opt[*optnum].wc.wc = wc;
5593 + opt[*optnum].wc.val = val;
5599 +static int osf_proc_read(char *buf, char **start, off_t off, int count, int *eof, void *data)
5601 + struct list_head *ent;
5602 + struct osf_finger *f = NULL;
5608 + read_lock_bh(&osf_lock);
5609 + list_for_each(ent, &finger_list)
5611 + f = list_entry(ent, struct osf_finger, flist);
5613 + log("%s [%s]", f->genre, f->details);
5615 + count += sprintf(buf+count, "%s - %s[%s] : %s",
5616 + f->genre, f->version,
5617 + f->subtype, f->details);
5622 + //count += sprintf(buf+count, " OPT: ");
5623 + for (i=0; i<f->opt_num; ++i)
5625 + //count += sprintf(buf+count, "%d.%c%lu; ",
5626 + // f->opt[i].kind, (f->opt[i].wc.wc)?f->opt[i].wc.wc:' ', f->opt[i].wc.val);
5627 + loga("%d.%c%lu; ",
5628 + f->opt[i].kind, (f->opt[i].wc.wc)?f->opt[i].wc.wc:' ', f->opt[i].wc.val);
5632 + count += sprintf(buf+count, "\n");
5634 + read_unlock_bh(&osf_lock);
5639 +static int osf_proc_write(struct file *file, const char *buffer, unsigned long count, void *data)
5643 + char obuf[MAXOPTSTRLEN];
5644 + struct osf_finger *finger;
5645 + struct list_head *ent, *n;
5647 + char *pbeg, *pend;
5649 + if (count == strlen(OSFFLUSH) && !strncmp(buffer, OSFFLUSH, strlen(OSFFLUSH)))
5652 + write_lock_bh(&osf_lock);
5653 + list_for_each_safe(ent, n, &finger_list)
5656 + finger = list_entry(ent, struct osf_finger, flist);
5657 + list_del(&finger->flist);
5658 + finger_free(finger);
5660 + write_unlock_bh(&osf_lock);
5662 + log("Flushed %d entries.\n", i);
5669 + for (i=0; i<count && buffer[i] != '\0'; ++i)
5670 + if (buffer[i] == ':')
5673 + if (cnt != 8 || i != count)
5675 + log("Wrong input line cnt=%d[8], len=%lu[%lu]\n",
5680 + memset(obuf, 0, sizeof(obuf));
5682 + finger = finger_alloc();
5685 + log("Failed to allocate new fingerprint entry.\n");
5689 + pbeg = (char *)buffer;
5690 + pend = osf_strchr(pbeg, OSFPDEL);
5694 + if (pbeg[0] == 'S')
5696 + finger->wss.wc = 'S';
5697 + if (pbeg[1] == '%')
5698 + finger->wss.val = simple_strtoul(pbeg+2, NULL, 10);
5699 + else if (pbeg[1] == '*')
5700 + finger->wss.val = 0;
5702 + finger->wss.val = simple_strtoul(pbeg+1, NULL, 10);
5704 + else if (pbeg[0] == 'T')
5706 + finger->wss.wc = 'T';
5707 + if (pbeg[1] == '%')
5708 + finger->wss.val = simple_strtoul(pbeg+2, NULL, 10);
5709 + else if (pbeg[1] == '*')
5710 + finger->wss.val = 0;
5712 + finger->wss.val = simple_strtoul(pbeg+1, NULL, 10);
5714 + else if (pbeg[0] == '%')
5716 + finger->wss.wc = '%';
5717 + finger->wss.val = simple_strtoul(pbeg+1, NULL, 10);
5719 + else if (isdigit(pbeg[0]))
5721 + finger->wss.wc = 0;
5722 + finger->wss.val = simple_strtoul(pbeg, NULL, 10);
5727 + pend = osf_strchr(pbeg, OSFPDEL);
5731 + finger->ttl = simple_strtoul(pbeg, NULL, 10);
5734 + pend = osf_strchr(pbeg, OSFPDEL);
5738 + finger->df = simple_strtoul(pbeg, NULL, 10);
5741 + pend = osf_strchr(pbeg, OSFPDEL);
5745 + finger->ss = simple_strtoul(pbeg, NULL, 10);
5749 + pend = osf_strchr(pbeg, OSFPDEL);
5753 + cnt = snprintf(obuf, sizeof(obuf), "%s", pbeg);
5757 + pend = osf_strchr(pbeg, OSFPDEL);
5761 + if (pbeg[0] == '@' || pbeg[0] == '*')
5762 + cnt = snprintf(finger->genre, sizeof(finger->genre), "%s", pbeg+1);
5764 + cnt = snprintf(finger->genre, sizeof(finger->genre), "%s", pbeg);
5768 + pend = osf_strchr(pbeg, OSFPDEL);
5772 + cnt = snprintf(finger->version, sizeof(finger->version), "%s", pbeg);
5776 + pend = osf_strchr(pbeg, OSFPDEL);
5780 + cnt = snprintf(finger->subtype, sizeof(finger->subtype), "%s", pbeg);
5784 + cnt = snprintf(finger->details,
5785 + ((count - (pbeg - buffer)+1) > MAXDETLEN)?MAXDETLEN:(count - (pbeg - buffer)+1),
5788 + log("%s - %s[%s] : %s\n",
5789 + finger->genre, finger->version,
5790 + finger->subtype, finger->details);
5792 + osf_parse_opt(finger->opt, &finger->opt_num, obuf, sizeof(obuf));
5795 + write_lock_bh(&osf_lock);
5796 + list_add_tail(&finger->flist, &finger_list);
5797 + write_unlock_bh(&osf_lock);
5802 +static int __init osf_init(void)
5805 + struct proc_dir_entry *p;
5807 + log("Startng OS fingerprint matching module.\n");
5809 + INIT_LIST_HEAD(&finger_list);
5811 + err = ipt_register_match(&osf_match);
5814 + log("Failed to register OS fingerprint matching module.\n");
5818 + p = create_proc_entry("sys/net/ipv4/osf", S_IFREG | 0644, NULL);
5821 + ipt_unregister_match(&osf_match);
5825 + p->write_proc = osf_proc_write;
5826 + p->read_proc = osf_proc_read;
5828 + nts = netlink_kernel_create(NETLINK_NFLOG, NULL);
5831 + log("netlink_kernel_create() failed\n");
5832 + remove_proc_entry("sys/net/ipv4/osf", NULL);
5833 + ipt_unregister_match(&osf_match);
5840 +static void __exit osf_fini(void)
5842 + struct list_head *ent, *n;
5843 + struct osf_finger *f;
5845 + remove_proc_entry("sys/net/ipv4/osf", NULL);
5846 + ipt_unregister_match(&osf_match);
5847 +// if (nts && nts->socket)
5848 +// sock_release(nts->socket);
5850 + list_for_each_safe(ent, n, &finger_list)
5852 + f = list_entry(ent, struct osf_finger, flist);
5853 + list_del(&f->flist);
5857 + log("OS fingerprint matching module finished.\n");
5860 +module_init(osf_init);
5861 +module_exit(osf_fini);
5863 +MODULE_LICENSE("GPL");
5864 +MODULE_AUTHOR("Evgeniy Polyakov <johnpol@2ka.mipt.ru>");
5865 +MODULE_DESCRIPTION("Passive OS fingerprint matching.");
5866 diff -Nur linux-2.6.6-rc1.org/net/ipv4/netfilter/ipt_pool.c linux-2.6.6-rc1/net/ipv4/netfilter/ipt_pool.c
5867 --- linux-2.6.6-rc1.org/net/ipv4/netfilter/ipt_pool.c 1970-01-01 01:00:00.000000000 +0100
5868 +++ linux-2.6.6-rc1/net/ipv4/netfilter/ipt_pool.c 2004-04-19 10:08:36.000000000 +0200
5870 +/* Kernel module to match an IP address pool. */
5872 +#include <linux/module.h>
5873 +#include <linux/ip.h>
5874 +#include <linux/skbuff.h>
5876 +#include <linux/netfilter_ipv4/ip_tables.h>
5877 +#include <linux/netfilter_ipv4/ip_pool.h>
5878 +#include <linux/netfilter_ipv4/ipt_pool.h>
5880 +static inline int match_pool(
5885 + if (ip_pool_match(index, ntohl(addr)))
5891 + const struct sk_buff *skb,
5892 + const struct net_device *in,
5893 + const struct net_device *out,
5894 + const void *matchinfo,
5897 + u_int16_t datalen,
5900 + const struct ipt_pool_info *info = matchinfo;
5901 + const struct iphdr *iph = skb->nh.iph;
5903 + if (info->src != IP_POOL_NONE && !match_pool(info->src, iph->saddr,
5904 + info->flags&IPT_POOL_INV_SRC))
5907 + if (info->dst != IP_POOL_NONE && !match_pool(info->dst, iph->daddr,
5908 + info->flags&IPT_POOL_INV_DST))
5914 +static int checkentry(
5915 + const char *tablename,
5916 + const struct ipt_ip *ip,
5918 + unsigned int matchsize,
5919 + unsigned int hook_mask
5921 + if (matchsize != IPT_ALIGN(sizeof(struct ipt_pool_info)))
5926 +static struct ipt_match pool_match
5927 += { { NULL, NULL }, "pool", &match, &checkentry, NULL, THIS_MODULE };
5929 +static int __init init(void)
5931 + return ipt_register_match(&pool_match);
5934 +static void __exit fini(void)
5936 + ipt_unregister_match(&pool_match);
5941 diff -Nur linux-2.6.6-rc1.org/net/ipv4/netfilter/ipt_psd.c linux-2.6.6-rc1/net/ipv4/netfilter/ipt_psd.c
5942 --- linux-2.6.6-rc1.org/net/ipv4/netfilter/ipt_psd.c 1970-01-01 01:00:00.000000000 +0100
5943 +++ linux-2.6.6-rc1/net/ipv4/netfilter/ipt_psd.c 2004-04-19 10:08:37.000000000 +0200
5946 + This is a module which is used for PSD (portscan detection)
5947 + Derived from scanlogd v2.1 written by Solar Designer <solar@false.com>
5948 + and LOG target module.
5950 + Copyright (C) 2000,2001 astaro AG
5952 + This file is distributed under the terms of the GNU General Public
5953 + License (GPL). Copies of the GPL can be obtained from:
5954 + ftp://prep.ai.mit.edu/pub/gnu/GPL
5956 + 2000-05-04 Markus Hennig <hennig@astaro.de> : initial
5957 + 2000-08-18 Dennis Koslowski <koslowski@astaro.de> : first release
5958 + 2000-12-01 Dennis Koslowski <koslowski@astaro.de> : UDP scans detection added
5959 + 2001-01-02 Dennis Koslowski <koslowski@astaro.de> : output modified
5960 + 2001-02-04 Jan Rekorajski <baggins@pld.org.pl> : converted from target to match
5963 +#include <linux/module.h>
5964 +#include <linux/skbuff.h>
5965 +#include <linux/ip.h>
5966 +#include <net/tcp.h>
5967 +#include <linux/spinlock.h>
5968 +#include <linux/netfilter_ipv4/ip_tables.h>
5969 +#include <linux/netfilter_ipv4/ipt_psd.h>
5972 +#define DEBUGP printk
5974 +#define DEBUGP(format, args...)
5977 +MODULE_LICENSE("GPL");
5978 +MODULE_AUTHOR("Dennis Koslowski <koslowski@astaro.com>");
5980 +#define HF_DADDR_CHANGING 0x01
5981 +#define HF_SPORT_CHANGING 0x02
5982 +#define HF_TOS_CHANGING 0x04
5983 +#define HF_TTL_CHANGING 0x08
5986 + * Information we keep per each target port
5989 + u_int16_t number; /* port number */
5990 + u_int8_t proto; /* protocol number */
5991 + u_int8_t and_flags; /* tcp ANDed flags */
5992 + u_int8_t or_flags; /* tcp ORed flags */
5996 + * Information we keep per each source address.
5999 + struct host *next; /* Next entry with the same hash */
6000 + clock_t timestamp; /* Last update time */
6001 + struct in_addr src_addr; /* Source address */
6002 + struct in_addr dest_addr; /* Destination address */
6003 + unsigned short src_port; /* Source port */
6004 + int count; /* Number of ports in the list */
6005 + int weight; /* Total weight of ports in the list */
6006 + struct port ports[SCAN_MAX_COUNT - 1]; /* List of ports */
6007 + unsigned char tos; /* TOS */
6008 + unsigned char ttl; /* TTL */
6009 + unsigned char flags; /* HF_ flags bitmask */
6013 + * State information.
6017 + struct host list[LIST_SIZE]; /* List of source addresses */
6018 + struct host *hash[HASH_SIZE]; /* Hash: pointers into the list */
6019 + int index; /* Oldest entry to be replaced */
6023 + * Convert an IP address into a hash table index.
6025 +static inline int hashfunc(struct in_addr addr)
6027 + unsigned int value;
6030 + value = addr.s_addr;
6034 + } while ((value >>= HASH_LOG));
6036 + return hash & (HASH_SIZE - 1);
6040 +ipt_psd_match(const struct sk_buff *pskb,
6041 + const struct net_device *in,
6042 + const struct net_device *out,
6043 + const void *matchinfo,
6046 + u_int16_t datalen,
6049 + struct iphdr *ip_hdr;
6050 + struct tcphdr *tcp_hdr;
6051 + struct in_addr addr;
6052 + u_int16_t src_port,dest_port;
6053 + u_int8_t tcp_flags, proto;
6055 + struct host *curr, *last, **head;
6056 + int hash, index, count;
6058 + /* Parameters from userspace */
6059 + const struct ipt_psd_info *psdinfo = matchinfo;
6062 + ip_hdr = pskb->nh.iph;
6064 + /* Sanity check */
6065 + if (ntohs(ip_hdr->frag_off) & IP_OFFSET) {
6066 + DEBUGP("PSD: sanity check failed\n");
6070 + /* TCP or UDP ? */
6071 + proto = ip_hdr->protocol;
6073 + if (proto != IPPROTO_TCP && proto != IPPROTO_UDP) {
6074 + DEBUGP("PSD: protocol not supported\n");
6078 + /* Get the source address, source & destination ports, and TCP flags */
6080 + addr.s_addr = ip_hdr->saddr;
6082 + tcp_hdr = (struct tcphdr*)((u_int32_t *)ip_hdr + ip_hdr->ihl);
6084 + /* Yep, it´s dirty */
6085 + src_port = tcp_hdr->source;
6086 + dest_port = tcp_hdr->dest;
6088 + if (proto == IPPROTO_TCP) {
6089 + tcp_flags = *((u_int8_t*)tcp_hdr + 13);
6095 + /* We're using IP address 0.0.0.0 for a special purpose here, so don't let
6096 + * them spoof us. [DHCP needs this feature - HW] */
6097 + if (!addr.s_addr) {
6098 + DEBUGP("PSD: spoofed source address (0.0.0.0)\n");
6102 + /* Use jiffies here not to depend on someone setting the time while we're
6103 + * running; we need to be careful with possible return value overflows. */
6106 + spin_lock(&state.lock);
6108 + /* Do we know this source address already? */
6111 + if ((curr = *(head = &state.hash[hash = hashfunc(addr)])))
6113 + if (curr->src_addr.s_addr == addr.s_addr) break;
6115 + if (curr->next) last = curr;
6116 + } while ((curr = curr->next));
6120 + /* We know this address, and the entry isn't too old. Update it. */
6121 + if (now - curr->timestamp <= (psdinfo->delay_threshold*HZ)/100 &&
6122 + time_after_eq(now, curr->timestamp)) {
6124 + /* Just update the appropriate list entry if we've seen this port already */
6125 + for (index = 0; index < curr->count; index++) {
6126 + if (curr->ports[index].number == dest_port) {
6127 + curr->ports[index].proto = proto;
6128 + curr->ports[index].and_flags &= tcp_flags;
6129 + curr->ports[index].or_flags |= tcp_flags;
6130 + goto out_no_match;
6134 + /* TCP/ACK and/or TCP/RST to a new port? This could be an outgoing connection. */
6135 + if (proto == IPPROTO_TCP && (tcp_hdr->ack || tcp_hdr->rst))
6136 + goto out_no_match;
6138 + /* Packet to a new port, and not TCP/ACK: update the timestamp */
6139 + curr->timestamp = now;
6141 + /* Logged this scan already? Then drop the packet. */
6142 + if (curr->weight >= psdinfo->weight_threshold)
6145 + /* Specify if destination address, source port, TOS or TTL are not fixed */
6146 + if (curr->dest_addr.s_addr != ip_hdr->daddr)
6147 + curr->flags |= HF_DADDR_CHANGING;
6148 + if (curr->src_port != src_port)
6149 + curr->flags |= HF_SPORT_CHANGING;
6150 + if (curr->tos != ip_hdr->tos)
6151 + curr->flags |= HF_TOS_CHANGING;
6152 + if (curr->ttl != ip_hdr->ttl)
6153 + curr->flags |= HF_TTL_CHANGING;
6155 + /* Update the total weight */
6156 + curr->weight += (ntohs(dest_port) < 1024) ?
6157 + psdinfo->lo_ports_weight : psdinfo->hi_ports_weight;
6159 + /* Got enough destination ports to decide that this is a scan? */
6160 + /* Then log it and drop the packet. */
6161 + if (curr->weight >= psdinfo->weight_threshold)
6164 + /* Remember the new port */
6165 + if (curr->count < SCAN_MAX_COUNT) {
6166 + curr->ports[curr->count].number = dest_port;
6167 + curr->ports[curr->count].proto = proto;
6168 + curr->ports[curr->count].and_flags = tcp_flags;
6169 + curr->ports[curr->count].or_flags = tcp_flags;
6173 + goto out_no_match;
6176 + /* We know this address, but the entry is outdated. Mark it unused, and
6177 + * remove from the hash table. We'll allocate a new entry instead since
6178 + * this one might get re-used too soon. */
6179 + curr->src_addr.s_addr = 0;
6181 + last->next = last->next->next;
6183 + *head = (*head)->next;
6187 + /* We don't need an ACK from a new source address */
6188 + if (proto == IPPROTO_TCP && tcp_hdr->ack)
6189 + goto out_no_match;
6191 + /* Got too many source addresses with the same hash value? Then remove the
6192 + * oldest one from the hash table, so that they can't take too much of our
6193 + * CPU time even with carefully chosen spoofed IP addresses. */
6194 + if (count >= HASH_MAX && last) last->next = NULL;
6196 + /* We're going to re-use the oldest list entry, so remove it from the hash
6197 + * table first (if it is really already in use, and isn't removed from the
6198 + * hash table already because of the HASH_MAX check above). */
6200 + /* First, find it */
6201 + if (state.list[state.index].src_addr.s_addr)
6202 + head = &state.hash[hashfunc(state.list[state.index].src_addr)];
6206 + if ((curr = *head))
6208 + if (curr == &state.list[state.index]) break;
6210 + } while ((curr = curr->next));
6212 + /* Then, remove it */
6215 + last->next = last->next->next;
6217 + *head = (*head)->next;
6220 + /* Get our list entry */
6221 + curr = &state.list[state.index++];
6222 + if (state.index >= LIST_SIZE) state.index = 0;
6224 + /* Link it into the hash table */
6225 + head = &state.hash[hash];
6226 + curr->next = *head;
6229 + /* And fill in the fields */
6230 + curr->timestamp = now;
6231 + curr->src_addr = addr;
6232 + curr->dest_addr.s_addr = ip_hdr->daddr;
6233 + curr->src_port = src_port;
6235 + curr->weight = (ntohs(dest_port) < 1024) ?
6236 + psdinfo->lo_ports_weight : psdinfo->hi_ports_weight;
6237 + curr->ports[0].number = dest_port;
6238 + curr->ports[0].proto = proto;
6239 + curr->ports[0].and_flags = tcp_flags;
6240 + curr->ports[0].or_flags = tcp_flags;
6241 + curr->tos = ip_hdr->tos;
6242 + curr->ttl = ip_hdr->ttl;
6245 + spin_unlock(&state.lock);
6249 + spin_unlock(&state.lock);
6253 +static int ipt_psd_checkentry(const char *tablename,
6254 + const struct ipt_ip *e,
6256 + unsigned int matchsize,
6257 + unsigned int hook_mask)
6259 +/* const struct ipt_psd_info *psdinfo = targinfo;*/
6261 + /* we accept TCP only */
6262 +/* if (e->ip.proto != IPPROTO_TCP) { */
6263 +/* DEBUGP("PSD: specified protocol may be TCP only\n"); */
6267 + if (matchsize != IPT_ALIGN(sizeof(struct ipt_psd_info))) {
6268 + DEBUGP("PSD: matchsize %u != %u\n",
6270 + IPT_ALIGN(sizeof(struct ipt_psd_info)));
6277 +static struct ipt_match ipt_psd_reg = {
6281 + ipt_psd_checkentry,
6285 +static int __init init(void)
6287 + if (ipt_register_match(&ipt_psd_reg))
6290 + memset(&state, 0, sizeof(state));
6292 + spin_lock_init(&(state.lock));
6294 + printk("netfilter PSD loaded - (c) astaro AG\n");
6298 +static void __exit fini(void)
6300 + ipt_unregister_match(&ipt_psd_reg);
6301 + printk("netfilter PSD unloaded - (c) astaro AG\n");
6306 diff -Nur linux-2.6.6-rc1.org/net/ipv4/netfilter/ipt_quota.c linux-2.6.6-rc1/net/ipv4/netfilter/ipt_quota.c
6307 --- linux-2.6.6-rc1.org/net/ipv4/netfilter/ipt_quota.c 1970-01-01 01:00:00.000000000 +0100
6308 +++ linux-2.6.6-rc1/net/ipv4/netfilter/ipt_quota.c 2004-04-19 10:08:37.000000000 +0200
6311 + * netfilter module to enforce network quotas
6313 + * Sam Johnston <samj@samj.net>
6315 +#include <linux/module.h>
6316 +#include <linux/skbuff.h>
6317 +#include <linux/spinlock.h>
6318 +#include <linux/interrupt.h>
6320 +#include <linux/netfilter_ipv4/ip_tables.h>
6321 +#include <linux/netfilter_ipv4/ipt_quota.h>
6323 +MODULE_LICENSE("GPL");
6324 +MODULE_AUTHOR("Sam Johnston <samj@samj.net>");
6326 +static spinlock_t quota_lock = SPIN_LOCK_UNLOCKED;
6329 +match(const struct sk_buff *skb,
6330 + const struct net_device *in,
6331 + const struct net_device *out,
6332 + const void *matchinfo,
6333 + int offset, int *hotdrop)
6335 + struct ipt_quota_info *q = (struct ipt_quota_info *) matchinfo;
6336 + unsigned int datalen;
6338 + if (skb->len < sizeof(struct iphdr))
6341 + datalen = skb->len - skb->nh.iph->ihl*4;
6343 + spin_lock_bh("a_lock);
6345 + if (q->quota >= datalen) {
6346 + /* we can afford this one */
6347 + q->quota -= datalen;
6348 + spin_unlock_bh("a_lock);
6350 +#ifdef DEBUG_IPT_QUOTA
6351 + printk("IPT Quota OK: %llu datlen %d \n", q->quota, datalen);
6356 + /* so we do not allow even small packets from now on */
6359 +#ifdef DEBUG_IPT_QUOTA
6360 + printk("IPT Quota Failed: %llu datlen %d \n", q->quota, datalen);
6363 + spin_unlock_bh("a_lock);
6368 +checkentry(const char *tablename,
6369 + const struct ipt_ip *ip,
6370 + void *matchinfo, unsigned int matchsize, unsigned int hook_mask)
6372 + /* TODO: spinlocks? sanity checks? */
6373 + if (matchsize != IPT_ALIGN(sizeof (struct ipt_quota_info)))
6379 +static struct ipt_match quota_match = {
6382 + .checkentry = checkentry,
6389 + return ipt_register_match("a_match);
6395 + ipt_unregister_match("a_match);
6401 diff -Nur linux-2.6.6-rc1.org/net/ipv4/netfilter/ipt_random.c linux-2.6.6-rc1/net/ipv4/netfilter/ipt_random.c
6402 --- linux-2.6.6-rc1.org/net/ipv4/netfilter/ipt_random.c 1970-01-01 01:00:00.000000000 +0100
6403 +++ linux-2.6.6-rc1/net/ipv4/netfilter/ipt_random.c 2004-04-19 10:08:38.000000000 +0200
6406 + This is a module which is used for a "random" match support.
6407 + This file is distributed under the terms of the GNU General Public
6408 + License (GPL). Copies of the GPL can be obtained from:
6409 + ftp://prep.ai.mit.edu/pub/gnu/GPL
6411 + 2001-10-14 Fabrice MARIE <fabrice@netfilter.org> : initial implementation.
6414 +#include <linux/module.h>
6415 +#include <linux/skbuff.h>
6416 +#include <linux/ip.h>
6417 +#include <linux/random.h>
6418 +#include <net/tcp.h>
6419 +#include <linux/spinlock.h>
6420 +#include <linux/netfilter_ipv4/ip_tables.h>
6421 +#include <linux/netfilter_ipv4/ipt_random.h>
6423 +MODULE_LICENSE("GPL");
6426 +ipt_rand_match(const struct sk_buff *pskb,
6427 + const struct net_device *in,
6428 + const struct net_device *out,
6429 + const void *matchinfo,
6432 + u_int16_t datalen,
6435 + /* Parameters from userspace */
6436 + const struct ipt_rand_info *info = matchinfo;
6437 + u_int8_t random_number;
6439 + /* get 1 random number from the kernel random number generation routine */
6440 + get_random_bytes((void *)(&random_number), 1);
6442 + /* Do we match ? */
6443 + if (random_number <= info->average)
6450 +ipt_rand_checkentry(const char *tablename,
6451 + const struct ipt_ip *e,
6453 + unsigned int matchsize,
6454 + unsigned int hook_mask)
6456 + /* Parameters from userspace */
6457 + const struct ipt_rand_info *info = matchinfo;
6459 + if (matchsize != IPT_ALIGN(sizeof(struct ipt_rand_info))) {
6460 + printk("ipt_random: matchsize %u != %u\n", matchsize,
6461 + IPT_ALIGN(sizeof(struct ipt_rand_info)));
6465 + /* must be 1 <= average % <= 99 */
6466 + /* 1 x 2.55 = 2 */
6467 + /* 99 x 2.55 = 252 */
6468 + if ((info->average < 2) || (info->average > 252)) {
6469 + printk("ipt_random: invalid average %u\n", info->average);
6476 +static struct ipt_match ipt_rand_reg = {
6480 + ipt_rand_checkentry,
6484 +static int __init init(void)
6486 + if (ipt_register_match(&ipt_rand_reg))
6489 + printk("ipt_random match loaded\n");
6493 +static void __exit fini(void)
6495 + ipt_unregister_match(&ipt_rand_reg);
6496 + printk("ipt_random match unloaded\n");
6501 diff -Nur linux-2.6.6-rc1.org/net/ipv4/netfilter/ipt_realm.c linux-2.6.6-rc1/net/ipv4/netfilter/ipt_realm.c
6502 --- linux-2.6.6-rc1.org/net/ipv4/netfilter/ipt_realm.c 1970-01-01 01:00:00.000000000 +0100
6503 +++ linux-2.6.6-rc1/net/ipv4/netfilter/ipt_realm.c 2004-04-19 10:08:39.000000000 +0200
6505 +/* IP tables module for matching the routing realm
6509 + * (C) 2003 by Sampsa Ranta <sampsa@netsonic.fi>
6511 + * This program is free software; you can redistribute it and/or modify
6512 + * it under the terms of the GNU General Public License version 2 as
6513 + * published by the Free Software Foundation.
6516 +#include <linux/module.h>
6517 +#include <linux/skbuff.h>
6518 +#include <linux/netdevice.h>
6519 +#include <net/route.h>
6521 +#include <linux/netfilter_ipv4/ipt_realm.h>
6522 +#include <linux/netfilter_ipv4/ip_tables.h>
6524 +MODULE_AUTHOR("Sampsa Ranta <sampsa@netsonic.fi>");
6525 +MODULE_LICENSE("GPL");
6528 +match(const struct sk_buff *skb,
6529 + const struct net_device *in,
6530 + const struct net_device *out,
6531 + const void *matchinfo,
6535 + const struct ipt_realm_info *info = matchinfo;
6536 + struct dst_entry *dst = skb->dst;
6541 + return (info->id == (dst->tclassid & info->mask)) ^ info->invert;
6544 +static int check(const char *tablename,
6545 + const struct ipt_ip *ip,
6547 + unsigned int matchsize,
6548 + unsigned int hook_mask)
6551 + & ~((1 << NF_IP_POST_ROUTING) | (1 << NF_IP_FORWARD) |
6552 + (1 << NF_IP_LOCAL_OUT)| (1 << NF_IP_LOCAL_IN))) {
6553 + printk("ipt_realm: only valid for POST_ROUTING, LOCAL_OUT, "
6554 + "LOCAL_IN or FORWARD.\n");
6558 + if (matchsize != IPT_ALIGN(sizeof(struct ipt_realm_info)))
6564 +static struct ipt_match realm_match = {
6567 + .checkentry = check,
6571 +static int __init init(void)
6573 + return ipt_register_match(&realm_match);
6576 +static void __exit fini(void)
6578 + ipt_unregister_match(&realm_match);
6583 diff -Nur linux-2.6.6-rc1.org/net/ipv4/netfilter/ipt_sctp.c linux-2.6.6-rc1/net/ipv4/netfilter/ipt_sctp.c
6584 --- linux-2.6.6-rc1.org/net/ipv4/netfilter/ipt_sctp.c 1970-01-01 01:00:00.000000000 +0100
6585 +++ linux-2.6.6-rc1/net/ipv4/netfilter/ipt_sctp.c 2004-04-19 10:08:40.000000000 +0200
6587 +#include <linux/module.h>
6588 +#include <linux/skbuff.h>
6589 +#include <net/ip.h>
6590 +#include <linux/sctp.h>
6592 +#include <linux/netfilter_ipv4/ip_tables.h>
6593 +#include <linux/netfilter_ipv4/ipt_sctp.h>
6596 +#define duprintf(format, args...) printk(format , ## args)
6598 +#define duprintf(format, args...)
6601 +#define SCCHECK(cond, option, flag, invflag) (!((flag) & (option)) \
6602 + || (!!((invflag) & (option)) ^ (cond)))
6605 +match_flags(const struct ipt_sctp_flag_info *flag_info,
6606 + const int flag_count,
6607 + u_int8_t chunktype,
6608 + u_int8_t chunkflags)
6612 + for (i = 0; i < flag_count; i++) {
6613 + if (flag_info[i].chunktype == chunktype) {
6614 + return (chunkflags & flag_info[i].flag_mask) == flag_info[i].flag;
6622 +match_packet(const struct sk_buff *skb,
6623 + const u_int32_t *chunkmap,
6624 + int chunk_match_type,
6625 + const struct ipt_sctp_flag_info *flag_info,
6626 + const int flag_count,
6630 + u_int32_t chunkmapcopy[256 / sizeof (u_int32_t)];
6631 + sctp_chunkhdr_t sch;
6635 + if (chunk_match_type == SCTP_CHUNK_MATCH_ALL) {
6636 + SCTP_CHUNKMAP_COPY(chunkmapcopy, chunkmap);
6639 + offset = skb->nh.iph->ihl * 4 + sizeof (sctp_sctphdr_t);
6641 + if (skb_copy_bits(skb, offset, &sch, sizeof(sch)) < 0) {
6642 + duprintf("Dropping invalid SCTP packet.\n");
6647 + duprintf("Chunk num: %d\toffset: %d\ttype: %d\tlength: %d\tflags: %x\n",
6648 + ++i, offset, sch.type, htons(sch.length), sch.flags);
6650 + offset += (htons(sch.length) + 3) & ~3;
6652 + duprintf("skb->len: %d\toffset: %d\n", skb->len, offset);
6654 + if (SCTP_CHUNKMAP_IS_SET(chunkmap, sch.type)) {
6655 + switch (chunk_match_type) {
6656 + case SCTP_CHUNK_MATCH_ANY:
6657 + if (match_flags(flag_info, flag_count,
6658 + sch.type, sch.flags)) {
6663 + case SCTP_CHUNK_MATCH_ALL:
6664 + if (match_flags(flag_info, flag_count,
6665 + sch.type, sch.flags)) {
6666 + SCTP_CHUNKMAP_CLEAR(chunkmapcopy, sch.type);
6670 + case SCTP_CHUNK_MATCH_ONLY:
6671 + if (!match_flags(flag_info, flag_count,
6672 + sch.type, sch.flags)) {
6678 + switch (chunk_match_type) {
6679 + case SCTP_CHUNK_MATCH_ONLY:
6683 + } while (offset < skb->len);
6685 + switch (chunk_match_type) {
6686 + case SCTP_CHUNK_MATCH_ALL:
6687 + return SCTP_CHUNKMAP_IS_CLEAR(chunkmap);
6688 + case SCTP_CHUNK_MATCH_ANY:
6690 + case SCTP_CHUNK_MATCH_ONLY:
6694 + /* This will never be reached, but required to stop compiler whine */
6699 +match(const struct sk_buff *skb,
6700 + const struct net_device *in,
6701 + const struct net_device *out,
6702 + const void *matchinfo,
6706 + const struct ipt_sctp_info *info;
6707 + sctp_sctphdr_t sh;
6709 + info = (const struct ipt_sctp_info *)matchinfo;
6712 + duprintf("Dropping non-first fragment.. FIXME\n");
6716 + if (skb_copy_bits(skb, skb->nh.iph->ihl*4, &sh, sizeof(sh)) < 0) {
6717 + duprintf("Dropping evil TCP offset=0 tinygram.\n");
6721 + duprintf("spt: %d\tdpt: %d\n", ntohs(sh.source), ntohs(sh.dest));
6723 + return SCCHECK(((ntohs(sh.source) >= info->spts[0])
6724 + && (ntohs(sh.source) <= info->spts[1])),
6725 + IPT_SCTP_SRC_PORTS, info->flags, info->invflags)
6726 + && SCCHECK(((ntohs(sh.dest) >= info->dpts[0])
6727 + && (ntohs(sh.dest) <= info->dpts[1])),
6728 + IPT_SCTP_DEST_PORTS, info->flags, info->invflags)
6729 + && SCCHECK(match_packet(skb, info->chunkmap, info->chunk_match_type,
6730 + info->flag_info, info->flag_count,
6732 + IPT_SCTP_CHUNK_TYPES, info->flags, info->invflags);
6736 +checkentry(const char *tablename,
6737 + const struct ipt_ip *ip,
6739 + unsigned int matchsize,
6740 + unsigned int hook_mask)
6742 + const struct ipt_sctp_info *info;
6744 + info = (const struct ipt_sctp_info *)matchinfo;
6746 + return ip->proto == IPPROTO_SCTP
6747 + && !(ip->invflags & IPT_INV_PROTO)
6748 + && matchsize == IPT_ALIGN(sizeof(struct ipt_sctp_info))
6749 + && !(info->flags & ~IPT_SCTP_VALID_FLAGS)
6750 + && !(info->invflags & ~IPT_SCTP_VALID_FLAGS)
6751 + && !(info->invflags & ~info->flags)
6752 + && ((!(info->flags & IPT_SCTP_CHUNK_TYPES)) ||
6753 + (info->chunk_match_type &
6754 + (SCTP_CHUNK_MATCH_ALL
6755 + | SCTP_CHUNK_MATCH_ANY
6756 + | SCTP_CHUNK_MATCH_ONLY)));
6759 +static struct ipt_match sctp_match =
6761 + .list = { NULL, NULL},
6764 + .checkentry = &checkentry,
6769 +static int __init init(void)
6771 + return ipt_register_match(&sctp_match);
6774 +static void __exit fini(void)
6776 + ipt_unregister_match(&sctp_match);
6782 +MODULE_LICENSE("GPL");
6783 +MODULE_AUTHOR("Kiran Kumar Immidi");
6784 +MODULE_DESCRIPTION("Match for SCTP protocol packets");
6786 diff -Nur linux-2.6.6-rc1.org/net/ipv4/netfilter/ipt_time.c linux-2.6.6-rc1/net/ipv4/netfilter/ipt_time.c
6787 --- linux-2.6.6-rc1.org/net/ipv4/netfilter/ipt_time.c 1970-01-01 01:00:00.000000000 +0100
6788 +++ linux-2.6.6-rc1/net/ipv4/netfilter/ipt_time.c 2004-04-19 10:08:41.000000000 +0200
6791 + This is a module which is used for time matching
6792 + It is using some modified code from dietlibc (localtime() function)
6793 + that you can find at http://www.fefe.de/dietlibc/
6794 + This file is distributed under the terms of the GNU General Public
6795 + License (GPL). Copies of the GPL can be obtained from: ftp://prep.ai.mit.edu/pub/gnu/GPL
6796 + 2001-05-04 Fabrice MARIE <fabrice@netfilter.org> : initial development.
6797 + 2001-21-05 Fabrice MARIE <fabrice@netfilter.org> : bug fix in the match code,
6798 + thanks to "Zeng Yu" <zengy@capitel.com.cn> for bug report.
6799 + 2001-26-09 Fabrice MARIE <fabrice@netfilter.org> : force the match to be in LOCAL_IN or PRE_ROUTING only.
6800 + 2001-30-11 Fabrice : added the possibility to use the match in FORWARD/OUTPUT with a little hack,
6801 + added Nguyen Dang Phuoc Dong <dongnd@tlnet.com.vn> patch to support timezones.
6804 +#include <linux/module.h>
6805 +#include <linux/skbuff.h>
6806 +#include <linux/netfilter_ipv4/ip_tables.h>
6807 +#include <linux/netfilter_ipv4/ipt_time.h>
6808 +#include <linux/time.h>
6810 +MODULE_AUTHOR("Fabrice MARIE <fabrice@netfilter.org>");
6811 +MODULE_DESCRIPTION("Match arrival timestamp");
6812 +MODULE_LICENSE("GPL");
6816 + int tm_sec; /* Seconds. [0-60] (1 leap second) */
6817 + int tm_min; /* Minutes. [0-59] */
6818 + int tm_hour; /* Hours. [0-23] */
6819 + int tm_mday; /* Day. [1-31] */
6820 + int tm_mon; /* Month. [0-11] */
6821 + int tm_year; /* Year - 1900. */
6822 + int tm_wday; /* Day of week. [0-6] */
6823 + int tm_yday; /* Days in year.[0-365] */
6824 + int tm_isdst; /* DST. [-1/0/1]*/
6826 + long int tm_gmtoff; /* we don't care, we count from GMT */
6827 + const char *tm_zone; /* we don't care, we count from GMT */
6831 +localtime(const time_t *timepr, struct tm *r);
6834 +match(const struct sk_buff *skb,
6835 + const struct net_device *in,
6836 + const struct net_device *out,
6837 + const void *matchinfo,
6840 + u_int16_t datalen,
6843 + const struct ipt_time_info *info = matchinfo; /* match info for rule */
6844 + struct tm currenttime; /* time human readable */
6845 + u_int8_t days_of_week[7] = {64, 32, 16, 8, 4, 2, 1};
6846 + u_int16_t packet_time;
6847 + struct timeval kerneltimeval;
6848 + time_t packet_local_time;
6850 + /* if kerneltime=1, we don't read the skb->timestamp but kernel time instead */
6851 + if (info->kerneltime)
6853 + do_gettimeofday(&kerneltimeval);
6854 + packet_local_time = kerneltimeval.tv_sec;
6857 + packet_local_time = skb->stamp.tv_sec;
6859 + /* Transform the timestamp of the packet, in a human readable form */
6860 + localtime(&packet_local_time, ¤ttime);
6862 + /* check if we match this timestamp, we start by the days... */
6863 + if ((days_of_week[currenttime.tm_wday] & info->days_match) != days_of_week[currenttime.tm_wday])
6864 + return 0; /* the day doesn't match */
6866 + /* ... check the time now */
6867 + packet_time = (currenttime.tm_hour * 60) + currenttime.tm_min;
6868 + if ((packet_time < info->time_start) || (packet_time > info->time_stop))
6871 + /* here we match ! */
6876 +checkentry(const char *tablename,
6877 + const struct ipt_ip *ip,
6879 + unsigned int matchsize,
6880 + unsigned int hook_mask)
6882 + struct ipt_time_info *info = matchinfo; /* match info for rule */
6884 + /* First, check that we are in the correct hook */
6885 + /* PRE_ROUTING, LOCAL_IN or FROWARD */
6887 + & ~((1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_LOCAL_IN) | (1 << NF_IP_FORWARD) | (1 << NF_IP_LOCAL_OUT)))
6889 + printk("ipt_time: error, only valid for PRE_ROUTING, LOCAL_IN, FORWARD and OUTPUT)\n");
6892 + /* we use the kerneltime if we are in forward or output */
6893 + info->kerneltime = 1;
6894 + if (hook_mask & ~((1 << NF_IP_FORWARD) | (1 << NF_IP_LOCAL_OUT)))
6895 + /* if not, we use the skb time */
6896 + info->kerneltime = 0;
6898 + /* Check the size */
6899 + if (matchsize != IPT_ALIGN(sizeof(struct ipt_time_info)))
6901 + /* Now check the coherence of the data ... */
6902 + if ((info->time_start > 1439) || /* 23*60+59 = 1439*/
6903 + (info->time_stop > 1439))
6905 + printk(KERN_WARNING "ipt_time: invalid argument\n");
6912 +static struct ipt_match time_match
6913 += { { NULL, NULL }, "time", &match, &checkentry, NULL, THIS_MODULE };
6915 +static int __init init(void)
6917 + printk("ipt_time loading\n");
6918 + return ipt_register_match(&time_match);
6921 +static void __exit fini(void)
6923 + ipt_unregister_match(&time_match);
6924 + printk("ipt_time unloaded\n");
6931 +/* The part below is borowed and modified from dietlibc */
6933 +/* seconds per day */
6934 +#define SPD 24*60*60
6937 +localtime(const time_t *timepr, struct tm *r) {
6940 + extern struct timezone sys_tz;
6941 + const unsigned int __spm[12] =
6948 + (31+28+31+30+31+30),
6949 + (31+28+31+30+31+30+31),
6950 + (31+28+31+30+31+30+31+31),
6951 + (31+28+31+30+31+30+31+31+30),
6952 + (31+28+31+30+31+30+31+31+30+31),
6953 + (31+28+31+30+31+30+31+31+30+31+30),
6955 + register time_t work;
6957 + timep = (*timepr) - (sys_tz.tz_minuteswest * 60);
6959 + r->tm_sec=work%60; work/=60;
6960 + r->tm_min=work%60; r->tm_hour=work/60;
6962 + r->tm_wday=(4+work)%7;
6963 + for (i=1970; ; ++i) {
6964 + register time_t k= (!(i%4) && ((i%100) || !(i%400)))?366:365;
6970 + r->tm_year=i-1900;
6971 + for (i=11; i && __spm[i]>work; --i) ;
6973 + r->tm_mday=work-__spm[i]+1;
6975 diff -Nur linux-2.6.6-rc1.org/net/ipv4/netfilter/ipt_u32.c linux-2.6.6-rc1/net/ipv4/netfilter/ipt_u32.c
6976 --- linux-2.6.6-rc1.org/net/ipv4/netfilter/ipt_u32.c 1970-01-01 01:00:00.000000000 +0100
6977 +++ linux-2.6.6-rc1/net/ipv4/netfilter/ipt_u32.c 2004-04-19 10:08:46.000000000 +0200
6979 +/* Kernel module to match u32 packet content. */
6982 +U32 tests whether quantities of up to 4 bytes extracted from a packet
6983 +have specified values. The specification of what to extract is general
6984 +enough to find data at given offsets from tcp headers or payloads.
6987 + The argument amounts to a program in a small language described below.
6988 + tests := location = value | tests && location = value
6989 + value := range | value , range
6990 + range := number | number : number
6991 + a single number, n, is interpreted the same as n:n
6992 + n:m is interpreted as the range of numbers >=n and <=m
6993 + location := number | location operator number
6994 + operator := & | << | >> | @
6996 + The operators &, <<, >>, && mean the same as in c. The = is really a set
6997 + membership operator and the value syntax describes a set. The @ operator
6998 + is what allows moving to the next header and is described further below.
7000 + *** Until I can find out how to avoid it, there are some artificial limits
7001 + on the size of the tests:
7002 + - no more than 10 ='s (and 9 &&'s) in the u32 argument
7003 + - no more than 10 ranges (and 9 commas) per value
7004 + - no more than 10 numbers (and 9 operators) per location
7006 + To describe the meaning of location, imagine the following machine that
7007 + interprets it. There are three registers:
7008 + A is of type char*, initially the address of the IP header
7009 + B and C are unsigned 32 bit integers, initially zero
7011 + The instructions are:
7012 + number B = number;
7013 + C = (*(A+B)<<24)+(*(A+B+1)<<16)+(*(A+B+2)<<8)+*(A+B+3)
7014 + &number C = C&number
7015 + <<number C = C<<number
7016 + >>number C = C>>number
7017 + @number A = A+C; then do the instruction number
7018 + Any access of memory outside [skb->head,skb->end] causes the match to fail.
7019 + Otherwise the result of the computation is the final value of C.
7021 + Whitespace is allowed but not required in the tests.
7022 + However the characters that do occur there are likely to require
7023 + shell quoting, so it's a good idea to enclose the arguments in quotes.
7026 + match IP packets with total length >= 256
7027 + The IP header contains a total length field in bytes 2-3.
7028 + --u32 "0&0xFFFF=0x100:0xFFFF"
7030 + AND that with FFFF (giving bytes 2-3),
7031 + and test whether that's in the range [0x100:0xFFFF]
7033 +Example: (more realistic, hence more complicated)
7034 + match icmp packets with icmp type 0
7035 + First test that it's an icmp packet, true iff byte 9 (protocol) = 1
7036 + --u32 "6&0xFF=1 && ...
7037 + read bytes 6-9, use & to throw away bytes 6-8 and compare the result to 1
7038 + Next test that it's not a fragment.
7039 + (If so it might be part of such a packet but we can't always tell.)
7040 + n.b. This test is generally needed if you want to match anything
7041 + beyond the IP header.
7042 + The last 6 bits of byte 6 and all of byte 7 are 0 iff this is a complete
7043 + packet (not a fragment). Alternatively, you can allow first fragments
7044 + by only testing the last 5 bits of byte 6.
7045 + ... 4&0x3FFF=0 && ...
7046 + Last test: the first byte past the IP header (the type) is 0
7047 + This is where we have to use the @syntax. The length of the IP header
7048 + (IHL) in 32 bit words is stored in the right half of byte 0 of the
7050 + ... 0>>22&0x3C@0>>24=0"
7051 + The first 0 means read bytes 0-3,
7052 + >>22 means shift that 22 bits to the right. Shifting 24 bits would give
7053 + the first byte, so only 22 bits is four times that plus a few more bits.
7054 + &3C then eliminates the two extra bits on the right and the first four
7055 + bits of the first byte.
7056 + For instance, if IHL=5 then the IP header is 20 (4 x 5) bytes long.
7057 + In this case bytes 0-1 are (in binary) xxxx0101 yyzzzzzz,
7058 + >>22 gives the 10 bit value xxxx0101yy and &3C gives 010100.
7059 + @ means to use this number as a new offset into the packet, and read
7060 + four bytes starting from there. This is the first 4 bytes of the icmp
7061 + payload, of which byte 0 is the icmp type. Therefore we simply shift
7062 + the value 24 to the right to throw out all but the first byte and compare
7063 + the result with 0.
7066 + tcp payload bytes 8-12 is any of 1, 2, 5 or 8
7067 + First we test that the packet is a tcp packet (similar to icmp).
7068 + --u32 "6&0xFF=6 && ...
7069 + Next, test that it's not a fragment (same as above).
7070 + ... 0>>22&0x3C@12>>26&0x3C@8=1,2,5,8"
7071 + 0>>22&3C as above computes the number of bytes in the IP header.
7072 + @ makes this the new offset into the packet, which is the start of the
7073 + tcp header. The length of the tcp header (again in 32 bit words) is
7074 + the left half of byte 12 of the tcp header. The 12>>26&3C
7075 + computes this length in bytes (similar to the IP header before).
7076 + @ makes this the new offset, which is the start of the tcp payload.
7077 + Finally 8 reads bytes 8-12 of the payload and = checks whether the
7078 + result is any of 1, 2, 5 or 8
7081 +#include <linux/module.h>
7082 +#include <linux/skbuff.h>
7084 +#include <linux/netfilter_ipv4/ipt_u32.h>
7085 +#include <linux/netfilter_ipv4/ip_tables.h>
7087 +/* #include <asm-i386/timex.h> for timing */
7089 +MODULE_AUTHOR("Don Cohen <don@isis.cs3-inc.com>");
7090 +MODULE_DESCRIPTION("IP tables u32 matching module");
7091 +MODULE_LICENSE("GPL");
7094 +match(const struct sk_buff *skb,
7095 + const struct net_device *in,
7096 + const struct net_device *out,
7097 + const void *matchinfo,
7100 + u_int16_t datalen,
7103 + const struct ipt_u32 *data = matchinfo;
7105 + unsigned char* origbase = (char*)skb->nh.iph;
7106 + unsigned char* base = origbase;
7107 + unsigned char* head = skb->head;
7108 + unsigned char* end = skb->end;
7110 + u_int32_t pos, val;
7111 + /* unsigned long long cycles1, cycles2, cycles3, cycles4;
7112 + cycles1 = get_cycles(); */
7114 + for (testind=0; testind < data->ntests; testind++) {
7115 + base = origbase; /* reset for each test */
7116 + pos = data->tests[testind].location[0].number;
7117 + if (base+pos+3 > end || base+pos < head)
7119 + val = (base[pos]<<24) + (base[pos+1]<<16) +
7120 + (base[pos+2]<<8) + base[pos+3];
7121 + nnums = data->tests[testind].nnums;
7122 + for (i=1; i < nnums; i++) {
7123 + u_int32_t number = data->tests[testind].location[i].number;
7124 + switch (data->tests[testind].location[i].nextop) {
7126 + val = val & number;
7128 + case IPT_U32_LEFTSH:
7129 + val = val << number;
7131 + case IPT_U32_RIGHTSH:
7132 + val = val >> number;
7135 + base = base + val;
7137 + if (base+pos+3 > end || base+pos < head)
7139 + val = (base[pos]<<24) + (base[pos+1]<<16) +
7140 + (base[pos+2]<<8) + base[pos+3];
7144 + nvals = data->tests[testind].nvalues;
7145 + for (i=0; i < nvals; i++) {
7146 + if ((data->tests[testind].value[i].min <= val) &&
7147 + (val <= data->tests[testind].value[i].max)) {
7151 + if (i >= data->tests[testind].nvalues) {
7152 + /* cycles2 = get_cycles();
7153 + printk("failed %d in %d cycles\n", testind,
7154 + cycles2-cycles1); */
7158 + /* cycles2 = get_cycles();
7159 + printk("succeeded in %d cycles\n", cycles2-cycles1); */
7164 +checkentry(const char *tablename,
7165 + const struct ipt_ip *ip,
7167 + unsigned int matchsize,
7168 + unsigned int hook_mask)
7170 + if (matchsize != IPT_ALIGN(sizeof(struct ipt_u32)))
7175 +static struct ipt_match u32_match
7176 += { { NULL, NULL }, "u32", &match, &checkentry, NULL, THIS_MODULE };
7178 +static int __init init(void)
7180 + return ipt_register_match(&u32_match);
7183 +static void __exit fini(void)
7185 + ipt_unregister_match(&u32_match);
7190 diff -Nur linux-2.6.6-rc1.org/net/ipv6/ip6_tunnel.c linux-2.6.6-rc1/net/ipv6/ip6_tunnel.c
7191 --- linux-2.6.6-rc1.org/net/ipv6/ip6_tunnel.c 2004-04-15 03:33:53.000000000 +0200
7192 +++ linux-2.6.6-rc1/net/ipv6/ip6_tunnel.c 2004-04-19 10:08:24.000000000 +0200
7193 @@ -715,13 +715,7 @@
7194 ipv6h->nexthdr = proto;
7195 ipv6_addr_copy(&ipv6h->saddr, &fl.fl6_src);
7196 ipv6_addr_copy(&ipv6h->daddr, &fl.fl6_dst);
7197 -#ifdef CONFIG_NETFILTER
7198 - nf_conntrack_put(skb->nfct);
7200 -#ifdef CONFIG_NETFILTER_DEBUG
7201 - skb->nf_debug = 0;
7206 err = NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL,
7207 skb->dst->dev, dst_output);
7208 diff -Nur linux-2.6.6-rc1.org/net/ipv6/netfilter/Kconfig linux-2.6.6-rc1/net/ipv6/netfilter/Kconfig
7209 --- linux-2.6.6-rc1.org/net/ipv6/netfilter/Kconfig 2004-04-19 09:59:33.000000000 +0200
7210 +++ linux-2.6.6-rc1/net/ipv6/netfilter/Kconfig 2004-04-19 10:08:38.000000000 +0200
7211 @@ -230,5 +230,30 @@
7212 <file:Documentation/modules.txt>. If unsure, say `N'.
7215 +config IP6_NF_TARGET_HL
7216 + tristate 'HL target support'
7217 + depends on IP6_NF_MANGLE
7220 +config IP6_NF_TARGET_REJECT
7221 + tristate 'REJECT target support'
7222 + depends on IP6_NF_FILTER
7225 +config IP6_NF_MATCH_FUZZY
7226 + tristate 'Fuzzy match support'
7227 + depends on IP6_NF_FILTER
7230 +config IP6_NF_MATCH_NTH
7231 + tristate 'Nth match support'
7232 + depends on IP6_NF_IPTABLES
7235 +config IP6_NF_MATCH_RANDOM
7236 + tristate 'Random match support'
7237 + depends on IP6_NF_IPTABLES
7242 diff -Nur linux-2.6.6-rc1.org/net/ipv6/netfilter/Makefile linux-2.6.6-rc1/net/ipv6/netfilter/Makefile
7243 --- linux-2.6.6-rc1.org/net/ipv6/netfilter/Makefile 2004-04-19 09:59:33.000000000 +0200
7244 +++ linux-2.6.6-rc1/net/ipv6/netfilter/Makefile 2004-04-19 10:08:38.000000000 +0200
7246 obj-$(CONFIG_IP6_NF_MATCH_MARK) += ip6t_mark.o
7247 obj-$(CONFIG_IP6_NF_MATCH_LENGTH) += ip6t_length.o
7248 obj-$(CONFIG_IP6_NF_MATCH_MAC) += ip6t_mac.o
7249 +obj-$(CONFIG_IP6_NF_MATCH_FUZZY) += ip6t_fuzzy.o
7250 obj-$(CONFIG_IP6_NF_MATCH_RT) += ip6t_rt.o
7251 obj-$(CONFIG_IP6_NF_MATCH_OPTS) += ip6t_hbh.o ip6t_dst.o
7252 obj-$(CONFIG_IP6_NF_MATCH_IPV6HEADER) += ip6t_ipv6header.o
7254 obj-$(CONFIG_IP6_NF_FILTER) += ip6table_filter.o
7255 obj-$(CONFIG_IP6_NF_MANGLE) += ip6table_mangle.o
7256 obj-$(CONFIG_IP6_NF_TARGET_MARK) += ip6t_MARK.o
7257 +obj-$(CONFIG_IP6_NF_TARGET_REJECT) += ip6t_REJECT.o
7258 obj-$(CONFIG_IP6_NF_QUEUE) += ip6_queue.o
7259 obj-$(CONFIG_IP6_NF_TARGET_LOG) += ip6t_LOG.o
7261 +obj-$(CONFIG_IP6_NF_MATCH_RANDOM) += ip6t_random.o
7263 +obj-$(CONFIG_IP6_NF_MATCH_NTH) += ip6t_nth.o
7264 +obj-$(CONFIG_IP6_NF_TARGET_HL) += ip6t_HL.o
7265 obj-$(CONFIG_IP6_NF_RAW) += ip6table_raw.o
7266 obj-$(CONFIG_IP6_NF_MATCH_HL) += ip6t_hl.o
7267 diff -Nur linux-2.6.6-rc1.org/net/ipv6/netfilter/ip6t_HL.c linux-2.6.6-rc1/net/ipv6/netfilter/ip6t_HL.c
7268 --- linux-2.6.6-rc1.org/net/ipv6/netfilter/ip6t_HL.c 1970-01-01 01:00:00.000000000 +0100
7269 +++ linux-2.6.6-rc1/net/ipv6/netfilter/ip6t_HL.c 2004-04-19 10:08:26.000000000 +0200
7272 + * Hop Limit modification target for ip6tables
7273 + * Maciej Soltysiak <solt@dns.toxicfilms.tv>
7274 + * Based on HW's TTL module
7276 + * This software is distributed under the terms of GNU GPL
7279 +#include <linux/module.h>
7280 +#include <linux/skbuff.h>
7281 +#include <linux/ip.h>
7283 +#include <linux/netfilter_ipv6/ip6_tables.h>
7284 +#include <linux/netfilter_ipv6/ip6t_HL.h>
7286 +MODULE_AUTHOR("Maciej Soltysiak <solt@dns.toxicfilms.tv>");
7287 +MODULE_DESCRIPTION("IP tables Hop Limit modification module");
7288 +MODULE_LICENSE("GPL");
7290 +static unsigned int ip6t_hl_target(struct sk_buff **pskb, unsigned int hooknum,
7291 + const struct net_device *in, const struct net_device *out,
7292 + const void *targinfo, void *userinfo)
7294 + struct ipv6hdr *ip6h = (*pskb)->nh.ipv6h;
7295 + const struct ip6t_HL_info *info = targinfo;
7296 + u_int16_t diffs[2];
7299 + switch (info->mode) {
7301 + new_hl = info->hop_limit;
7304 + new_hl = ip6h->hop_limit + info->hop_limit;
7309 + new_hl = ip6h->hop_limit + info->hop_limit;
7314 + new_hl = ip6h->hop_limit;
7318 + if (new_hl != ip6h->hop_limit) {
7319 + diffs[0] = htons(((unsigned)ip6h->hop_limit) << 8) ^ 0xFFFF;
7320 + ip6h->hop_limit = new_hl;
7321 + diffs[1] = htons(((unsigned)ip6h->hop_limit) << 8);
7324 + return IP6T_CONTINUE;
7327 +static int ip6t_hl_checkentry(const char *tablename,
7328 + const struct ip6t_entry *e,
7330 + unsigned int targinfosize,
7331 + unsigned int hook_mask)
7333 + struct ip6t_HL_info *info = targinfo;
7335 + if (targinfosize != IP6T_ALIGN(sizeof(struct ip6t_HL_info))) {
7336 + printk(KERN_WARNING "HL: targinfosize %u != %Zu\n",
7338 + IP6T_ALIGN(sizeof(struct ip6t_HL_info)));
7342 + if (strcmp(tablename, "mangle")) {
7343 + printk(KERN_WARNING "HL: can only be called from \"mangle\" table, not \"%s\"\n", tablename);
7347 + if (info->mode > IP6T_HL_MAXMODE) {
7348 + printk(KERN_WARNING "HL: invalid or unknown Mode %u\n",
7353 + if ((info->mode != IP6T_HL_SET) && (info->hop_limit == 0)) {
7354 + printk(KERN_WARNING "HL: increment/decrement doesn't make sense with value 0\n");
7361 +static struct ip6t_target ip6t_HL = { { NULL, NULL }, "HL",
7362 + ip6t_hl_target, ip6t_hl_checkentry, NULL, THIS_MODULE };
7364 +static int __init init(void)
7366 + return ip6t_register_target(&ip6t_HL);
7369 +static void __exit fini(void)
7371 + ip6t_unregister_target(&ip6t_HL);
7376 diff -Nur linux-2.6.6-rc1.org/net/ipv6/netfilter/ip6t_REJECT.c linux-2.6.6-rc1/net/ipv6/netfilter/ip6t_REJECT.c
7377 --- linux-2.6.6-rc1.org/net/ipv6/netfilter/ip6t_REJECT.c 1970-01-01 01:00:00.000000000 +0100
7378 +++ linux-2.6.6-rc1/net/ipv6/netfilter/ip6t_REJECT.c 2004-04-19 10:08:28.000000000 +0200
7381 + * IP6 tables REJECT target module
7382 + * Linux INET6 implementation
7384 + * Copyright (C)2003 USAGI/WIDE Project
7387 + * Yasuyuki Kozakai <yasuyuki.kozakai@toshiba.co.jp>
7389 + * Based on net/ipv4/netfilter/ipt_REJECT.c
7391 + * This program is free software; you can redistribute it and/or
7392 + * modify it under the terms of the GNU General Public License
7393 + * as published by the Free Software Foundation; either version
7394 + * 2 of the License, or (at your option) any later version.
7397 +#include <linux/config.h>
7398 +#include <linux/module.h>
7399 +#include <linux/skbuff.h>
7400 +#include <linux/icmpv6.h>
7401 +#include <net/ipv6.h>
7402 +#include <net/tcp.h>
7403 +#include <net/icmp.h>
7404 +#include <net/ip6_fib.h>
7405 +#include <net/ip6_route.h>
7406 +#include <net/flow.h>
7407 +#include <linux/netfilter_ipv6/ip6_tables.h>
7408 +#include <linux/netfilter_ipv6/ip6t_REJECT.h>
7410 +MODULE_AUTHOR("Yasuyuki KOZAKAI <yasuyuki.kozakai@toshiba.co.jp>");
7411 +MODULE_DESCRIPTION("IP6 tables REJECT target module");
7412 +MODULE_LICENSE("GPL");
7415 +#define DEBUGP printk
7417 +#define DEBUGP(format, args...)
7421 +static void connection_attach(struct sk_buff *new_skb, struct nf_ct_info *nfct)
7423 + void (*attach)(struct sk_buff *, struct nf_ct_info *);
7424 + if (nfct && (attach = ip6_ct_attach) != NULL) {
7426 + attach(new_skb, nfct);
7431 +static int maybe_reroute(struct sk_buff *skb)
7433 + if (skb->nfcache & NFC_ALTERED){
7434 + if (ip6_route_me_harder(skb) != 0){
7440 + return dst_output(skb);
7443 +/* Send RST reply */
7444 +static void send_reset(struct sk_buff *oldskb)
7446 + struct sk_buff *nskb;
7447 + struct tcphdr otcph, *tcph;
7448 + unsigned int otcplen, tcphoff, hh_len;
7450 + struct ipv6hdr *oip6h = oldskb->nh.ipv6h, *ip6h;
7451 + struct dst_entry *dst = NULL;
7454 + proto = oip6h->nexthdr;
7457 + if ((!(ipv6_addr_type(&oip6h->saddr) & IPV6_ADDR_UNICAST)) ||
7458 + (!(ipv6_addr_type(&oip6h->daddr) & IPV6_ADDR_UNICAST))) {
7459 + DEBUGP("ip6t_REJECT: addr is not unicast.\n");
7463 + tcphoff = ipv6_skip_exthdr(oldskb, ((u8*)(oip6h+1) - oldskb->data),
7464 + &proto, oldskb->len - ((u8*)(oip6h+1)
7467 + if ((tcphoff < 0) || (tcphoff > oldskb->len)) {
7468 + DEBUGP("ip6t_REJECT: Can't get TCP header.\n");
7472 + otcplen = oldskb->len - tcphoff;
7474 + /* IP header checks: fragment, too short. */
7475 + if ((proto != IPPROTO_TCP) || (otcplen < sizeof(struct tcphdr))) {
7476 + DEBUGP("ip6t_REJECT: proto(%d) != IPPROTO_TCP, or too short. otcplen = %d\n",
7481 + if (skb_copy_bits(oldskb, tcphoff, &otcph, sizeof(struct tcphdr))) {
7482 + if (net_ratelimit())
7483 + printk("ip6t_REJECT: Can't copy tcp header\n");
7487 + /* No RST for RST. */
7489 + DEBUGP("ip6t_REJECT: RST is set\n");
7493 + /* Check checksum. */
7494 + if (csum_ipv6_magic(&oip6h->saddr, &oip6h->daddr, otcplen, IPPROTO_TCP,
7495 + skb_checksum(oldskb, tcphoff, otcplen, 0))) {
7496 + DEBUGP("ip6t_REJECT: TCP checksum is invalid\n");
7500 + memset(&fl, 0, sizeof(fl));
7501 + fl.proto = IPPROTO_TCP;
7502 + ipv6_addr_copy(&fl.fl6_src, &oip6h->daddr);
7503 + ipv6_addr_copy(&fl.fl6_dst, &oip6h->saddr);
7504 + fl.fl_ip_sport = otcph.dest;
7505 + fl.fl_ip_dport = otcph.source;
7506 + err = ip6_dst_lookup(NULL, &dst, &fl);
7508 + if (net_ratelimit())
7509 + printk("ip6t_REJECT: can't find dst. err = %d\n", err);
7513 + hh_len = (dst->dev->hard_header_len + 15)&~15;
7514 + nskb = alloc_skb(hh_len + 15 + dst->header_len + sizeof(struct ipv6hdr)
7515 + + sizeof(struct tcphdr) + dst->trailer_len,
7519 + if (net_ratelimit())
7520 + printk("ip6t_REJECT: Can't alloc skb\n");
7528 + skb_reserve(nskb, hh_len + dst->header_len);
7530 + ip6h = nskb->nh.ipv6h = (struct ipv6hdr *)
7531 + skb_put(nskb, sizeof(struct ipv6hdr));
7532 + ip6h->version = 6;
7533 + ip6h->hop_limit = dst_metric(dst, RTAX_HOPLIMIT);
7534 + ip6h->nexthdr = IPPROTO_TCP;
7535 + ip6h->payload_len = htons(sizeof(struct tcphdr));
7536 + ipv6_addr_copy(&ip6h->saddr, &oip6h->daddr);
7537 + ipv6_addr_copy(&ip6h->daddr, &oip6h->saddr);
7539 + tcph = (struct tcphdr *)skb_put(nskb, sizeof(struct tcphdr));
7540 + /* Truncate to length (no data) */
7541 + tcph->doff = sizeof(struct tcphdr)/4;
7542 + tcph->source = otcph.dest;
7543 + tcph->dest = otcph.source;
7547 + tcph->seq = otcph.ack_seq;
7548 + tcph->ack_seq = 0;
7551 + tcph->ack_seq = htonl(ntohl(otcph.seq) + otcph.syn + otcph.fin
7552 + + otcplen - (otcph.doff<<2));
7557 + ((u_int8_t *)tcph)[13] = 0;
7559 + tcph->ack = needs_ack;
7561 + tcph->urg_ptr = 0;
7564 + /* Adjust TCP checksum */
7565 + tcph->check = csum_ipv6_magic(&nskb->nh.ipv6h->saddr,
7566 + &nskb->nh.ipv6h->daddr,
7567 + sizeof(struct tcphdr), IPPROTO_TCP,
7568 + csum_partial((char *)tcph,
7569 + sizeof(struct tcphdr), 0));
7572 + connection_attach(nskb, oldskb->nfct);
7575 + NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, nskb, NULL, nskb->dst->dev,
7581 +static void send_unreach(struct sk_buff *skb_in, unsigned char code)
7583 + struct ipv6hdr *ip6h, *hdr = skb_in->nh.ipv6h;
7584 + struct icmp6hdr *icmp6h;
7585 + struct dst_entry *dst = NULL;
7586 + struct rt6_info *rt;
7589 + unsigned int len, datalen, hh_len;
7590 + int saddr_type, daddr_type;
7591 + unsigned int ptr, ip6off;
7594 + struct sk_buff *nskb;
7597 + saddr_type = ipv6_addr_type(&hdr->saddr);
7598 + daddr_type = ipv6_addr_type(&hdr->daddr);
7600 + if ((!(saddr_type & IPV6_ADDR_UNICAST)) ||
7601 + (!(daddr_type & IPV6_ADDR_UNICAST))) {
7602 + DEBUGP("ip6t_REJECT: addr is not unicast.\n");
7606 + ip6off = skb_in->nh.raw - skb_in->data;
7607 + proto = hdr->nexthdr;
7608 + ptr = ipv6_skip_exthdr(skb_in, ip6off + sizeof(struct ipv6hdr), &proto,
7609 + skb_in->len - ip6off);
7611 + if ((ptr < 0) || (ptr > skb_in->len)) {
7612 + ptr = ip6off + sizeof(struct ipv6hdr);
7613 + proto = hdr->nexthdr;
7614 + } else if (proto == IPPROTO_ICMPV6) {
7617 + if (skb_copy_bits(skb_in, ptr + offsetof(struct icmp6hdr,
7618 + icmp6_type), &type, 1)) {
7619 + DEBUGP("ip6t_REJECT: Can't get ICMPv6 type\n");
7623 + if (!(type & ICMPV6_INFOMSG_MASK)) {
7624 + DEBUGP("ip6t_REJECT: no reply to icmp error\n");
7627 + } else if (proto == IPPROTO_UDP) {
7628 + int plen = skb_in->len - (ptr - ip6off);
7631 + if (plen < sizeof(struct udphdr)) {
7632 + DEBUGP("ip6t_REJECT: too short\n");
7636 + if (skb_copy_bits(skb_in, ptr + offsetof(struct udphdr, check),
7638 + if (net_ratelimit())
7639 + printk("ip6t_REJECT: can't get copy from skb");
7644 + csum_ipv6_magic(&hdr->saddr, &hdr->daddr, plen,
7646 + skb_checksum(skb_in, ptr, plen, 0))) {
7647 + DEBUGP("ip6t_REJECT: UDP checksum is invalid.\n");
7652 + memset(&fl, 0, sizeof(fl));
7653 + fl.proto = IPPROTO_ICMPV6;
7654 + ipv6_addr_copy(&fl.fl6_src, &hdr->daddr);
7655 + ipv6_addr_copy(&fl.fl6_dst, &hdr->saddr);
7656 + fl.fl_icmp_type = ICMPV6_DEST_UNREACH;
7657 + fl.fl_icmp_code = code;
7659 + if (ip6_dst_lookup(NULL, &dst, &fl)) {
7663 + rt = (struct rt6_info *)dst;
7666 + if (rt->rt6i_dst.plen < 128)
7667 + tmo >>= ((128 - rt->rt6i_dst.plen)>>5);
7669 + if (!xrlim_allow(dst, tmo)) {
7670 + if (net_ratelimit())
7671 + printk("ip6t_REJECT: rate limitted\n");
7672 + goto dst_release_out;
7675 + len = skb_in->len + sizeof(struct ipv6hdr) + sizeof(struct icmp6hdr);
7677 + if (len > dst_pmtu(dst))
7678 + len = dst_pmtu(dst);
7679 + if (len > IPV6_MIN_MTU)
7680 + len = IPV6_MIN_MTU;
7682 + datalen = len - sizeof(struct ipv6hdr) - sizeof(struct icmp6hdr);
7683 + hh_len = (rt->u.dst.dev->hard_header_len + 15)&~15;
7685 + nskb = alloc_skb(hh_len + 15 + dst->header_len + dst->trailer_len + len,
7689 + if (net_ratelimit())
7690 + printk("ip6t_REJECT: can't alloc skb\n");
7691 + goto dst_release_out;
7694 + nskb->priority = 0;
7698 + skb_reserve(nskb, hh_len + dst->header_len);
7700 + ip6h = nskb->nh.ipv6h = (struct ipv6hdr *)
7701 + skb_put(nskb, sizeof(struct ipv6hdr));
7702 + ip6h->version = 6;
7703 + ip6h->hop_limit = dst_metric(dst, RTAX_HOPLIMIT);
7704 + ip6h->nexthdr = IPPROTO_ICMPV6;
7705 + ip6h->payload_len = htons(datalen + sizeof(struct icmp6hdr));
7706 + ipv6_addr_copy(&ip6h->saddr, &hdr->daddr);
7707 + ipv6_addr_copy(&ip6h->daddr, &hdr->saddr);
7709 + icmp6h = (struct icmp6hdr *) skb_put(nskb, sizeof(struct icmp6hdr));
7710 + icmp6h->icmp6_type = ICMPV6_DEST_UNREACH;
7711 + icmp6h->icmp6_code = code;
7712 + icmp6h->icmp6_cksum = 0;
7714 + data = skb_put(nskb, datalen);
7716 + csum = csum_partial((unsigned char *)icmp6h, sizeof(struct icmp6hdr), 0);
7717 + csum = skb_copy_and_csum_bits(skb_in, ip6off, data, datalen, csum);
7718 + icmp6h->icmp6_cksum = csum_ipv6_magic(&hdr->saddr, &hdr->daddr,
7719 + datalen + sizeof(struct icmp6hdr),
7720 + IPPROTO_ICMPV6, csum);
7723 + connection_attach(nskb, skb_in->nfct);
7725 + NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, nskb, NULL, nskb->dst->dev,
7732 +static unsigned int reject6_target(struct sk_buff **pskb,
7733 + unsigned int hooknum,
7734 + const struct net_device *in,
7735 + const struct net_device *out,
7736 + const void *targinfo,
7739 + const struct ip6t_reject_info *reject = targinfo;
7741 + DEBUGP(KERN_DEBUG "%s: medium point\n", __FUNCTION__);
7742 + /* WARNING: This code causes reentry within ip6tables.
7743 + This means that the ip6tables jump stack is now crap. We
7744 + must return an absolute verdict. --RR */
7745 + switch (reject->with) {
7746 + case IP6T_ICMP6_NO_ROUTE:
7747 + send_unreach(*pskb, ICMPV6_NOROUTE);
7749 + case IP6T_ICMP6_ADM_PROHIBITED:
7750 + send_unreach(*pskb, ICMPV6_ADM_PROHIBITED);
7752 + case IP6T_ICMP6_NOT_NEIGHBOUR:
7753 + send_unreach(*pskb, ICMPV6_NOT_NEIGHBOUR);
7755 + case IP6T_ICMP6_ADDR_UNREACH:
7756 + send_unreach(*pskb, ICMPV6_ADDR_UNREACH);
7758 + case IP6T_ICMP6_PORT_UNREACH:
7759 + send_unreach(*pskb, ICMPV6_PORT_UNREACH);
7761 + case IP6T_ICMP6_ECHOREPLY:
7764 + case IP6T_TCP_RESET:
7765 + send_reset(*pskb);
7768 + if (net_ratelimit())
7769 + printk(KERN_WARNING "ip6t_REJECT: case %u not handled yet\n", reject->with);
7776 +static int check(const char *tablename,
7777 + const struct ip6t_entry *e,
7779 + unsigned int targinfosize,
7780 + unsigned int hook_mask)
7782 + const struct ip6t_reject_info *rejinfo = targinfo;
7784 + if (targinfosize != IP6T_ALIGN(sizeof(struct ip6t_reject_info))) {
7785 + DEBUGP("ip6t_REJECT: targinfosize %u != 0\n", targinfosize);
7789 + /* Only allow these for packet filtering. */
7790 + if (strcmp(tablename, "filter") != 0) {
7791 + DEBUGP("ip6t_REJECT: bad table `%s'.\n", tablename);
7795 + if ((hook_mask & ~((1 << NF_IP6_LOCAL_IN)
7796 + | (1 << NF_IP6_FORWARD)
7797 + | (1 << NF_IP6_LOCAL_OUT))) != 0) {
7798 + DEBUGP("ip6t_REJECT: bad hook mask %X\n", hook_mask);
7802 + if (rejinfo->with == IP6T_ICMP6_ECHOREPLY) {
7803 + printk("ip6t_REJECT: ECHOREPLY is not supported.\n");
7805 + } else if (rejinfo->with == IP6T_TCP_RESET) {
7806 + /* Must specify that it's a TCP packet */
7807 + if (e->ipv6.proto != IPPROTO_TCP
7808 + || (e->ipv6.invflags & IP6T_INV_PROTO)) {
7809 + DEBUGP("ip6t_REJECT: TCP_RESET illegal for non-tcp\n");
7817 +static struct ip6t_target ip6t_reject_reg = {
7819 + .target = reject6_target,
7820 + .checkentry = check,
7824 +static int __init init(void)
7826 + if (ip6t_register_target(&ip6t_reject_reg))
7831 +static void __exit fini(void)
7833 + ip6t_unregister_target(&ip6t_reject_reg);
7838 diff -Nur linux-2.6.6-rc1.org/net/ipv6/netfilter/ip6t_fuzzy.c linux-2.6.6-rc1/net/ipv6/netfilter/ip6t_fuzzy.c
7839 --- linux-2.6.6-rc1.org/net/ipv6/netfilter/ip6t_fuzzy.c 1970-01-01 01:00:00.000000000 +0100
7840 +++ linux-2.6.6-rc1/net/ipv6/netfilter/ip6t_fuzzy.c 2004-04-19 10:08:31.000000000 +0200
7843 + * This module implements a simple TSK FLC
7844 + * (Takagi-Sugeno-Kang Fuzzy Logic Controller) that aims
7845 + * to limit , in an adaptive and flexible way , the packet rate crossing
7846 + * a given stream . It serves as an initial and very simple (but effective)
7847 + * example of how Fuzzy Logic techniques can be applied to defeat DoS attacks.
7848 + * As a matter of fact , Fuzzy Logic can help us to insert any "behavior"
7849 + * into our code in a precise , adaptive and efficient manner.
7850 + * The goal is very similar to that of "limit" match , but using techniques of
7851 + * Fuzzy Control , that allow us to shape the transfer functions precisely ,
7852 + * avoiding over and undershoots - and stuff like that .
7855 + * 2002-08-10 Hime Aguiar e Oliveira Jr. <hime@engineer.com> : Initial version.
7856 + * 2002-08-17 : Changed to eliminate floating point operations .
7857 + * 2002-08-23 : Coding style changes .
7858 + * 2003-04-08 Maciej Soltysiak <solt@dns.toxicilms.tv> : IPv6 Port
7861 +#include <linux/module.h>
7862 +#include <linux/skbuff.h>
7863 +#include <linux/ipv6.h>
7864 +#include <linux/random.h>
7865 +#include <net/tcp.h>
7866 +#include <linux/spinlock.h>
7867 +#include <linux/netfilter_ipv6/ip6_tables.h>
7868 +#include <linux/netfilter_ipv6/ip6t_fuzzy.h>
7871 + Packet Acceptance Rate - LOW and Packet Acceptance Rate - HIGH
7872 + Expressed in percentage
7875 +#define PAR_LOW 1/100
7878 +static spinlock_t fuzzy_lock = SPIN_LOCK_UNLOCKED;
7880 +MODULE_AUTHOR("Hime Aguiar e Oliveira Junior <hime@engineer.com>");
7881 +MODULE_DESCRIPTION("IP tables Fuzzy Logic Controller match module");
7882 +MODULE_LICENSE("GPL");
7884 +static u_int8_t mf_high(u_int32_t tx,u_int32_t mini,u_int32_t maxi)
7886 + if (tx >= maxi) return 100;
7888 + if (tx <= mini) return 0;
7890 + return ((100 * (tx-mini)) / (maxi-mini));
7893 +static u_int8_t mf_low(u_int32_t tx,u_int32_t mini,u_int32_t maxi)
7895 + if (tx <= mini) return 100;
7897 + if (tx >= maxi) return 0;
7899 + return ((100 * (maxi - tx)) / (maxi - mini));
7904 +ip6t_fuzzy_match(const struct sk_buff *pskb,
7905 + const struct net_device *in,
7906 + const struct net_device *out,
7907 + const void *matchinfo,
7910 + u_int16_t datalen,
7913 + /* From userspace */
7915 + struct ip6t_fuzzy_info *info = (struct ip6t_fuzzy_info *) matchinfo;
7917 + u_int8_t random_number;
7918 + unsigned long amount;
7919 + u_int8_t howhigh, howlow;
7922 + spin_lock_bh(&fuzzy_lock); /* Rise the lock */
7924 + info->bytes_total += pskb->len;
7925 + info->packets_total++;
7927 + info->present_time = jiffies;
7929 + if (info->present_time >= info->previous_time)
7930 + amount = info->present_time - info->previous_time;
7932 + /* There was a transition : I choose to re-sample
7933 + and keep the old acceptance rate...
7937 + info->previous_time = info->present_time;
7938 + info->bytes_total = info->packets_total = 0;
7941 + if ( amount > HZ/10) {/* More than 100 ms elapsed ... */
7943 + info->mean_rate = (u_int32_t) ((HZ * info->packets_total) \
7946 + info->previous_time = info->present_time;
7947 + info->bytes_total = info->packets_total = 0;
7949 + howhigh = mf_high(info->mean_rate,info->minimum_rate,info->maximum_rate);
7950 + howlow = mf_low(info->mean_rate,info->minimum_rate,info->maximum_rate);
7952 + info->acceptance_rate = (u_int8_t) \
7953 + (howhigh * PAR_LOW + PAR_HIGH * howlow);
7955 + /* In fact, the above defuzzification would require a denominator
7956 + * proportional to (howhigh+howlow) but, in this particular case,
7957 + * that expression is constant.
7958 + * An imediate consequence is that it is not necessary to call
7959 + * both mf_high and mf_low - but to keep things understandable,
7965 + spin_unlock_bh(&fuzzy_lock); /* Release the lock */
7968 + if (info->acceptance_rate < 100)
7970 + get_random_bytes((void *)(&random_number), 1);
7972 + /* If within the acceptance , it can pass => don't match */
7973 + if (random_number <= (255 * info->acceptance_rate) / 100)
7976 + return 1; /* It can't pass (It matches) */
7979 + return 0; /* acceptance_rate == 100 % => Everything passes ... */
7984 +ip6t_fuzzy_checkentry(const char *tablename,
7985 + const struct ip6t_ip6 *ip,
7987 + unsigned int matchsize,
7988 + unsigned int hook_mask)
7991 + const struct ip6t_fuzzy_info *info = matchinfo;
7993 + if (matchsize != IP6T_ALIGN(sizeof(struct ip6t_fuzzy_info))) {
7994 + printk("ip6t_fuzzy: matchsize %u != %u\n", matchsize,
7995 + IP6T_ALIGN(sizeof(struct ip6t_fuzzy_info)));
7999 + if ((info->minimum_rate < MINFUZZYRATE) || (info->maximum_rate > MAXFUZZYRATE)
8000 + || (info->minimum_rate >= info->maximum_rate)) {
8001 + printk("ip6t_fuzzy: BAD limits , please verify !!!\n");
8008 +static struct ip6t_match ip6t_fuzzy_reg = {
8012 + ip6t_fuzzy_checkentry,
8016 +static int __init init(void)
8018 + if (ip6t_register_match(&ip6t_fuzzy_reg))
8024 +static void __exit fini(void)
8026 + ip6t_unregister_match(&ip6t_fuzzy_reg);
8031 diff -Nur linux-2.6.6-rc1.org/net/ipv6/netfilter/ip6t_nth.c linux-2.6.6-rc1/net/ipv6/netfilter/ip6t_nth.c
8032 --- linux-2.6.6-rc1.org/net/ipv6/netfilter/ip6t_nth.c 1970-01-01 01:00:00.000000000 +0100
8033 +++ linux-2.6.6-rc1/net/ipv6/netfilter/ip6t_nth.c 2004-04-19 10:08:34.000000000 +0200
8036 + This is a module which is used for match support for every Nth packet
8037 + This file is distributed under the terms of the GNU General Public
8038 + License (GPL). Copies of the GPL can be obtained from:
8039 + ftp://prep.ai.mit.edu/pub/gnu/GPL
8041 + 2001-07-18 Fabrice MARIE <fabrice@netfilter.org> : initial implementation.
8042 + 2001-09-20 Richard Wagner (rwagner@cloudnet.com)
8043 + * added support for multiple counters
8044 + * added support for matching on individual packets
8045 + in the counter cycle
8046 + 2003-04-30 Maciej Soltysiak <solt@dns.toxicfilms.tv> : IPv6 Port
8050 +#include <linux/module.h>
8051 +#include <linux/skbuff.h>
8052 +#include <linux/ip.h>
8053 +#include <net/tcp.h>
8054 +#include <linux/spinlock.h>
8055 +#include <linux/netfilter_ipv6/ip6_tables.h>
8056 +#include <linux/netfilter_ipv6/ip6t_nth.h>
8058 +MODULE_LICENSE("GPL");
8061 + * State information.
8068 +static struct state states[IP6T_NTH_NUM_COUNTERS];
8071 +ip6t_nth_match(const struct sk_buff *pskb,
8072 + const struct net_device *in,
8073 + const struct net_device *out,
8074 + const void *matchinfo,
8077 + u_int16_t datalen,
8080 + /* Parameters from userspace */
8081 + const struct ip6t_nth_info *info = matchinfo;
8082 + unsigned counter = info->counter;
8083 + if((counter < 0) || (counter >= IP6T_NTH_NUM_COUNTERS))
8085 + printk(KERN_WARNING "nth: invalid counter %u. counter between 0 and %u\n", counter, IP6T_NTH_NUM_COUNTERS-1);
8089 + spin_lock(&states[counter].lock);
8091 + /* Are we matching every nth packet?*/
8092 + if (info->packet == 0xFF)
8094 + /* We're matching every nth packet and only every nth packet*/
8095 + /* Do we match or invert match? */
8096 + if (info->not == 0)
8098 + if (states[counter].number == 0)
8100 + ++states[counter].number;
8103 + if (states[counter].number >= info->every)
8104 + states[counter].number = 0; /* reset the counter */
8106 + ++states[counter].number;
8111 + if (states[counter].number == 0)
8113 + ++states[counter].number;
8116 + if (states[counter].number >= info->every)
8117 + states[counter].number = 0;
8119 + ++states[counter].number;
8125 + /* We're using the --packet, so there must be a rule for every value */
8126 + if (states[counter].number == info->packet)
8128 + /* only increment the counter when a match happens */
8129 + if (states[counter].number >= info->every)
8130 + states[counter].number = 0; /* reset the counter */
8132 + ++states[counter].number;
8141 + spin_unlock(&states[counter].lock);
8145 + spin_unlock(&states[counter].lock);
8150 +ip6t_nth_checkentry(const char *tablename,
8151 + const struct ip6t_ip6 *e,
8153 + unsigned int matchsize,
8154 + unsigned int hook_mask)
8156 + /* Parameters from userspace */
8157 + const struct ip6t_nth_info *info = matchinfo;
8158 + unsigned counter = info->counter;
8159 + if((counter < 0) || (counter >= IP6T_NTH_NUM_COUNTERS))
8161 + printk(KERN_WARNING "nth: invalid counter %u. counter between 0 and %u\n", counter, IP6T_NTH_NUM_COUNTERS-1);
8165 + if (matchsize != IP6T_ALIGN(sizeof(struct ip6t_nth_info))) {
8166 + printk("nth: matchsize %u != %u\n", matchsize,
8167 + IP6T_ALIGN(sizeof(struct ip6t_nth_info)));
8171 + states[counter].number = info->startat;
8176 +static struct ip6t_match ip6t_nth_reg = {
8180 + ip6t_nth_checkentry,
8184 +static int __init init(void)
8187 + memset(&states, 0, sizeof(states));
8188 + if (ip6t_register_match(&ip6t_nth_reg))
8191 + for(counter = 0; counter < IP6T_NTH_NUM_COUNTERS; counter++)
8193 + spin_lock_init(&(states[counter].lock));
8196 + printk("ip6t_nth match loaded\n");
8200 +static void __exit fini(void)
8202 + ip6t_unregister_match(&ip6t_nth_reg);
8203 + printk("ip6t_nth match unloaded\n");
8208 diff -Nur linux-2.6.6-rc1.org/net/ipv6/netfilter/ip6t_random.c linux-2.6.6-rc1/net/ipv6/netfilter/ip6t_random.c
8209 --- linux-2.6.6-rc1.org/net/ipv6/netfilter/ip6t_random.c 1970-01-01 01:00:00.000000000 +0100
8210 +++ linux-2.6.6-rc1/net/ipv6/netfilter/ip6t_random.c 2004-04-19 10:08:38.000000000 +0200
8213 + This is a module which is used for a "random" match support.
8214 + This file is distributed under the terms of the GNU General Public
8215 + License (GPL). Copies of the GPL can be obtained from:
8216 + ftp://prep.ai.mit.edu/pub/gnu/GPL
8218 + 2001-10-14 Fabrice MARIE <fabrice@netfilter.org> : initial implementation.
8219 + 2003-04-30 Maciej Soltysiak <solt@dns.toxicfilms.tv> : IPv6 Port
8222 +#include <linux/module.h>
8223 +#include <linux/skbuff.h>
8224 +#include <linux/ip.h>
8225 +#include <linux/random.h>
8226 +#include <net/tcp.h>
8227 +#include <linux/spinlock.h>
8228 +#include <linux/netfilter_ipv6/ip6_tables.h>
8229 +#include <linux/netfilter_ipv6/ip6t_random.h>
8231 +MODULE_LICENSE("GPL");
8234 +ip6t_rand_match(const struct sk_buff *pskb,
8235 + const struct net_device *in,
8236 + const struct net_device *out,
8237 + const void *matchinfo,
8240 + u_int16_t datalen,
8243 + /* Parameters from userspace */
8244 + const struct ip6t_rand_info *info = matchinfo;
8245 + u_int8_t random_number;
8247 + /* get 1 random number from the kernel random number generation routine */
8248 + get_random_bytes((void *)(&random_number), 1);
8250 + /* Do we match ? */
8251 + if (random_number <= info->average)
8258 +ip6t_rand_checkentry(const char *tablename,
8259 + const struct ip6t_ip6 *e,
8261 + unsigned int matchsize,
8262 + unsigned int hook_mask)
8264 + /* Parameters from userspace */
8265 + const struct ip6t_rand_info *info = matchinfo;
8267 + if (matchsize != IP6T_ALIGN(sizeof(struct ip6t_rand_info))) {
8268 + printk("ip6t_random: matchsize %u != %u\n", matchsize,
8269 + IP6T_ALIGN(sizeof(struct ip6t_rand_info)));
8273 + /* must be 1 <= average % <= 99 */
8274 + /* 1 x 2.55 = 2 */
8275 + /* 99 x 2.55 = 252 */
8276 + if ((info->average < 2) || (info->average > 252)) {
8277 + printk("ip6t_random: invalid average %u\n", info->average);
8284 +static struct ip6t_match ip6t_rand_reg = {
8288 + ip6t_rand_checkentry,
8292 +static int __init init(void)
8294 + if (ip6t_register_match(&ip6t_rand_reg))
8297 + printk("ip6t_random match loaded\n");
8301 +static void __exit fini(void)
8303 + ip6t_unregister_match(&ip6t_rand_reg);
8304 + printk("ip6t_random match unloaded\n");
8309 diff -Nur linux-2.6.6-rc1.org/net/ipv6/sit.c linux-2.6.6-rc1/net/ipv6/sit.c
8310 --- linux-2.6.6-rc1.org/net/ipv6/sit.c 2004-04-15 03:35:37.000000000 +0200
8311 +++ linux-2.6.6-rc1/net/ipv6/sit.c 2004-04-19 10:08:24.000000000 +0200
8312 @@ -388,13 +388,7 @@
8313 skb->dev = tunnel->dev;
8314 dst_release(skb->dst);
8316 -#ifdef CONFIG_NETFILTER
8317 - nf_conntrack_put(skb->nfct);
8319 -#ifdef CONFIG_NETFILTER_DEBUG
8320 - skb->nf_debug = 0;
8324 ipip6_ecn_decapsulate(iph, skb);
8326 read_unlock(&ipip6_lock);
8327 @@ -580,13 +574,7 @@
8328 if ((iph->ttl = tiph->ttl) == 0)
8329 iph->ttl = iph6->hop_limit;
8331 -#ifdef CONFIG_NETFILTER
8332 - nf_conntrack_put(skb->nfct);
8334 -#ifdef CONFIG_NETFILTER_DEBUG
8335 - skb->nf_debug = 0;
8341 tunnel->recursion--;