]> git.pld-linux.org Git - packages/kernel.git/blob - 2.6.6-rc1-patch-o-matic-ng-base-20040419.patch
- added description of djurban's branch
[packages/kernel.git] / 2.6.6-rc1-patch-o-matic-ng-base-20040419.patch
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
4 @@ -0,0 +1,64 @@
5 +#ifndef _IP_POOL_H
6 +#define _IP_POOL_H
7 +
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.                                           */
13 +/*                                                                        */
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.                          */
18 +/*                                                                        */
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 +/***************************************************************************/
23 +
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!
28 + *
29 + * Comes with its own certificate of authenticity, valid anywhere in the
30 + * Free world!
31 + *
32 + * Rusty, 19.4.2000
33 + */
34 +#define SO_IP_POOL 81
35 +
36 +typedef int ip_pool_t;                 /* pool index */
37 +#define IP_POOL_NONE   ((ip_pool_t)-1)
38 +
39 +struct ip_pool_request {
40 +       int op;
41 +       ip_pool_t index;
42 +       u_int32_t addr;
43 +       u_int32_t addr2;
44 +};
45 +
46 +/* NOTE: I deliberately break the first cut ippool utility. Nobody uses it. */
47 +
48 +#define IP_POOL_BAD001         0x00000010
49 +
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 */
59 +
60 +#ifdef __KERNEL__
61 +
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);
65 +
66 +#endif
67 +
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
72 @@ -0,0 +1,21 @@
73 +/* TTL modification module for IP tables
74 + * (C) 2000 by Harald Welte <laforge@gnumonks.org> */
75 +
76 +#ifndef _IPT_TTL_H
77 +#define _IPT_TTL_H
78 +
79 +enum {
80 +       IPT_TTL_SET = 0,
81 +       IPT_TTL_INC,
82 +       IPT_TTL_DEC
83 +};
84 +
85 +#define IPT_TTL_MAXMODE        IPT_TTL_DEC
86 +
87 +struct ipt_TTL_info {
88 +       u_int8_t        mode;
89 +       u_int8_t        ttl;
90 +};
91 +
92 +
93 +#endif
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
97 @@ -0,0 +1,12 @@
98 +#ifndef _IPT_CONNLIMIT_H
99 +#define _IPT_CONNLIMIT_H
100 +
101 +struct ipt_connlimit_data;
102 +
103 +struct ipt_connlimit_info {
104 +       int limit;
105 +       int inverse;
106 +       u_int32_t mask;
107 +       struct ipt_connlimit_data *data;
108 +};
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
113 @@ -0,0 +1,39 @@
114 +#ifndef _IPT_DSTLIMIT_H
115 +#define _IPT_DSTLIMIT_H
116 +
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. */
121 +
122 +/* details of this structure hidden by the implementation */
123 +struct ipt_dstlimit_htable;
124 +
125 +#define IPT_DSTLIMIT_HASH_DIP  0x0001
126 +#define IPT_DSTLIMIT_HASH_DPT  0x0002
127 +#define IPT_DSTLIMIT_HASH_SIP  0x0004
128 +
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. */
133 +
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? */
139 +};
140 +
141 +struct ipt_dstlimit_info {
142 +       char name [IFNAMSIZ];           /* name */
143 +       struct dstlimit_cfg cfg;
144 +       struct ipt_dstlimit_htable *hinfo;
145 +
146 +       /* Used internally by the kernel */
147 +       union {
148 +               void *ptr;
149 +               struct ipt_dstlimit_info *master;
150 +       } u;
151 +};
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
156 @@ -0,0 +1,21 @@
157 +#ifndef _IPT_FUZZY_H
158 +#define _IPT_FUZZY_H
159 +
160 +#include <linux/param.h>
161 +#include <linux/types.h>
162 +
163 +#define MAXFUZZYRATE 10000000
164 +#define MINFUZZYRATE 3
165 +
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;
175 +};
176 +
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
181 @@ -0,0 +1,21 @@
182 +#ifndef __ipt_ipv4options_h_included__
183 +#define __ipt_ipv4options_h_included__
184 +
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 */
196 +
197 +struct ipt_ipv4options_info {
198 +       u_int16_t options;
199 +};
200 +
201 +
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
206 @@ -0,0 +1,24 @@
207 +#ifndef _IPT_MPORT_H
208 +#define _IPT_MPORT_H
209 +#include <linux/netfilter_ipv4/ip_tables.h>
210 +
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)
214 +
215 +#define IPT_MULTI_PORTS        15
216 +
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[] */
224 +struct ipt_mport
225 +{
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 */
229 +};
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
234 @@ -0,0 +1,19 @@
235 +#ifndef _IPT_NTH_H
236 +#define _IPT_NTH_H
237 +
238 +#include <linux/param.h>
239 +#include <linux/types.h>
240 +
241 +#ifndef IPT_NTH_NUM_COUNTERS
242 +#define IPT_NTH_NUM_COUNTERS 16
243 +#endif
244 +
245 +struct ipt_nth_info {
246 +       u_int8_t every;
247 +       u_int8_t not;
248 +       u_int8_t startat;
249 +       u_int8_t counter;
250 +       u_int8_t packet;
251 +};
252 +
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
257 @@ -0,0 +1,148 @@
258 +/*
259 + * ipt_osf.h
260 + *
261 + * Copyright (c) 2003 Evgeniy Polyakov <johnpol@2ka.mipt.ru>
262 + *
263 + *
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.
268 + *
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.
273 + *
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
277 + */
278 +
279 +#ifndef _IPT_OSF_H
280 +#define _IPT_OSF_H
281 +
282 +#define MAXGENRELEN            32
283 +#define MAXDETLEN              64
284 +
285 +#define IPT_OSF_GENRE          1
286 +#define        IPT_OSF_SMART           2
287 +#define IPT_OSF_LOG            4
288 +#define IPT_OSF_NETLINK                8
289 +
290 +#define IPT_OSF_LOGLEVEL_ALL   0
291 +#define IPT_OSF_LOGLEVEL_FIRST 1
292 +
293 +#include <linux/list.h>
294 +
295 +#ifndef __KERNEL__
296 +#include <netinet/ip.h>
297 +#include <netinet/tcp.h>
298 +
299 +struct list_head
300 +{
301 +       struct list_head *prev, *next;
302 +};
303 +#endif
304 +
305 +struct ipt_osf_info
306 +{
307 +       char                    genre[MAXGENRELEN];
308 +       int                     len;
309 +       unsigned long           flags;
310 +       int                     loglevel;
311 +       int                     invert; /* UNSUPPORTED */
312 +};
313 +
314 +struct osf_wc
315 +{
316 +       char                    wc;
317 +       unsigned long           val;
318 +};
319 +
320 +/* This struct represents IANA options
321 + * http://www.iana.org/assignments/tcp-parameters
322 + */
323 +struct osf_opt
324 +{
325 +       unsigned char           kind;
326 +       unsigned char           length;
327 +       struct osf_wc           wc;
328 +};
329 +
330 +struct osf_finger
331 +{
332 +       struct list_head        flist;
333 +       struct osf_wc           wss;
334 +       unsigned char           ttl;
335 +       unsigned char           df;
336 +       unsigned long           ss;
337 +       unsigned char           genre[MAXGENRELEN];
338 +       unsigned char           version[MAXGENRELEN], subtype[MAXGENRELEN];
339 +       
340 +       /* Not needed, but for consistency with original table from Michal Zalewski */
341 +       unsigned char           details[MAXDETLEN]; 
342 +
343 +       int                     opt_num;
344 +       struct osf_opt          opt[MAX_IPOPTLEN]; /* In case it is all NOP or EOL */
345 +
346 +};
347 +
348 +struct ipt_osf_nlmsg
349 +{
350 +       struct osf_finger       f;
351 +       struct iphdr            ip;
352 +       struct tcphdr           tcp;
353 +};
354 +
355 +#ifdef __KERNEL__
356 +
357 +/* Defines for IANA option kinds */
358 +
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 */
371 +
372 +static struct osf_opt IANA_opts[] = 
373 +{
374 +       {0, 1,},
375 +       {1, 1,},
376 +       {2, 4,},
377 +       {3, 3,},
378 +       {4, 2,},
379 +       {5, 1 ,}, /* SACK length is not defined */
380 +       {6, 6,},
381 +       {7, 6,},
382 +       {8, 10,},
383 +       {9, 2,},
384 +       {10, 3,},
385 +       {11, 1,}, /* CC: Suppose 1 */
386 +       {12, 1,}, /* the same */
387 +       {13, 1,}, /* and here too */
388 +       {14, 3,},
389 +       {15, 1,}, /* TCP Alternate Checksum Data. Length is not defined */
390 +       {16, 1,},
391 +       {17, 1,},
392 +       {18, 3,},
393 +       {19, 18,},
394 +       {20, 1,},
395 +       {21, 1,},
396 +       {22, 1,},
397 +       {23, 1,},
398 +       {24, 1,},
399 +       {25, 1,},
400 +       {26, 1,},
401 +};
402 +
403 +#endif /* __KERNEL__ */
404 +
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
409 @@ -0,0 +1,25 @@
410 +#ifndef _IPT_POOL_H
411 +#define _IPT_POOL_H
412 +
413 +#include <linux/netfilter_ipv4/ip_pool.h>
414 +
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
425 +
426 +/* match info */
427 +struct ipt_pool_info
428 +{
429 +       ip_pool_t src;
430 +       ip_pool_t dst;
431 +       unsigned flags;
432 +};
433 +
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
438 @@ -0,0 +1,40 @@
439 +#ifndef _IPT_PSD_H
440 +#define _IPT_PSD_H
441 +
442 +#include <linux/param.h>
443 +#include <linux/types.h>
444 +
445 +/*
446 + * High port numbers have a lower weight to reduce the frequency of false
447 + * positives, such as from passive mode FTP transfers.
448 + */
449 +#define PORT_WEIGHT_PRIV               3
450 +#define PORT_WEIGHT_HIGH               1
451 +
452 +/*
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.
455 + */
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)
460 +
461 +/*
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.
465 + */
466 +#define LIST_SIZE                      0x100
467 +#define HASH_LOG                       9
468 +#define HASH_SIZE                      (1 << HASH_LOG)
469 +#define HASH_MAX                       0x10
470 +
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;
476 +};
477 +
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
482 @@ -0,0 +1,11 @@
483 +#ifndef _IPT_QUOTA_H
484 +#define _IPT_QUOTA_H
485 +
486 +/* print debug info in both kernel/netfilter module & iptable library */
487 +//#define DEBUG_IPT_QUOTA
488 +
489 +struct ipt_quota_info {
490 +        u_int64_t quota;
491 +};
492 +
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
497 @@ -0,0 +1,11 @@
498 +#ifndef _IPT_RAND_H
499 +#define _IPT_RAND_H
500 +
501 +#include <linux/param.h>
502 +#include <linux/types.h>
503 +
504 +struct ipt_rand_info {
505 +       u_int8_t average;
506 +};
507 +
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
512 @@ -0,0 +1,9 @@
513 +#ifndef _IPT_REALM_H
514 +#define _IPT_REALM_H
515 +
516 +struct ipt_realm_info {
517 +       u_int32_t id;
518 +       u_int32_t mask;
519 +       u_int8_t invert;
520 +};
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
525 @@ -0,0 +1,107 @@
526 +#ifndef _IPT_SCTP_H_
527 +#define _IPT_SCTP_H_
528 +
529 +#define IPT_SCTP_SRC_PORTS             0x01
530 +#define IPT_SCTP_DEST_PORTS            0x02
531 +#define IPT_SCTP_CHUNK_TYPES           0x04
532 +
533 +#define IPT_SCTP_VALID_FLAGS           0x07
534 +
535 +#define ELEMCOUNT(x) (sizeof(x)/sizeof(x[0]))
536 +
537 +
538 +struct ipt_sctp_flag_info {
539 +       u_int8_t chunktype;
540 +       u_int8_t flag;
541 +       u_int8_t flag_mask;
542 +};
543 +
544 +#define IPT_NUM_SCTP_FLAGS     4
545 +
546 +struct ipt_sctp_info {
547 +       u_int16_t dpts[2];  /* Min, Max */
548 +       u_int16_t spts[2];  /* Min, Max */
549 +
550 +       u_int32_t chunkmap[256 / sizeof (u_int32_t)];  /* Bit mask of chunks to be matched according to RFC 2960 */
551 +
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 */
555 +
556 +       u_int32_t chunk_match_type;
557 +       struct ipt_sctp_flag_info flag_info[IPT_NUM_SCTP_FLAGS];
558 +       int flag_count;
559 +
560 +       u_int32_t flags;
561 +       u_int32_t invflags;
562 +};
563 +
564 +#define bytes(type) (sizeof(type) * 8)
565 +
566 +#define SCTP_CHUNKMAP_SET(chunkmap, type)              \
567 +       do {                                            \
568 +               chunkmap[type / bytes(u_int32_t)] |=    \
569 +                       1 << (type % bytes(u_int32_t)); \
570 +       } while (0)
571 +
572 +#define SCTP_CHUNKMAP_CLEAR(chunkmap, type)                    \
573 +       do {                                                    \
574 +               chunkmap[type / bytes(u_int32_t)] &=            \
575 +                       ~(1 << (type % bytes(u_int32_t)));      \
576 +       } while (0)
577 +
578 +#define SCTP_CHUNKMAP_IS_SET(chunkmap, type)                   \
579 +({                                                             \
580 +       (chunkmap[type / bytes (u_int32_t)] &                   \
581 +               (1 << (type % bytes (u_int32_t)))) ? 1: 0;      \
582 +})
583 +
584 +#define SCTP_CHUNKMAP_RESET(chunkmap)                          \
585 +       do {                                                    \
586 +               int i;                                          \
587 +               for (i = 0; i < ELEMCOUNT(chunkmap); i++)       \
588 +                       chunkmap[i] = 0;                        \
589 +       } while (0)
590 +
591 +#define SCTP_CHUNKMAP_SET_ALL(chunkmap)                        \
592 +       do {                                                    \
593 +               int i;                                          \
594 +               for (i = 0; i < ELEMCOUNT(chunkmap); i++)       \
595 +                       chunkmap[i] = ~0;                       \
596 +       } while (0)
597 +
598 +#define SCTP_CHUNKMAP_COPY(destmap, srcmap)                    \
599 +       do {                                                    \
600 +               int i;                                          \
601 +               for (i = 0; i < ELEMCOUNT(chunkmap); i++)       \
602 +                       destmap[i] = srcmap[i];                 \
603 +       } while (0)
604 +
605 +#define SCTP_CHUNKMAP_IS_CLEAR(chunkmap)               \
606 +({                                                     \
607 +       int i;                                          \
608 +       int flag = 1;                                   \
609 +       for (i = 0; i < ELEMCOUNT(chunkmap); i++) {     \
610 +               if (chunkmap[i]) {                      \
611 +                       flag = 0;                       \
612 +                       break;                          \
613 +               }                                       \
614 +       }                                               \
615 +        flag;                                          \
616 +})
617 +
618 +#define SCTP_CHUNKMAP_IS_ALL_SET(chunkmap)             \
619 +({                                                     \
620 +       int i;                                          \
621 +       int flag = 1;                                   \
622 +       for (i = 0; i < ELEMCOUNT(chunkmap); i++) {     \
623 +               if (chunkmap[i] != ~0) {                \
624 +                       flag = 0;                       \
625 +                               break;                  \
626 +               }                                       \
627 +       }                                               \
628 +        flag;                                          \
629 +})
630 +
631 +#endif /* _IPT_SCTP_H_ */
632 +
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
636 @@ -0,0 +1,13 @@
637 +#ifndef __ipt_time_h_included__
638 +#define __ipt_time_h_included__
639 +
640 +
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. */
646 +};
647 +
648 +
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
653 @@ -0,0 +1,40 @@
654 +#ifndef _IPT_U32_H
655 +#define _IPT_U32_H
656 +#include <linux/netfilter_ipv4/ip_tables.h>
657 +
658 +enum ipt_u32_ops
659 +{
660 +       IPT_U32_AND,
661 +       IPT_U32_LEFTSH,
662 +       IPT_U32_RIGHTSH,
663 +       IPT_U32_AT
664 +};
665 +
666 +struct ipt_u32_location_element
667 +{
668 +       u_int32_t number;
669 +       u_int8_t nextop;
670 +};
671 +struct ipt_u32_value_element
672 +{
673 +       u_int32_t min;
674 +       u_int32_t max;
675 +};
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
679 +struct ipt_u32_test
680 +{
681 +       u_int8_t nnums;
682 +       struct ipt_u32_location_element location[U32MAXSIZE+1];
683 +       u_int8_t nvalues;
684 +       struct ipt_u32_value_element value[U32MAXSIZE+1];
685 +};
686 +
687 +struct ipt_u32
688 +{
689 +       u_int8_t ntests;
690 +       struct ipt_u32_test tests[U32MAXSIZE+1];
691 +};
692 +
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
697 @@ -0,0 +1,22 @@
698 +/* Hop Limit modification module for ip6tables
699 + * Maciej Soltysiak <solt@dns.toxicfilms.tv>
700 + * Based on HW's TTL module */
701 +
702 +#ifndef _IP6T_HL_H
703 +#define _IP6T_HL_H
704 +
705 +enum {
706 +       IP6T_HL_SET = 0,
707 +       IP6T_HL_INC,
708 +       IP6T_HL_DEC
709 +};
710 +
711 +#define IP6T_HL_MAXMODE        IP6T_HL_DEC
712 +
713 +struct ip6t_HL_info {
714 +       u_int8_t        mode;
715 +       u_int8_t        hop_limit;
716 +};
717 +
718 +
719 +#endif
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
723 @@ -2,15 +2,17 @@
724  #define _IP6T_REJECT_H
725  
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,
738 +       IP6T_TCP_RESET
739  };
740  
741  struct ip6t_reject_info {
742         enum ip6t_reject_with with;      /* reject type */
743  };
744  
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
750 @@ -0,0 +1,21 @@
751 +#ifndef _IP6T_FUZZY_H
752 +#define _IP6T_FUZZY_H
753 +
754 +#include <linux/param.h>
755 +#include <linux/types.h>
756 +
757 +#define MAXFUZZYRATE 10000000
758 +#define MINFUZZYRATE 3
759 +
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;
769 +};
770 +
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
775 @@ -0,0 +1,19 @@
776 +#ifndef _IP6T_NTH_H
777 +#define _IP6T_NTH_H
778 +
779 +#include <linux/param.h>
780 +#include <linux/types.h>
781 +
782 +#ifndef IP6T_NTH_NUM_COUNTERS
783 +#define IP6T_NTH_NUM_COUNTERS 16
784 +#endif
785 +
786 +struct ip6t_nth_info {
787 +       u_int8_t every;
788 +       u_int8_t not;
789 +       u_int8_t startat;
790 +       u_int8_t counter;
791 +       u_int8_t packet;
792 +};
793 +
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
798 @@ -0,0 +1,11 @@
799 +#ifndef _IP6T_RAND_H
800 +#define _IP6T_RAND_H
801 +
802 +#include <linux/param.h>
803 +#include <linux/types.h>
804 +
805 +struct ip6t_rand_info {
806 +       u_int8_t average;
807 +};
808 +
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 @@
814         if (nfct)
815                 atomic_inc(&nfct->master->use);
816  }
817 +static inline void nf_reset(struct sk_buff *skb)
818 +{
819 +       nf_conntrack_put(skb->nfct);
820 +       skb->nfct = NULL;
821 +#ifdef CONFIG_NETFILTER_DEBUG
822 +       skb->nf_debug = 0;
823 +#endif
824 +}
825  
826  #ifdef CONFIG_BRIDGE_NETFILTER
827  static inline void nf_bridge_put(struct nf_bridge_info *nf_bridge)
828 @@ -1213,9 +1221,10 @@
829         if (nf_bridge)
830                 atomic_inc(&nf_bridge->use);
831  }
832 -#endif
833 -
834 -#endif
835 +#endif /* CONFIG_BRIDGE_NETFILTER */
836 +#else /* CONFIG_NETFILTER */
837 +static inline void nf_reset(struct sk_buff *skb) {}
838 +#endif /* CONFIG_NETFILTER */
839  
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
845 @@ -643,13 +643,7 @@
846                 skb->dev = tunnel->dev;
847                 dst_release(skb->dst);
848                 skb->dst = NULL;
849 -#ifdef CONFIG_NETFILTER
850 -               nf_conntrack_put(skb->nfct);
851 -               skb->nfct = NULL;
852 -#ifdef CONFIG_NETFILTER_DEBUG
853 -               skb->nf_debug = 0;
854 -#endif
855 -#endif
856 +               nf_reset(skb);
857                 ipgre_ecn_decapsulate(iph, skb);
858                 netif_rx(skb);
859                 read_unlock(&ipgre_lock);
860 @@ -877,13 +871,7 @@
861                 }
862         }
863  
864 -#ifdef CONFIG_NETFILTER
865 -       nf_conntrack_put(skb->nfct);
866 -       skb->nfct = NULL;
867 -#ifdef CONFIG_NETFILTER_DEBUG
868 -       skb->nf_debug = 0;
869 -#endif
870 -#endif
871 +       nf_reset(skb);
872  
873         IPTUNNEL_XMIT();
874         tunnel->recursion--;
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 @@
879  
880  #ifdef CONFIG_NETFILTER_DEBUG
881         nf_debug_ip_local_deliver(skb);
882 -       skb->nf_debug = 0;
883  #endif /*CONFIG_NETFILTER_DEBUG*/
884  
885         __skb_pull(skb, ihl);
886  
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);
891 -       skb->nfct = NULL;
892 -#endif /*CONFIG_NETFILTER*/
893 +       nf_reset(skb);
894  
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
900 @@ -496,13 +496,7 @@
901                 skb->dev = tunnel->dev;
902                 dst_release(skb->dst);
903                 skb->dst = NULL;
904 -#ifdef CONFIG_NETFILTER
905 -               nf_conntrack_put(skb->nfct);
906 -               skb->nfct = NULL;
907 -#ifdef CONFIG_NETFILTER_DEBUG
908 -               skb->nf_debug = 0;
909 -#endif
910 -#endif
911 +               nf_reset(skb);
912                 ipip_ecn_decapsulate(iph, skb);
913                 netif_rx(skb);
914                 read_unlock(&ipip_lock);
915 @@ -647,13 +641,7 @@
916         if ((iph->ttl = tiph->ttl) == 0)
917                 iph->ttl        =       old_iph->ttl;
918  
919 -#ifdef CONFIG_NETFILTER
920 -       nf_conntrack_put(skb->nfct);
921 -       skb->nfct = NULL;
922 -#ifdef CONFIG_NETFILTER_DEBUG
923 -       skb->nf_debug = 0;
924 -#endif
925 -#endif
926 +       nf_reset(skb);
927  
928         IPTUNNEL_XMIT();
929         tunnel->recursion--;
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
933 @@ -603,5 +603,94 @@
934           <file:Documentation/modules.txt>.  If unsure, say `N'.
935           help
936  
937 +config IP_NF_TARGET_IPV4OPTSSTRIP
938 +       tristate  'IPV4OPTSSTRIP target support'
939 +       depends on IP_NF_MANGLE
940 +         help
941 +
942 +config IP_NF_TARGET_TTL
943 +       tristate  'TTL target support'
944 +       depends on IP_NF_MANGLE
945 +         help
946 +
947 +config IP_NF_MATCH_CONNLIMIT
948 +       tristate  'Connections/IP limit match support'
949 +       depends on IP_NF_IPTABLES
950 +         help
951 +
952 +config IP_NF_MATCH_DSTLIMIT
953 +       tristate  'dstlimit match support'
954 +       depends on IP_NF_IPTABLES
955 +         help
956 +
957 +config IP_NF_MATCH_FUZZY
958 +       tristate  'fuzzy match support'
959 +       depends on IP_NF_IPTABLES
960 +         help
961 +
962 +config IP_NF_MATCH_IPV4OPTIONS
963 +       tristate  'IPV4OPTIONS match support'
964 +       depends on IP_NF_IPTABLES
965 +         help
966 +
967 +config IP_NF_MATCH_MPORT
968 +       tristate  'Multiple port with ranges match support'
969 +       depends on IP_NF_IPTABLES
970 +         help
971 +
972 +config IP_NF_MATCH_NTH
973 +       tristate  'Nth match support'
974 +       depends on IP_NF_IPTABLES
975 +         help
976 +
977 +config IP_NF_MATCH_OSF
978 +       tristate  'OSF match support'
979 +       depends on IP_NF_IPTABLES
980 +         help
981 +
982 +config IP_POOL_STATISTICS
983 +       bool  'enable statistics on pool usage'
984 +       depends on IP_NF_POOL!=n
985 +
986 +config IP_NF_POOL
987 +       tristate  'IP address pool support'
988 +       depends on IP_NF_IPTABLES
989 +         help
990 +
991 +config IP_NF_MATCH_PSD
992 +       tristate  'psd match support'
993 +       depends on IP_NF_IPTABLES
994 +         help
995 +
996 +config IP_NF_MATCH_QUOTA
997 +       tristate  'quota match support'
998 +       depends on IP_NF_IPTABLES
999 +         help
1000 +
1001 +config IP_NF_MATCH_RANDOM
1002 +       tristate  'random match support'
1003 +       depends on IP_NF_IPTABLES
1004 +         help
1005 +
1006 +config IP_NF_MATCH_REALM
1007 +       tristate  'realm match support'
1008 +       depends on IP_NF_IPTABLES && NET_CLS_ROUTE
1009 +         help
1010 +
1011 +config IP_NF_MATCH_SCTP
1012 +       tristate  'SCTP protocol match support'
1013 +       depends on IP_NF_IPTABLES
1014 +         help
1015 +
1016 +config IP_NF_MATCH_TIME
1017 +       tristate  'TIME match support'
1018 +       depends on IP_NF_IPTABLES
1019 +         help
1020 +
1021 +config IP_NF_MATCH_U32
1022 +       tristate  'U32 match support'
1023 +       depends on IP_NF_IPTABLES
1024 +         help
1025 +
1026  endmenu
1027  
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
1031 @@ -43,15 +43,39 @@
1032  # matches
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
1042  
1043  obj-$(CONFIG_IP_NF_MATCH_PKTTYPE) += ipt_pkttype.o
1044  obj-$(CONFIG_IP_NF_MATCH_MULTIPORT) += ipt_multiport.o
1045 +
1046 +obj-$(CONFIG_IP_NF_MATCH_MPORT) += ipt_mport.o
1047 +
1048  obj-$(CONFIG_IP_NF_MATCH_OWNER) += ipt_owner.o
1049  obj-$(CONFIG_IP_NF_MATCH_TOS) += ipt_tos.o
1050  
1051 +obj-$(CONFIG_IP_NF_MATCH_TIME) += ipt_time.o
1052 +
1053 +
1054 +obj-$(CONFIG_IP_NF_MATCH_RANDOM) += ipt_random.o
1055 +
1056 +obj-$(CONFIG_IP_NF_MATCH_PSD) += ipt_psd.o
1057 +
1058 +obj-$(CONFIG_IP_NF_MATCH_OSF) += ipt_osf.o
1059 +
1060 +
1061 +obj-$(CONFIG_IP_NF_MATCH_NTH) += ipt_nth.o
1062 +
1063 +obj-$(CONFIG_IP_NF_MATCH_IPV4OPTIONS) += ipt_ipv4options.o
1064 +
1065 +
1066 +obj-$(CONFIG_IP_NF_MATCH_FUZZY) += ipt_fuzzy.o
1067 +
1068  obj-$(CONFIG_IP_NF_MATCH_RECENT) += ipt_recent.o
1069  
1070  obj-$(CONFIG_IP_NF_MATCH_ECN) += ipt_ecn.o
1071 @@ -60,10 +84,15 @@
1072  
1073  obj-$(CONFIG_IP_NF_MATCH_LENGTH) += ipt_length.o
1074  
1075 +obj-$(CONFIG_IP_NF_MATCH_U32) += ipt_u32.o
1076 +
1077 +
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
1084  
1085  obj-$(CONFIG_IP_NF_MATCH_PHYSDEV) += ipt_physdev.o
1086  
1087 @@ -80,6 +109,8 @@
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);
1102  
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))
1109 -               expected = NULL;
1110 -
1111 -       /* Look up the conntrack helper for master connections only */
1112 -       if (!expected)
1113 -               conntrack->helper = ip_ct_find_helper(&repl_tuple);
1114 -
1115 -       /* If the expectation is dying, then this is a loser. */
1116 -       if (expected
1117 -           && expected->expectant->helper->timeout
1118 -           && ! del_timer(&expected->timeout))
1119 -               expected = NULL;
1120 -
1121         if (expected) {
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]);
1132 -       }
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)) {
1140 +                       
1141 +                       conntrack->helper = ip_ct_find_helper(&repl_tuple);
1142 +                       goto end;
1143 +               }
1144 +
1145 +               /* Expectation is dying... */
1146 +               if (expected->expectant->helper->timeout
1147 +                   && ! del_timer(&expected->timeout)) {
1148 +                       goto end;       
1149 +               }
1150 +
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]);
1161 +
1162 +               /* this is a braindead... --pablo */
1163 +               atomic_inc(&ip_conntrack_count);
1164 +               WRITE_UNLOCK(&ip_conntrack_lock);
1165 +
1166 +               if (expected->expectfn)
1167 +                       expected->expectfn(conntrack);
1168 +
1169 +               goto ret;
1170 +        } else 
1171 +                conntrack->helper = ip_ct_find_helper(&repl_tuple);
1172 +
1173 +end:   atomic_inc(&ip_conntrack_count);
1174         WRITE_UNLOCK(&ip_conntrack_lock);
1175  
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];
1180  }
1181  
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
1186 @@ -0,0 +1,1467 @@
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
1189 +   extension. */
1190 +
1191 +/* (C) 1999-2001 Paul `Rusty' Russell  
1192 + * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org>
1193 + *
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.
1197 + *
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
1204 + * */
1205 +
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>
1224 +
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)
1229 +
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>
1235 +
1236 +#define IP_CONNTRACK_VERSION   "2.1"
1237 +
1238 +#if 0
1239 +#define DEBUGP printk
1240 +#else
1241 +#define DEBUGP(format, args...)
1242 +#endif
1243 +
1244 +DECLARE_RWLOCK(ip_conntrack_lock);
1245 +DECLARE_RWLOCK(ip_conntrack_expect_tuple_lock);
1246 +
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;
1257 +
1258 +extern struct ip_conntrack_protocol ip_conntrack_generic_protocol;
1259 +
1260 +static inline int proto_cmpfn(const struct ip_conntrack_protocol *curr,
1261 +                             u_int8_t protocol)
1262 +{
1263 +       return protocol == curr->proto;
1264 +}
1265 +
1266 +struct ip_conntrack_protocol *__ip_ct_find_proto(u_int8_t protocol)
1267 +{
1268 +       struct ip_conntrack_protocol *p;
1269 +
1270 +       MUST_BE_READ_LOCKED(&ip_conntrack_lock);
1271 +       p = LIST_FIND(&protocol_list, proto_cmpfn,
1272 +                     struct ip_conntrack_protocol *, protocol);
1273 +       if (!p)
1274 +               p = &ip_conntrack_generic_protocol;
1275 +
1276 +       return p;
1277 +}
1278 +
1279 +struct ip_conntrack_protocol *ip_ct_find_proto(u_int8_t protocol)
1280 +{
1281 +       struct ip_conntrack_protocol *p;
1282 +
1283 +       READ_LOCK(&ip_conntrack_lock);
1284 +       p = __ip_ct_find_proto(protocol);
1285 +       READ_UNLOCK(&ip_conntrack_lock);
1286 +       return p;
1287 +}
1288 +
1289 +inline void 
1290 +ip_conntrack_put(struct ip_conntrack *ct)
1291 +{
1292 +       IP_NF_ASSERT(ct);
1293 +       IP_NF_ASSERT(ct->infos[0].master);
1294 +       /* nf_conntrack_put wants to go via an info struct, so feed it
1295 +           one at random. */
1296 +       nf_conntrack_put(&ct->infos[0]);
1297 +}
1298 +
1299 +static int ip_conntrack_hash_rnd_initted;
1300 +static unsigned int ip_conntrack_hash_rnd;
1301 +
1302 +static u_int32_t
1303 +hash_conntrack(const struct ip_conntrack_tuple *tuple)
1304 +{
1305 +#if 0
1306 +       dump_tuple(tuple);
1307 +#endif
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);
1312 +}
1313 +
1314 +int
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)
1320 +{
1321 +       /* Never happen */
1322 +       if (iph->frag_off & htons(IP_OFFSET)) {
1323 +               printk("ip_conntrack_core: Frag of proto %u.\n",
1324 +                      iph->protocol);
1325 +               return 0;
1326 +       }
1327 +
1328 +       tuple->src.ip = iph->saddr;
1329 +       tuple->dst.ip = iph->daddr;
1330 +       tuple->dst.protonum = iph->protocol;
1331 +
1332 +       return protocol->pkt_to_tuple(skb, dataoff, tuple);
1333 +}
1334 +
1335 +static int
1336 +invert_tuple(struct ip_conntrack_tuple *inverse,
1337 +            const struct ip_conntrack_tuple *orig,
1338 +            const struct ip_conntrack_protocol *protocol)
1339 +{
1340 +       inverse->src.ip = orig->dst.ip;
1341 +       inverse->dst.ip = orig->src.ip;
1342 +       inverse->dst.protonum = orig->dst.protonum;
1343 +
1344 +       return protocol->invert_tuple(inverse, orig);
1345 +}
1346 +
1347 +
1348 +/* ip_conntrack_expect helper functions */
1349 +
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)
1353 +{
1354 +       MUST_BE_READ_LOCKED(&ip_conntrack_expect_tuple_lock);
1355 +       return ip_ct_tuple_mask_cmp(tuple, &i->tuple, &i->mask);
1356 +}
1357 +
1358 +static void
1359 +destroy_expect(struct ip_conntrack_expect *exp)
1360 +{
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));
1364 +
1365 +       kfree(exp);
1366 +}
1367 +
1368 +
1369 +inline void ip_conntrack_expect_put(struct ip_conntrack_expect *exp)
1370 +{
1371 +       IP_NF_ASSERT(exp);
1372 +
1373 +       if (atomic_dec_and_test(&exp->use)) {
1374 +               /* usage count dropped to zero */
1375 +               destroy_expect(exp);
1376 +       }
1377 +}
1378 +
1379 +static inline struct ip_conntrack_expect *
1380 +__ip_ct_expect_find(const struct ip_conntrack_tuple *tuple)
1381 +{
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);
1386 +}
1387 +
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)
1391 +{
1392 +       struct ip_conntrack_expect *exp;
1393 +
1394 +       READ_LOCK(&ip_conntrack_lock);
1395 +       READ_LOCK(&ip_conntrack_expect_tuple_lock);
1396 +       exp = __ip_ct_expect_find(tuple);
1397 +       if (exp)
1398 +               atomic_inc(&exp->use);
1399 +       READ_UNLOCK(&ip_conntrack_expect_tuple_lock);
1400 +       READ_UNLOCK(&ip_conntrack_lock);
1401 +
1402 +       return exp;
1403 +}
1404 +
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)
1408 +{
1409 +       DEBUGP("unexpect_related(%p)\n", expect);
1410 +       MUST_BE_WRITE_LOCKED(&ip_conntrack_lock);
1411 +
1412 +       /* we're not allowed to unexpect a confirmed expectation! */
1413 +       IP_NF_ASSERT(!expect->sibling);
1414 +
1415 +       /* delete from global and local lists */
1416 +       list_del(&expect->list);
1417 +       list_del(&expect->expected_list);
1418 +
1419 +       /* decrement expect-count of master conntrack */
1420 +       if (expect->expectant)
1421 +               expect->expectant->expecting--;
1422 +
1423 +       ip_conntrack_expect_put(expect);
1424 +}
1425 +
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)
1430 +{
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))
1438 +               return;
1439 +
1440 +       __unexpect_related(expect);
1441 +}
1442 +
1443 +/* delete all unconfirmed expectations for this conntrack */
1444 +static void remove_expectations(struct ip_conntrack *ct, int drop_refcount)
1445 +{
1446 +       struct list_head *exp_entry, *next;
1447 +       struct ip_conntrack_expect *exp;
1448 +
1449 +       DEBUGP("remove_expectations(%p)\n", ct);
1450 +
1451 +       list_for_each_safe(exp_entry, next, &ct->sibling_list) {
1452 +               exp = list_entry(exp_entry, struct ip_conntrack_expect,
1453 +                                expected_list);
1454 +
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;
1463 +                       }
1464 +                       continue;
1465 +               }
1466 +
1467 +               IP_NF_ASSERT(list_inlist(&ip_conntrack_expect_list, exp));
1468 +               IP_NF_ASSERT(exp->expectant == ct);
1469 +
1470 +               /* delete expectation from global and private lists */
1471 +               unexpect_related(exp);
1472 +       }
1473 +}
1474 +
1475 +static void
1476 +clean_from_lists(struct ip_conntrack *ct)
1477 +{
1478 +       unsigned int ho, hr;
1479 +       
1480 +       DEBUGP("clean_from_lists(%p)\n", ct);
1481 +       MUST_BE_WRITE_LOCKED(&ip_conntrack_lock);
1482 +
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]);
1487 +
1488 +       /* Destroy all un-established, pending expectations */
1489 +       remove_expectations(ct, 1);
1490 +}
1491 +
1492 +static void
1493 +destroy_conntrack(struct nf_conntrack *nfct)
1494 +{
1495 +       struct ip_conntrack *ct = (struct ip_conntrack *)nfct, *master = NULL;
1496 +       struct ip_conntrack_protocol *proto;
1497 +
1498 +       DEBUGP("destroy_conntrack(%p)\n", ct);
1499 +       IP_NF_ASSERT(atomic_read(&nfct->use) == 0);
1500 +       IP_NF_ASSERT(!timer_pending(&ct->timeout));
1501 +
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);
1508 +
1509 +       if (ip_conntrack_destroyed)
1510 +               ip_conntrack_destroyed(ct);
1511 +
1512 +       WRITE_LOCK(&ip_conntrack_lock);
1513 +       /* Delete us from our own list to prevent corruption later */
1514 +       list_del(&ct->sibling_list);
1515 +
1516 +       /* Delete our master expectation */
1517 +       if (ct->master) {
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;
1523 +               }
1524 +               kfree(ct->master);
1525 +       }
1526 +       WRITE_UNLOCK(&ip_conntrack_lock);
1527 +
1528 +       if (master)
1529 +               ip_conntrack_put(master);
1530 +
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);
1534 +}
1535 +
1536 +static void death_by_timeout(unsigned long ul_conntrack)
1537 +{
1538 +       struct ip_conntrack *ct = (void *)ul_conntrack;
1539 +
1540 +       WRITE_LOCK(&ip_conntrack_lock);
1541 +       clean_from_lists(ct);
1542 +       WRITE_UNLOCK(&ip_conntrack_lock);
1543 +       ip_conntrack_put(ct);
1544 +}
1545 +
1546 +static inline int
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)
1550 +{
1551 +       MUST_BE_READ_LOCKED(&ip_conntrack_lock);
1552 +       return i->ctrack != ignored_conntrack
1553 +               && ip_ct_tuple_equal(tuple, &i->tuple);
1554 +}
1555 +
1556 +static struct ip_conntrack_tuple_hash *
1557 +__ip_conntrack_find(const struct ip_conntrack_tuple *tuple,
1558 +                   const struct ip_conntrack *ignored_conntrack)
1559 +{
1560 +       struct ip_conntrack_tuple_hash *h;
1561 +       unsigned int hash = hash_conntrack(tuple);
1562 +
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);
1568 +       return h;
1569 +}
1570 +
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)
1575 +{
1576 +       struct ip_conntrack_tuple_hash *h;
1577 +
1578 +       READ_LOCK(&ip_conntrack_lock);
1579 +       h = __ip_conntrack_find(tuple, ignored_conntrack);
1580 +       if (h)
1581 +               atomic_inc(&h->ctrack->ct_general.use);
1582 +       READ_UNLOCK(&ip_conntrack_lock);
1583 +
1584 +       return h;
1585 +}
1586 +
1587 +static inline struct ip_conntrack *
1588 +__ip_conntrack_get(struct nf_ct_info *nfct, enum ip_conntrack_info *ctinfo)
1589 +{
1590 +       struct ip_conntrack *ct
1591 +               = (struct ip_conntrack *)nfct->master;
1592 +
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);
1596 +       return ct;
1597 +}
1598 +
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)
1602 +{
1603 +       if (skb->nfct) 
1604 +               return __ip_conntrack_get(skb->nfct, ctinfo);
1605 +       return NULL;
1606 +}
1607 +
1608 +/* Confirm a connection given skb->nfct; places it in hash table */
1609 +int
1610 +__ip_conntrack_confirm(struct nf_ct_info *nfct)
1611 +{
1612 +       unsigned int hash, repl_hash;
1613 +       struct ip_conntrack *ct;
1614 +       enum ip_conntrack_info ctinfo;
1615 +
1616 +       ct = __ip_conntrack_get(nfct, &ctinfo);
1617 +
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)
1623 +               return NF_ACCEPT;
1624 +
1625 +       hash = hash_conntrack(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
1626 +       repl_hash = hash_conntrack(&ct->tuplehash[IP_CT_DIR_REPLY].tuple);
1627 +
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); */
1632 +
1633 +       /* No external references means noone else could have
1634 +           confirmed us. */
1635 +       IP_NF_ASSERT(!is_confirmed(ct));
1636 +       DEBUGP("Confirming conntrack %p\n", ct);
1637 +
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);
1662 +               return NF_ACCEPT;
1663 +       }
1664 +
1665 +       WRITE_UNLOCK(&ip_conntrack_lock);
1666 +       return NF_DROP;
1667 +}
1668 +
1669 +/* Returns true if a connection correspondings to the tuple (required
1670 +   for NAT). */
1671 +int
1672 +ip_conntrack_tuple_taken(const struct ip_conntrack_tuple *tuple,
1673 +                        const struct ip_conntrack *ignored_conntrack)
1674 +{
1675 +       struct ip_conntrack_tuple_hash *h;
1676 +
1677 +       READ_LOCK(&ip_conntrack_lock);
1678 +       h = __ip_conntrack_find(tuple, ignored_conntrack);
1679 +       READ_UNLOCK(&ip_conntrack_lock);
1680 +
1681 +       return h != NULL;
1682 +}
1683 +
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)
1689 +{
1690 +       struct ip_conntrack_tuple innertuple, origtuple;
1691 +       struct {
1692 +               struct icmphdr icmp;
1693 +               struct iphdr ip;
1694 +       } inside;
1695 +       struct ip_conntrack_protocol *innerproto;
1696 +       struct ip_conntrack_tuple_hash *h;
1697 +       int dataoff;
1698 +
1699 +       IP_NF_ASSERT(skb->nfct == NULL);
1700 +
1701 +       /* Not enough header? */
1702 +       if (skb_copy_bits(skb, skb->nh.iph->ihl*4, &inside, sizeof(inside))!=0)
1703 +               return NULL;
1704 +
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)
1710 +               return NULL;
1711 +
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);
1716 +               return NULL;
1717 +       }
1718 +
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);
1724 +               return NULL;
1725 +       }
1726 +
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");
1731 +               return NULL;
1732 +       }
1733 +
1734 +       *ctinfo = IP_CT_RELATED;
1735 +
1736 +       h = ip_conntrack_find_get(&innertuple, NULL);
1737 +       if (!h) {
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);
1743 +
1744 +               if (!h) {
1745 +                       DEBUGP("icmp_error_track: no match\n");
1746 +                       return NULL;
1747 +               }
1748 +               /* Reverse direction from that found */
1749 +               if (DIRECTION(h) != IP_CT_DIR_REPLY)
1750 +                       *ctinfo += IP_CT_IS_REPLY;
1751 +       } else {
1752 +               if (DIRECTION(h) == IP_CT_DIR_REPLY)
1753 +                       *ctinfo += IP_CT_IS_REPLY;
1754 +       }
1755 +
1756 +       /* Update skb to refer to this connection */
1757 +       skb->nfct = &h->ctrack->infos[*ctinfo];
1758 +       return h->ctrack;
1759 +}
1760 +
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)
1764 +{
1765 +       return !(test_bit(IPS_ASSURED_BIT, &i->ctrack->status));
1766 +}
1767 +
1768 +static int early_drop(struct list_head *chain)
1769 +{
1770 +       /* Traverse backwards: gives us oldest, which is roughly LRU */
1771 +       struct ip_conntrack_tuple_hash *h;
1772 +       int dropped = 0;
1773 +
1774 +       READ_LOCK(&ip_conntrack_lock);
1775 +       h = LIST_FIND_B(chain, unreplied, struct ip_conntrack_tuple_hash *);
1776 +       if (h)
1777 +               atomic_inc(&h->ctrack->ct_general.use);
1778 +       READ_UNLOCK(&ip_conntrack_lock);
1779 +
1780 +       if (!h)
1781 +               return dropped;
1782 +
1783 +       if (del_timer(&h->ctrack->timeout)) {
1784 +               death_by_timeout((unsigned long)h->ctrack);
1785 +               dropped = 1;
1786 +       }
1787 +       ip_conntrack_put(h->ctrack);
1788 +       return dropped;
1789 +}
1790 +
1791 +static inline int helper_cmp(const struct ip_conntrack_helper *i,
1792 +                            const struct ip_conntrack_tuple *rtuple)
1793 +{
1794 +       return ip_ct_tuple_mask_cmp(rtuple, &i->tuple, &i->mask);
1795 +}
1796 +
1797 +struct ip_conntrack_helper *ip_ct_find_helper(const struct ip_conntrack_tuple *tuple)
1798 +{
1799 +       return LIST_FIND(&helpers, helper_cmp,
1800 +                        struct ip_conntrack_helper *,
1801 +                        tuple);
1802 +}
1803 +
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)
1810 +{
1811 +       struct ip_conntrack *conntrack;
1812 +       struct ip_conntrack_tuple repl_tuple;
1813 +       size_t hash;
1814 +       struct ip_conntrack_expect *expected;
1815 +       int i;
1816 +       static unsigned int drop_next;
1817 +
1818 +       if (!ip_conntrack_hash_rnd_initted) {
1819 +               get_random_bytes(&ip_conntrack_hash_rnd, 4);
1820 +               ip_conntrack_hash_rnd_initted = 1;
1821 +       }
1822 +
1823 +       hash = hash_conntrack(tuple);
1824 +
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;
1831 +
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"
1837 +                                      " packet.\n");
1838 +                       return ERR_PTR(-ENOMEM);
1839 +               }
1840 +       }
1841 +
1842 +       if (!invert_tuple(&repl_tuple, tuple, protocol)) {
1843 +               DEBUGP("Can't invert tuple.\n");
1844 +               return NULL;
1845 +       }
1846 +
1847 +       conntrack = kmem_cache_alloc(ip_conntrack_cachep, GFP_ATOMIC);
1848 +       if (!conntrack) {
1849 +               DEBUGP("Can't allocate conntrack.\n");
1850 +               return ERR_PTR(-ENOMEM);
1851 +       }
1852 +
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;
1862 +
1863 +       if (!protocol->new(conntrack, skb)) {
1864 +               kmem_cache_free(ip_conntrack_cachep, conntrack);
1865 +               return NULL;
1866 +       }
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;
1871 +
1872 +       INIT_LIST_HEAD(&conntrack->sibling_list);
1873 +
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);
1880 +
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))
1887 +               expected = NULL;
1888 +
1889 +       /* Look up the conntrack helper for master connections only */
1890 +       if (!expected)
1891 +               conntrack->helper = ip_ct_find_helper(&repl_tuple);
1892 +
1893 +       /* If the expectation is dying, then this is a loser. */
1894 +       if (expected
1895 +           && expected->expectant->helper->timeout
1896 +           && ! del_timer(&expected->timeout))
1897 +               expected = NULL;
1898 +
1899 +       if (expected) {
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]);
1910 +       }
1911 +       atomic_inc(&ip_conntrack_count);
1912 +       WRITE_UNLOCK(&ip_conntrack_lock);
1913 +
1914 +       if (expected && expected->expectfn)
1915 +               expected->expectfn(conntrack);
1916 +       return &conntrack->tuplehash[IP_CT_DIR_ORIGINAL];
1917 +}
1918 +
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,
1923 +                 int *set_reply,
1924 +                 unsigned int hooknum,
1925 +                 enum ip_conntrack_info *ctinfo)
1926 +{
1927 +       struct ip_conntrack_tuple tuple;
1928 +       struct ip_conntrack_tuple_hash *h;
1929 +
1930 +       IP_NF_ASSERT((skb->nh.iph->frag_off & htons(IP_OFFSET)) == 0);
1931 +
1932 +       if (!get_tuple(skb->nh.iph, skb, skb->nh.iph->ihl*4, &tuple, proto))
1933 +               return NULL;
1934 +
1935 +       /* look for tuple match */
1936 +       h = ip_conntrack_find_get(&tuple, NULL);
1937 +       if (!h) {
1938 +               h = init_conntrack(&tuple, proto, skb);
1939 +               if (!h)
1940 +                       return NULL;
1941 +               if (IS_ERR(h))
1942 +                       return (void *)h;
1943 +       }
1944 +
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 */
1949 +               *set_reply = 1;
1950 +       } else {
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",
1954 +                              h->ctrack);
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",
1958 +                              h->ctrack);
1959 +                       *ctinfo = IP_CT_RELATED;
1960 +               } else {
1961 +                       DEBUGP("ip_conntrack_in: new packet for %p\n",
1962 +                              h->ctrack);
1963 +                       *ctinfo = IP_CT_NEW;
1964 +               }
1965 +               *set_reply = 0;
1966 +       }
1967 +       skb->nfct = &h->ctrack->infos[*ctinfo];
1968 +       return h->ctrack;
1969 +}
1970 +
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 *))
1977 +{
1978 +       struct ip_conntrack *ct;
1979 +       enum ip_conntrack_info ctinfo;
1980 +       struct ip_conntrack_protocol *proto;
1981 +       int set_reply;
1982 +       int ret;
1983 +
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);
1989 +               }
1990 +               return NF_DROP;
1991 +       }
1992 +
1993 +       /* FIXME: Do this right please. --RR */
1994 +       (*pskb)->nfcache |= NFC_UNKNOWN;
1995 +
1996 +/* Doesn't cover locally-generated broadcast, so not worth it. */
1997 +#if 0
1998 +       /* Ignore broadcast: no `connection'. */
1999 +       if ((*pskb)->pkt_type == PACKET_BROADCAST) {
2000 +               printk("Broadcast packet!\n");
2001 +               return NF_ACCEPT;
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);
2008 +       }
2009 +#endif
2010 +
2011 +       /* Previously seen (loopback or untracked)?  Ignore. */
2012 +       if ((*pskb)->nfct)
2013 +               return NF_ACCEPT;
2014 +
2015 +       proto = ip_ct_find_proto((*pskb)->nh.iph->protocol);
2016 +
2017 +       /* It may be an icmp error... */
2018 +       if ((*pskb)->nh.iph->protocol == IPPROTO_ICMP 
2019 +           && icmp_error_track(*pskb, &ctinfo, hooknum))
2020 +               return NF_ACCEPT;
2021 +
2022 +       if (!(ct = resolve_normal_ct(*pskb, proto,&set_reply,hooknum,&ctinfo)))
2023 +               /* Not valid part of a connection */
2024 +               return NF_ACCEPT;
2025 +
2026 +       if (IS_ERR(ct))
2027 +               /* Too stressed to deal. */
2028 +               return NF_DROP;
2029 +
2030 +       IP_NF_ASSERT((*pskb)->nfct);
2031 +
2032 +       ret = proto->packet(ct, *pskb, ctinfo);
2033 +       if (ret == -1) {
2034 +               /* Invalid */
2035 +               nf_conntrack_put((*pskb)->nfct);
2036 +               (*pskb)->nfct = NULL;
2037 +               return NF_ACCEPT;
2038 +       }
2039 +
2040 +       if (ret != NF_DROP && ct->helper) {
2041 +               ret = ct->helper->help(*pskb, ct, ctinfo);
2042 +               if (ret == -1) {
2043 +                       /* Invalid */
2044 +                       nf_conntrack_put((*pskb)->nfct);
2045 +                       (*pskb)->nfct = NULL;
2046 +                       return NF_ACCEPT;
2047 +               }
2048 +       }
2049 +       if (set_reply)
2050 +               set_bit(IPS_SEEN_REPLY_BIT, &ct->status);
2051 +
2052 +       return ret;
2053 +}
2054 +
2055 +int invert_tuplepr(struct ip_conntrack_tuple *inverse,
2056 +                  const struct ip_conntrack_tuple *orig)
2057 +{
2058 +       return invert_tuple(inverse, orig, ip_ct_find_proto(orig->dst.protonum));
2059 +}
2060 +
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)
2064 +{
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));
2072 +}
2073 +
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)
2078 +{
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 } };
2087 +
2088 +       return ip_ct_tuple_mask_cmp(&i->tuple, tuple, &intersect_mask);
2089 +}
2090 +
2091 +inline void ip_conntrack_unexpect_related(struct ip_conntrack_expect *expect)
2092 +{
2093 +       WRITE_LOCK(&ip_conntrack_lock);
2094 +       unexpect_related(expect);
2095 +       WRITE_UNLOCK(&ip_conntrack_lock);
2096 +}
2097 +       
2098 +static void expectation_timed_out(unsigned long ul_expect)
2099 +{
2100 +       struct ip_conntrack_expect *expect = (void *) ul_expect;
2101 +
2102 +       DEBUGP("expectation %p timed out\n", expect);   
2103 +       WRITE_LOCK(&ip_conntrack_lock);
2104 +       __unexpect_related(expect);
2105 +       WRITE_UNLOCK(&ip_conntrack_lock);
2106 +}
2107 +
2108 +struct ip_conntrack_expect *
2109 +ip_conntrack_expect_alloc()
2110 +{
2111 +       struct ip_conntrack_expect *new;
2112 +       
2113 +       new = (struct ip_conntrack_expect *)
2114 +               kmalloc(sizeof(struct ip_conntrack_expect), GFP_ATOMIC);
2115 +       if (!new) {
2116 +               DEBUGP("expect_related: OOM allocating expect\n");
2117 +               return NULL;
2118 +       }
2119 +
2120 +       /* tuple_cmp compares whole union, we have to initialized cleanly */
2121 +       memset(new, 0, sizeof(struct ip_conntrack_expect));
2122 +
2123 +       return new;
2124 +}
2125 +
2126 +static void
2127 +ip_conntrack_expect_insert(struct ip_conntrack_expect *new,
2128 +                          struct ip_conntrack *related_to)
2129 +{
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);
2134 +
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 */
2138 +
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);
2148 +       }
2149 +       related_to->expecting++;
2150 +}
2151 +
2152 +/* Add a related connection. */
2153 +int ip_conntrack_expect_related(struct ip_conntrack_expect *expect,
2154 +                               struct ip_conntrack *related_to)
2155 +{
2156 +       struct ip_conntrack_expect *old;
2157 +       int ret = 0;
2158 +
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 */
2162 +
2163 +       DEBUGP("ip_conntrack_expect_related %p\n", related_to);
2164 +       DEBUGP("tuple: "); DUMP_TUPLE(&expect->tuple);
2165 +       DEBUGP("mask:  "); DUMP_TUPLE(&expect->mask);
2166 +
2167 +       old = LIST_FIND(&ip_conntrack_expect_list, resent_expect,
2168 +                       struct ip_conntrack_expect *, &expect->tuple, 
2169 +                       &expect->mask);
2170 +       if (old) {
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 */
2178 +                               goto out;
2179 +                       } else {
2180 +                               old->timeout.expires = jiffies + 
2181 +                                       related_to->helper->timeout * HZ;
2182 +                               add_timer(&old->timeout);
2183 +                       }
2184 +               }
2185 +
2186 +               WRITE_UNLOCK(&ip_conntrack_lock);
2187 +               kfree(expect);
2188 +               return -EEXIST;
2189 +
2190 +       } else if (related_to->helper->max_expected && 
2191 +                  related_to->expecting >= related_to->helper->max_expected) {
2192 +               struct list_head *cur_item;
2193 +               /* old == NULL */
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));
2206 +                       kfree(expect);
2207 +                       return -EPERM;
2208 +               }
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));
2216
2217 +               /* choose the the oldest expectation to evict */
2218 +               list_for_each(cur_item, &related_to->sibling_list) { 
2219 +                       struct ip_conntrack_expect *cur;
2220 +
2221 +                       cur = list_entry(cur_item, 
2222 +                                        struct ip_conntrack_expect,
2223 +                                        expected_list);
2224 +                       if (cur->sibling == NULL) {
2225 +                               old = cur;
2226 +                               break;
2227 +                       }
2228 +               }
2229 +
2230 +               /* (!old) cannot happen, since related_to->expecting is the
2231 +                * number of unconfirmed expects */
2232 +               IP_NF_ASSERT(old);
2233 +
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. 
2238 +                */
2239 +               unexpect_related(old);
2240 +               ret = -EPERM;
2241 +       } else if (LIST_FIND(&ip_conntrack_expect_list, expect_clash,
2242 +                            struct ip_conntrack_expect *, &expect->tuple, 
2243 +                            &expect->mask)) {
2244 +               WRITE_UNLOCK(&ip_conntrack_lock);
2245 +               DEBUGP("expect_related: busy!\n");
2246 +
2247 +               kfree(expect);
2248 +               return -EBUSY;
2249 +       }
2250 +
2251 +out:   ip_conntrack_expect_insert(expect, related_to);
2252 +
2253 +       WRITE_UNLOCK(&ip_conntrack_lock);
2254 +
2255 +       return ret;
2256 +}
2257 +
2258 +/* Change tuple in an existing expectation */
2259 +int ip_conntrack_change_expect(struct ip_conntrack_expect *expect,
2260 +                              struct ip_conntrack_tuple *newtuple)
2261 +{
2262 +       int ret;
2263 +
2264 +       MUST_BE_READ_LOCKED(&ip_conntrack_lock);
2265 +       WRITE_LOCK(&ip_conntrack_expect_tuple_lock);
2266 +
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 */
2278 +                       ret = -1;
2279 +               } else {
2280 +                       memcpy(&expect->ct_tuple, &expect->tuple, sizeof(expect->tuple));
2281 +                       memcpy(&expect->tuple, newtuple, sizeof(expect->tuple));
2282 +                       ret = 0;
2283 +               }
2284 +       } else {
2285 +               /* Resent packet */
2286 +               DEBUGP("change expect: resent packet\n");
2287 +               if (ip_ct_tuple_equal(&expect->tuple, newtuple)) {
2288 +                       ret = 0;
2289 +               } else {
2290 +                       /* Force NAT to choose again the same port */
2291 +                       ret = -1;
2292 +               }
2293 +       }
2294 +       WRITE_UNLOCK(&ip_conntrack_expect_tuple_lock);
2295 +       
2296 +       return ret;
2297 +}
2298 +
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)
2303 +{
2304 +       WRITE_LOCK(&ip_conntrack_lock);
2305 +       if (__ip_conntrack_find(newreply, conntrack)) {
2306 +               WRITE_UNLOCK(&ip_conntrack_lock);
2307 +               return 0;
2308 +       }
2309 +       /* Should be unconfirmed, so not in hash table yet */
2310 +       IP_NF_ASSERT(!is_confirmed(conntrack));
2311 +
2312 +       DEBUGP("Altering reply tuple of %p to ", conntrack);
2313 +       DUMP_TUPLE(newreply);
2314 +
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 *,
2319 +                                             newreply);
2320 +       WRITE_UNLOCK(&ip_conntrack_lock);
2321 +
2322 +       return 1;
2323 +}
2324 +
2325 +int ip_conntrack_helper_register(struct ip_conntrack_helper *me)
2326 +{
2327 +       WRITE_LOCK(&ip_conntrack_lock);
2328 +       list_prepend(&helpers, me);
2329 +       WRITE_UNLOCK(&ip_conntrack_lock);
2330 +
2331 +       return 0;
2332 +}
2333 +
2334 +static inline int unhelp(struct ip_conntrack_tuple_hash *i,
2335 +                        const struct ip_conntrack_helper *me)
2336 +{
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;
2342 +       }
2343 +       return 0;
2344 +}
2345 +
2346 +void ip_conntrack_helper_unregister(struct ip_conntrack_helper *me)
2347 +{
2348 +       unsigned int i;
2349 +
2350 +       /* Need write lock here, to delete helper. */
2351 +       WRITE_LOCK(&ip_conntrack_lock);
2352 +       LIST_DELETE(&helpers, me);
2353 +
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);
2359 +
2360 +       /* Someone could be still looking at the helper in a bh. */
2361 +       synchronize_net();
2362 +}
2363 +
2364 +/* Refresh conntrack for this many jiffies. */
2365 +void ip_ct_refresh(struct ip_conntrack *ct, unsigned long extra_jiffies)
2366 +{
2367 +       IP_NF_ASSERT(ct->timeout.data == (unsigned long)ct);
2368 +
2369 +       /* If not in hash table, timer will not be active yet */
2370 +       if (!is_confirmed(ct))
2371 +               ct->timeout.expires = extra_jiffies;
2372 +       else {
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);
2378 +               }
2379 +               WRITE_UNLOCK(&ip_conntrack_lock);
2380 +       }
2381 +}
2382 +
2383 +/* Returns new sk_buff, or NULL */
2384 +struct sk_buff *
2385 +ip_ct_gather_frags(struct sk_buff *skb)
2386 +{
2387 +       struct sock *sk = skb->sk;
2388 +#ifdef CONFIG_NETFILTER_DEBUG
2389 +       unsigned int olddebug = skb->nf_debug;
2390 +#endif
2391 +       if (sk) {
2392 +               sock_hold(sk);
2393 +               skb_orphan(skb);
2394 +       }
2395 +
2396 +       local_bh_disable(); 
2397 +       skb = ip_defrag(skb);
2398 +       local_bh_enable();
2399 +
2400 +       if (!skb) {
2401 +               if (sk)
2402 +                       sock_put(sk);
2403 +               return skb;
2404 +       }
2405 +
2406 +       if (sk) {
2407 +               skb_set_owner_w(skb, sk);
2408 +               sock_put(sk);
2409 +       }
2410 +
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;
2416 +#endif
2417 +       return skb;
2418 +}
2419 +
2420 +/* Used by ipt_REJECT. */
2421 +static void ip_conntrack_attach(struct sk_buff *nskb, struct nf_ct_info *nfct)
2422 +{
2423 +       struct ip_conntrack *ct;
2424 +       enum ip_conntrack_info ctinfo;
2425 +
2426 +       ct = __ip_conntrack_get(nfct, &ctinfo);
2427 +
2428 +       /* This ICMP is in reverse direction to the packet which
2429 +           caused it */
2430 +       if (CTINFO2DIR(ctinfo) == IP_CT_DIR_ORIGINAL)
2431 +               ctinfo = IP_CT_RELATED + IP_CT_IS_REPLY;
2432 +       else
2433 +               ctinfo = IP_CT_RELATED;
2434 +
2435 +       /* Attach new skbuff, and increment count */
2436 +       nskb->nfct = &ct->infos[ctinfo];
2437 +       atomic_inc(&ct->ct_general.use);
2438 +}
2439 +
2440 +static inline int
2441 +do_kill(const struct ip_conntrack_tuple_hash *i,
2442 +       int (*kill)(const struct ip_conntrack *i, void *data),
2443 +       void *data)
2444 +{
2445 +       return kill(i->ctrack, data);
2446 +}
2447 +
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)
2452 +{
2453 +       struct ip_conntrack_tuple_hash *h = NULL;
2454 +
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);
2459 +       }
2460 +       if (h)
2461 +               atomic_inc(&h->ctrack->ct_general.use);
2462 +       READ_UNLOCK(&ip_conntrack_lock);
2463 +
2464 +       return h;
2465 +}
2466 +
2467 +void
2468 +ip_ct_selective_cleanup(int (*kill)(const struct ip_conntrack *i, void *data),
2469 +                       void *data)
2470 +{
2471 +       struct ip_conntrack_tuple_hash *h;
2472 +       unsigned int bucket = 0;
2473 +
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. */
2479 +
2480 +               ip_conntrack_put(h->ctrack);
2481 +       }
2482 +}
2483 +
2484 +/* Fast function for those who don't want to parse /proc (and I don't
2485 +   blame them). */
2486 +/* Reversing the socket's dst/src point of view gives us the reply
2487 +   mapping. */
2488 +static int
2489 +getorigdst(struct sock *sk, int optval, void *user, int *len)
2490 +{
2491 +       struct inet_opt *inet = inet_sk(sk);
2492 +       struct ip_conntrack_tuple_hash *h;
2493 +       struct ip_conntrack_tuple tuple;
2494 +       
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;
2501 +
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;
2506 +       }
2507 +
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));
2511 +               return -EINVAL;
2512 +       }
2513 +
2514 +       h = ip_conntrack_find_get(&tuple, NULL);
2515 +       if (h) {
2516 +               struct sockaddr_in sin;
2517 +
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]
2522 +                       .tuple.dst.ip;
2523 +
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)
2528 +                       return -EFAULT;
2529 +               else
2530 +                       return 0;
2531 +       }
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));
2535 +       return -ENOENT;
2536 +}
2537 +
2538 +static struct nf_sockopt_ops so_getorigdst = {
2539 +       .pf             = PF_INET,
2540 +       .get_optmin     = SO_ORIGINAL_DST,
2541 +       .get_optmax     = SO_ORIGINAL_DST+1,
2542 +       .get            = &getorigdst,
2543 +};
2544 +
2545 +static int kill_all(const struct ip_conntrack *i, void *data)
2546 +{
2547 +       return 1;
2548 +}
2549 +
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)
2553 +{
2554 +       ip_ct_attach = NULL;
2555 +       /* This makes sure all current packets have passed through
2556 +           netfilter framework.  Roll on, two-stage module
2557 +           delete... */
2558 +       synchronize_net();
2559
2560 + i_see_dead_people:
2561 +       ip_ct_selective_cleanup(kill_all, NULL);
2562 +       if (atomic_read(&ip_conntrack_count) != 0) {
2563 +               schedule();
2564 +               goto i_see_dead_people;
2565 +       }
2566 +
2567 +       kmem_cache_destroy(ip_conntrack_cachep);
2568 +       vfree(ip_conntrack_hash);
2569 +       nf_unregister_sockopt(&so_getorigdst);
2570 +}
2571 +
2572 +static int hashsize;
2573 +MODULE_PARM(hashsize, "i");
2574 +
2575 +int __init ip_conntrack_init(void)
2576 +{
2577 +       unsigned int i;
2578 +       int ret;
2579 +
2580 +       /* Idea from tcp.c: use 1/16384 of memory.  On i386: 32MB
2581 +        * machine has 256 buckets.  >= 1GB machines have 8192 buckets. */
2582 +       if (hashsize) {
2583 +               ip_conntrack_htable_size = hashsize;
2584 +       } else {
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;
2592 +       }
2593 +       ip_conntrack_max = 8 * ip_conntrack_htable_size;
2594 +
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));
2599 +
2600 +       ret = nf_register_sockopt(&so_getorigdst);
2601 +       if (ret != 0) {
2602 +               printk(KERN_ERR "Unable to register netfilter socket option\n");
2603 +               return ret;
2604 +       }
2605 +
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;
2611 +       }
2612 +
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;
2619 +       }
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);
2627 +
2628 +       for (i = 0; i < ip_conntrack_htable_size; i++)
2629 +               INIT_LIST_HEAD(&ip_conntrack_hash[i]);
2630 +
2631 +       /* For use by ipt_REJECT */
2632 +       ip_ct_attach = ip_conntrack_attach;
2633 +
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;
2644 +
2645 +       return ret;
2646 +
2647 +err_free_hash:
2648 +       vfree(ip_conntrack_hash);
2649 +err_unreg_sockopt:
2650 +       nf_unregister_sockopt(&so_getorigdst);
2651 +
2652 +       return -ENOMEM;
2653 +}
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
2657 @@ -0,0 +1,332 @@
2658 +/* Kernel module for IP pool management */
2659 +
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>
2670 +
2671 +#if 0
2672 +#define DP printk
2673 +#else
2674 +#define DP(format, args...)
2675 +#endif
2676 +
2677 +MODULE_LICENSE("GPL");
2678 +
2679 +#define NR_POOL 16
2680 +static int nr_pool = NR_POOL;/* overwrite this when loading module */
2681 +
2682 +struct ip_pool {
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 */
2688 +       rwlock_t lock;
2689 +};
2690 +
2691 +static struct ip_pool *POOL;
2692 +
2693 +static inline struct ip_pool *lookup(ip_pool_t index)
2694 +{
2695 +       if (index < 0 || index >= nr_pool) {
2696 +               DP("ip_pool:lookup: bad index %d\n", index);
2697 +               return 0;
2698 +       }
2699 +       return POOL+index;
2700 +}
2701 +
2702 +int ip_pool_match(ip_pool_t index, u_int32_t addr)
2703 +{
2704 +        struct ip_pool *pool = lookup(index);
2705 +       int res = 0;
2706 +
2707 +       if (!pool || !pool->members)
2708 +               return 0;
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)) {
2714 +                               res = 1;
2715 +#ifdef CONFIG_IP_POOL_STATISTICS
2716 +                               pool->nr_match++;
2717 +#endif
2718 +                       }
2719 +               }
2720 +#ifdef CONFIG_IP_POOL_STATISTICS
2721 +               pool->nr_use++;
2722 +#endif
2723 +       }
2724 +       read_unlock_bh(&pool->lock);
2725 +       return res;
2726 +}
2727 +
2728 +static int pool_change(ip_pool_t index, u_int32_t addr, int isdel)
2729 +{
2730 +       struct ip_pool *pool;
2731 +       int res = -1;
2732 +
2733 +       pool = lookup(index);
2734 +       if (    !pool || !pool->members
2735 +            || addr < pool->first_ip || addr > pool->last_ip)
2736 +               return -1;
2737 +       read_lock_bh(&pool->lock);
2738 +       if (pool->members && addr >= pool->first_ip && addr <= pool->last_ip) {
2739 +               addr -= pool->first_ip;
2740 +               res = isdel
2741 +                       ? (0 != test_and_clear_bit(addr, pool->members))
2742 +                       : (0 != test_and_set_bit(addr, pool->members));
2743 +       }
2744 +       read_unlock_bh(&pool->lock);
2745 +       return res;
2746 +}
2747 +
2748 +int ip_pool_mod(ip_pool_t index, u_int32_t addr, int isdel)
2749 +{
2750 +       int res = pool_change(index,addr,isdel);
2751 +
2752 +       if (!isdel) res = !res;
2753 +       return res;
2754 +}
2755 +
2756 +static inline int bitmap_bytes(u_int32_t a, u_int32_t b)
2757 +{
2758 +       return 4*((((b-a+8)/8)+3)/4);
2759 +}
2760 +
2761 +static inline int poolbytes(ip_pool_t index)
2762 +{
2763 +       struct ip_pool *pool = lookup(index);
2764 +
2765 +       return pool ? bitmap_bytes(pool->first_ip, pool->last_ip) : 0;
2766 +}
2767 +
2768 +static int setpool(
2769 +       struct sock *sk,
2770 +       int optval,
2771 +       void *user,
2772 +       unsigned int len
2773 +) {
2774 +       struct ip_pool_request req;
2775 +
2776 +       DP("ip_pool:setpool: optval=%d, user=%p, len=%d\n", optval, user, len);
2777 +       if (!capable(CAP_NET_ADMIN))
2778 +               return -EPERM;
2779 +       if (optval != SO_IP_POOL)
2780 +               return -EBADF;
2781 +       if (len != sizeof(req))
2782 +               return -EINVAL;
2783 +       if (copy_from_user(&req, user, sizeof(req)) != 0)
2784 +               return -EFAULT;
2785 +       printk("obsolete op - upgrade your ippool(8) utility.\n");
2786 +       return -EINVAL;
2787 +}
2788 +
2789 +static int getpool(
2790 +       struct sock *sk,
2791 +       int optval,
2792 +       void *user,
2793 +       int *len
2794 +) {
2795 +       struct ip_pool_request req;
2796 +       struct ip_pool *pool;
2797 +       ip_pool_t i;
2798 +       int newbytes;
2799 +       void *newmembers;
2800 +       int res;
2801 +
2802 +       DP("ip_pool:getpool: optval=%d, user=%p\n", optval, user);
2803 +       if (!capable(CAP_NET_ADMIN))
2804 +               return -EINVAL;
2805 +       if (optval != SO_IP_POOL)
2806 +               return -EINVAL;
2807 +       if (*len != sizeof(req)) {
2808 +               return -EFAULT;
2809 +       }
2810 +       if (copy_from_user(&req, user, sizeof(req)) != 0)
2811 +               return -EFAULT;
2812 +       DP("ip_pool:getpool op=%d, index=%d\n", req.op, req.index);
2813 +       if (req.op < IP_POOL_BAD001) {
2814 +               printk("obsolete op - upgrade your ippool(8) utility.\n");
2815 +               return -EFAULT;
2816 +       }
2817 +       switch(req.op) {
2818 +       case IP_POOL_HIGH_NR:
2819 +               DP("ip_pool HIGH_NR\n");
2820 +               req.index = IP_POOL_NONE;
2821 +               for (i=0; i<nr_pool; i++)
2822 +                       if (POOL[i].members)
2823 +                               req.index = i;
2824 +               return copy_to_user(user, &req, sizeof(req));
2825 +       case IP_POOL_LOOKUP:
2826 +               DP("ip_pool LOOKUP\n");
2827 +               pool = lookup(req.index);
2828 +               if (!pool)
2829 +                       return -EINVAL;
2830 +               if (!pool->members)
2831 +                       return -EBADF;
2832 +               req.addr = htonl(pool->first_ip);
2833 +               req.addr2 = htonl(pool->last_ip);
2834 +               return copy_to_user(user, &req, sizeof(req));
2835 +       case IP_POOL_USAGE:
2836 +               DP("ip_pool USE\n");
2837 +               pool = lookup(req.index);
2838 +               if (!pool)
2839 +                       return -EINVAL;
2840 +               if (!pool->members)
2841 +                       return -EBADF;
2842 +               req.addr = pool->nr_use;
2843 +               req.addr2 = pool->nr_match;
2844 +               return copy_to_user(user, &req, sizeof(req));
2845 +       case IP_POOL_TEST_ADDR:
2846 +               DP("ip_pool TEST 0x%08x\n", req.addr);
2847 +               pool = lookup(req.index);
2848 +               if (!pool)
2849 +                       return -EINVAL;
2850 +               res = 0;
2851 +               read_lock_bh(&pool->lock);
2852 +               if (!pool->members) {
2853 +                       DP("ip_pool TEST_ADDR no members in pool\n");
2854 +                       res = -EBADF;
2855 +                       goto unlock_and_return_res;
2856 +               }
2857 +               req.addr = ntohl(req.addr);
2858 +               if (req.addr < pool->first_ip) {
2859 +                       DP("ip_pool TEST_ADDR address < pool bounds\n");
2860 +                       res = -ERANGE;
2861 +                       goto unlock_and_return_res;
2862 +               }
2863 +               if (req.addr > pool->last_ip) {
2864 +                       DP("ip_pool TEST_ADDR address > pool bounds\n");
2865 +                       res = -ERANGE;
2866 +                       goto unlock_and_return_res;
2867 +               }
2868 +               req.addr = (0 != test_bit((req.addr - pool->first_ip),
2869 +                                       pool->members));
2870 +               read_unlock_bh(&pool->lock);
2871 +               return copy_to_user(user, &req, sizeof(req));
2872 +       case IP_POOL_FLUSH:
2873 +               DP("ip_pool FLUSH not yet implemented.\n");
2874 +               return -EBUSY;
2875 +       case IP_POOL_DESTROY:
2876 +               DP("ip_pool DESTROY not yet implemented.\n");
2877 +               return -EBUSY;
2878 +       case IP_POOL_INIT:
2879 +               DP("ip_pool INIT 0x%08x-0x%08x\n", req.addr, req.addr2);
2880 +               pool = lookup(req.index);
2881 +               if (!pool)
2882 +                       return -EINVAL;
2883 +               req.addr = ntohl(req.addr);
2884 +               req.addr2 = ntohl(req.addr2);
2885 +               if (req.addr > req.addr2) {
2886 +                       DP("ip_pool INIT bad ip range\n");
2887 +                       return -EINVAL;
2888 +               }
2889 +               newbytes = bitmap_bytes(req.addr, req.addr2);
2890 +               newmembers = kmalloc(newbytes, GFP_KERNEL);
2891 +               if (!newmembers) {
2892 +                       DP("ip_pool INIT out of mem for %d bytes\n", newbytes);
2893 +                       return -ENOMEM;
2894 +               }
2895 +               memset(newmembers, 0, newbytes);
2896 +               write_lock_bh(&pool->lock);
2897 +               if (pool->members) {
2898 +                       DP("ip_pool INIT pool %d exists\n", req.index);
2899 +                       kfree(newmembers);
2900 +                       res = -EBUSY;
2901 +                       goto unlock_and_return_res;
2902 +               }
2903 +               pool->first_ip = req.addr;
2904 +               pool->last_ip = req.addr2;
2905 +               pool->nr_use = 0;
2906 +               pool->nr_match = 0;
2907 +               pool->members = newmembers;
2908 +               write_unlock_bh(&pool->lock);
2909 +               return 0;
2910 +       case IP_POOL_ADD_ADDR:
2911 +               DP("ip_pool ADD_ADDR 0x%08x\n", req.addr);
2912 +               req.addr = pool_change(req.index, ntohl(req.addr), 0);
2913 +               return copy_to_user(user, &req, sizeof(req));
2914 +       case IP_POOL_DEL_ADDR:
2915 +               DP("ip_pool DEL_ADDR 0x%08x\n", req.addr);
2916 +               req.addr = pool_change(req.index, ntohl(req.addr), 1);
2917 +               return copy_to_user(user, &req, sizeof(req));
2918 +       default:
2919 +               DP("ip_pool:getpool bad op %d\n", req.op);
2920 +               return -EINVAL;
2921 +       }
2922 +       return -EINVAL;
2923 +
2924 +unlock_and_return_res:
2925 +       if (pool)
2926 +               read_unlock_bh(&pool->lock);
2927 +       return res;
2928 +}
2929 +
2930 +static struct nf_sockopt_ops so_pool
2931 += { { NULL, NULL }, PF_INET,
2932 +    SO_IP_POOL, SO_IP_POOL+1, &setpool,
2933 +    SO_IP_POOL, SO_IP_POOL+1, &getpool,
2934 +    0, NULL };
2935 +
2936 +MODULE_PARM(nr_pool, "i");
2937 +
2938 +static int __init init(void)
2939 +{
2940 +       ip_pool_t i;
2941 +       int res;
2942 +
2943 +       if (nr_pool < 1) {
2944 +               printk("ip_pool module init: bad nr_pool %d\n", nr_pool);
2945 +               return -EINVAL;
2946 +       }
2947 +       POOL = kmalloc(nr_pool * sizeof(*POOL), GFP_KERNEL);
2948 +       if (!POOL) {
2949 +               printk("ip_pool module init: out of memory for nr_pool %d\n",
2950 +                       nr_pool);
2951 +               return -ENOMEM;
2952 +       }
2953 +       for (i=0; i<nr_pool; i++) {
2954 +               POOL[i].first_ip = 0;
2955 +               POOL[i].last_ip = 0;
2956 +               POOL[i].members = 0;
2957 +               POOL[i].nr_use = 0;
2958 +               POOL[i].nr_match = 0;
2959 +               POOL[i].lock = RW_LOCK_UNLOCKED;
2960 +       }
2961 +       res = nf_register_sockopt(&so_pool);
2962 +       DP("ip_pool:init %d pools, result %d\n", nr_pool, res);
2963 +       if (res != 0) {
2964 +               kfree(POOL);
2965 +               POOL = 0;
2966 +       }
2967 +       return res;
2968 +}
2969 +
2970 +static void __exit fini(void)
2971 +{
2972 +       ip_pool_t i;
2973 +
2974 +       DP("ip_pool:fini BYEBYE\n");
2975 +       nf_unregister_sockopt(&so_pool);
2976 +       for (i=0; i<nr_pool; i++) {
2977 +               if (POOL[i].members) {
2978 +                       kfree(POOL[i].members);
2979 +                       POOL[i].members = 0;
2980 +               }
2981 +       }
2982 +       kfree(POOL);
2983 +       POOL = 0;
2984 +       DP("ip_pool:fini these are the famous last words\n");
2985 +       return;
2986 +}
2987 +
2988 +module_init(init);
2989 +module_exit(fini);
2990 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
2991 --- linux-2.6.6-rc1.org/net/ipv4/netfilter/ip_tables.c  2004-04-15 03:34:03.000000000 +0200
2992 +++ linux-2.6.6-rc1/net/ipv4/netfilter/ip_tables.c      2004-04-19 10:08:25.000000000 +0200
2993 @@ -1716,9 +1716,9 @@
2994  };
2995  
2996  #ifdef CONFIG_PROC_FS
2997 -static inline int print_name(const char *i,
2998 -                            off_t start_offset, char *buffer, int length,
2999 -                            off_t *pos, unsigned int *count)
3000 +static int print_name(const char *i,
3001 +                      off_t start_offset, char *buffer, int length,
3002 +                      off_t *pos, unsigned int *count)
3003  {
3004         if ((*count)++ >= start_offset) {
3005                 unsigned int namelen;
3006 @@ -1752,6 +1752,15 @@
3007         return pos;
3008  }
3009  
3010 +static inline int print_target(const struct ipt_target *t,
3011 +                               off_t start_offset, char *buffer, int length,
3012 +                               off_t *pos, unsigned int *count)
3013 +{
3014 +       if (t != &ipt_standard_target && t != &ipt_error_target)
3015 +               return 0;
3016 +       return print_name((char *)t, start_offset, buffer, length, pos, count);
3017 +}
3018 +
3019  static int ipt_get_targets(char *buffer, char **start, off_t offset, int length)
3020  {
3021         off_t pos = 0;
3022 @@ -1760,7 +1769,7 @@
3023         if (down_interruptible(&ipt_mutex) != 0)
3024                 return 0;
3025  
3026 -       LIST_FIND(&ipt_target, print_name, void *,
3027 +       LIST_FIND(&ipt_target, print_target, struct ipt_target *,
3028                   offset, buffer, length, &pos, &count);
3029         
3030         up(&ipt_mutex);
3031 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
3032 --- linux-2.6.6-rc1.org/net/ipv4/netfilter/ipt_IPV4OPTSSTRIP.c  1970-01-01 01:00:00.000000000 +0100
3033 +++ linux-2.6.6-rc1/net/ipv4/netfilter/ipt_IPV4OPTSSTRIP.c      2004-04-19 10:08:26.000000000 +0200
3034 @@ -0,0 +1,89 @@
3035 +/**
3036 + * Strip all IP options in the IP packet header.
3037 + *
3038 + * (C) 2001 by Fabrice MARIE <fabrice@netfilter.org>
3039 + * This software is distributed under GNU GPL v2, 1991
3040 + */
3041 +
3042 +#include <linux/module.h>
3043 +#include <linux/skbuff.h>
3044 +#include <linux/ip.h>
3045 +#include <net/checksum.h>
3046 +
3047 +#include <linux/netfilter_ipv4/ip_tables.h>
3048 +
3049 +MODULE_AUTHOR("Fabrice MARIE <fabrice@netfilter.org>");
3050 +MODULE_DESCRIPTION("Strip all options in IPv4 packets");
3051 +MODULE_LICENSE("GPL");
3052 +
3053 +static unsigned int
3054 +target(struct sk_buff **pskb,
3055 +       const struct net_device *in,
3056 +       const struct net_device *out,
3057 +       unsigned int hooknum,
3058 +       const void *targinfo,
3059 +       void *userinfo)
3060 +{
3061 +       struct iphdr *iph;
3062 +       struct sk_buff *skb;
3063 +       struct ip_options *opt;
3064 +       unsigned char *optiph;
3065 +       int l;
3066 +       
3067 +       if (!skb_ip_make_writable(pskb, (*pskb)->len))
3068 +               return NF_DROP;
3069
3070 +       skb = (*pskb);
3071 +       iph = (*pskb)->nh.iph;
3072 +       optiph = skb->nh.raw;
3073 +       l = ((struct ip_options *)(&(IPCB(skb)->opt)))->optlen;
3074 +
3075 +       /* if no options in packet then nothing to clear. */
3076 +       if (iph->ihl * 4 == sizeof(struct iphdr))
3077 +               return IPT_CONTINUE;
3078 +
3079 +       /* else clear all options */
3080 +       memset(&(IPCB(skb)->opt), 0, sizeof(struct ip_options));
3081 +       memset(optiph+sizeof(struct iphdr), IPOPT_NOOP, l);
3082 +       opt = &(IPCB(skb)->opt);
3083 +       opt->is_data = 0;
3084 +       opt->optlen = l;
3085 +
3086 +       skb->nfcache |= NFC_ALTERED;
3087 +
3088 +        return IPT_CONTINUE;
3089 +}
3090 +
3091 +static int
3092 +checkentry(const char *tablename,
3093 +          const struct ipt_entry *e,
3094 +           void *targinfo,
3095 +           unsigned int targinfosize,
3096 +           unsigned int hook_mask)
3097 +{
3098 +       if (strcmp(tablename, "mangle")) {
3099 +               printk(KERN_WARNING "IPV4OPTSSTRIP: can only be called from \"mangle\" table, not \"%s\"\n", tablename);
3100 +               return 0;
3101 +       }
3102 +       /* nothing else to check because no parameters */
3103 +       return 1;
3104 +}
3105 +
3106 +static struct ipt_target ipt_ipv4optsstrip_reg = { 
3107 +       .name = "IPV4OPTSSTRIP",
3108 +       .target = target,
3109 +       .checkentry = checkentry,
3110 +       .me = THIS_MODULE };
3111 +
3112 +static int __init init(void)
3113 +{
3114 +       return ipt_register_target(&ipt_ipv4optsstrip_reg);
3115 +}
3116 +
3117 +static void __exit fini(void)
3118 +{
3119 +       ipt_unregister_target(&ipt_ipv4optsstrip_reg);
3120 +}
3121 +
3122 +module_init(init);
3123 +module_exit(fini);
3124 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
3125 --- linux-2.6.6-rc1.org/net/ipv4/netfilter/ipt_POOL.c   1970-01-01 01:00:00.000000000 +0100
3126 +++ linux-2.6.6-rc1/net/ipv4/netfilter/ipt_POOL.c       2004-04-19 10:08:36.000000000 +0200
3127 @@ -0,0 +1,116 @@
3128 +/* ipt_POOL.c - netfilter target to manipulate IP pools
3129 + *
3130 + * This target can be used almost everywhere. It acts on some specified
3131 + * IP pool, adding or deleting some IP address in the pool. The address
3132 + * can be either the source (--addsrc, --delsrc), or destination (--add/deldst)
3133 + * of the packet under inspection.
3134 + *
3135 + * The target normally returns IPT_CONTINUE.
3136 + */
3137 +
3138 +#include <linux/types.h>
3139 +#include <linux/ip.h>
3140 +#include <linux/timer.h>
3141 +#include <linux/module.h>
3142 +#include <linux/netfilter.h>
3143 +#include <linux/netdevice.h>
3144 +#include <linux/if.h>
3145 +#include <linux/inetdevice.h>
3146 +#include <net/protocol.h>
3147 +#include <net/checksum.h>
3148 +#include <linux/netfilter_ipv4.h>
3149 +#include <linux/netfilter_ipv4/ip_nat_rule.h>
3150 +#include <linux/netfilter_ipv4/ipt_pool.h>
3151 +
3152 +#if 0
3153 +#define DEBUGP printk
3154 +#else
3155 +#define DEBUGP(format, args...)
3156 +#endif
3157 +
3158 +/*** NOTE NOTE NOTE NOTE ***
3159 +**
3160 +** By sheer luck, I get away with using the "struct ipt_pool_info", as defined
3161 +** in <linux/netfilter_ipv4/ipt_pool.h>, both as the match and target info.
3162 +** Here, in the target implementation, ipt_pool_info.src, if not IP_POOL_NONE,
3163 +** is modified for the source IP address of the packet under inspection.
3164 +** The same way, the ipt_pool_info.dst pool is modified for the destination.
3165 +**
3166 +** The address is added to the pool normally. However, if IPT_POOL_DEL_dir
3167 +** flag is set in ipt_pool_info.flags, the address is deleted from the pool.
3168 +**
3169 +** If a modification was done to the pool, we possibly return ACCEPT or DROP,
3170 +** if the right IPT_POOL_MOD_dir_ACCEPT or _MOD_dir_DROP flags are set.
3171 +** The IPT_POOL_INV_MOD_dir flag inverts the sense of the check (i.e. the
3172 +** ACCEPT and DROP flags are evaluated when the pool was not modified.)
3173 +*/
3174 +
3175 +static int
3176 +do_check(const char *tablename,
3177 +              const struct ipt_entry *e,
3178 +              void *targinfo,
3179 +              unsigned int targinfosize,
3180 +              unsigned int hook_mask)
3181 +{
3182 +       const struct ipt_pool_info *ipi = targinfo;
3183 +
3184 +       if (targinfosize != IPT_ALIGN(sizeof(*ipi))) {
3185 +               DEBUGP("POOL_check: size %u.\n", targinfosize);
3186 +               return 0;
3187 +       }
3188 +       DEBUGP("ipt_POOL:do_check(%d,%d,%d)\n",ipi->src,ipi->dst,ipi->flags);
3189 +       return 1;
3190 +}
3191 +
3192 +static unsigned int
3193 +do_target(struct sk_buff **pskb,
3194 +               unsigned int hooknum,
3195 +               const struct net_device *in,
3196 +               const struct net_device *out,
3197 +               const void *targinfo,
3198 +               void *userinfo)
3199 +{
3200 +       const struct ipt_pool_info *ipi = targinfo;
3201 +       int modified;
3202 +       unsigned int verdict = IPT_CONTINUE;
3203 +
3204 +       if (ipi->src != IP_POOL_NONE) {
3205 +               modified = ip_pool_mod(ipi->src, ntohl((*pskb)->nh.iph->saddr),
3206 +                                       ipi->flags & IPT_POOL_DEL_SRC);
3207 +               if (!!modified ^ !!(ipi->flags & IPT_POOL_INV_MOD_SRC)) {
3208 +                       if (ipi->flags & IPT_POOL_MOD_SRC_ACCEPT)
3209 +                               verdict = NF_ACCEPT;
3210 +                       else if (ipi->flags & IPT_POOL_MOD_SRC_DROP)
3211 +                               verdict = NF_DROP;
3212 +               }
3213 +       }
3214 +       if (verdict == IPT_CONTINUE && ipi->dst != IP_POOL_NONE) {
3215 +               modified = ip_pool_mod(ipi->dst, ntohl((*pskb)->nh.iph->daddr),
3216 +                                       ipi->flags & IPT_POOL_DEL_DST);
3217 +               if (!!modified ^ !!(ipi->flags & IPT_POOL_INV_MOD_DST)) {
3218 +                       if (ipi->flags & IPT_POOL_MOD_DST_ACCEPT)
3219 +                               verdict = NF_ACCEPT;
3220 +                       else if (ipi->flags & IPT_POOL_MOD_DST_DROP)
3221 +                               verdict = NF_DROP;
3222 +               }
3223 +       }
3224 +       return verdict;
3225 +}
3226 +
3227 +static struct ipt_target pool_reg
3228 += { { NULL, NULL }, "POOL", do_target, do_check, NULL, THIS_MODULE };
3229 +
3230 +static int __init init(void)
3231 +{
3232 +       DEBUGP("init ipt_POOL\n");
3233 +       return ipt_register_target(&pool_reg);
3234 +}
3235 +
3236 +static void __exit fini(void)
3237 +{
3238 +       DEBUGP("fini ipt_POOL\n");
3239 +       ipt_unregister_target(&pool_reg);
3240 +}
3241 +
3242 +module_init(init);
3243 +module_exit(fini);
3244 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
3245 --- linux-2.6.6-rc1.org/net/ipv4/netfilter/ipt_TTL.c    1970-01-01 01:00:00.000000000 +0100
3246 +++ linux-2.6.6-rc1/net/ipv4/netfilter/ipt_TTL.c        2004-04-19 10:08:28.000000000 +0200
3247 @@ -0,0 +1,120 @@
3248 +/* TTL modification target for IP tables
3249 + * (C) 2000 by Harald Welte <laforge@gnumonks.org>
3250 + *
3251 + * Version: $Revision$
3252 + *
3253 + * This software is distributed under the terms of GNU GPL
3254 + */
3255 +
3256 +#include <linux/module.h>
3257 +#include <linux/skbuff.h>
3258 +#include <linux/ip.h>
3259 +#include <net/checksum.h>
3260 +
3261 +#include <linux/netfilter_ipv4/ip_tables.h>
3262 +#include <linux/netfilter_ipv4/ipt_TTL.h>
3263 +
3264 +MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
3265 +MODULE_DESCRIPTION("IP tables TTL modification module");
3266 +MODULE_LICENSE("GPL");
3267 +
3268 +static unsigned int 
3269 +ipt_ttl_target(struct sk_buff **pskb, const struct net_device *in, 
3270 +               const struct net_device *out, unsigned int hooknum, 
3271 +               const void *targinfo, void *userinfo)
3272 +{
3273 +       struct iphdr *iph;
3274 +       const struct ipt_TTL_info *info = targinfo;
3275 +       u_int16_t diffs[2];
3276 +       int new_ttl;
3277 +
3278 +       if (!skb_ip_make_writable(pskb, (*pskb)->len))
3279 +               return NF_DROP;
3280 +
3281 +       iph = (*pskb)->nh.iph;
3282 +                        
3283 +       switch (info->mode) {
3284 +               case IPT_TTL_SET:
3285 +                       new_ttl = info->ttl;
3286 +                       break;
3287 +               case IPT_TTL_INC:
3288 +                       new_ttl = iph->ttl + info->ttl;
3289 +                       if (new_ttl > 255)
3290 +                               new_ttl = 255;
3291 +                       break;
3292 +               case IPT_TTL_DEC:
3293 +                       new_ttl = iph->ttl + info->ttl;
3294 +                       if (new_ttl < 0)
3295 +                               new_ttl = 0;
3296 +                       break;
3297 +               default:
3298 +                       new_ttl = iph->ttl;
3299 +                       break;
3300 +       }
3301 +
3302 +       if (new_ttl != iph->ttl) {
3303 +               diffs[0] = htons(((unsigned)iph->ttl) << 8) ^ 0xFFFF;
3304 +               iph->ttl = new_ttl;
3305 +               diffs[1] = htons(((unsigned)iph->ttl) << 8);
3306 +               iph->check = csum_fold(csum_partial((char *)diffs,
3307 +                                                   sizeof(diffs),
3308 +                                                   iph->check^0xFFFF));
3309 +                                                                                               (*pskb)->nfcache |= NFC_ALTERED;
3310 +       }
3311 +
3312 +       return IPT_CONTINUE;
3313 +}
3314 +
3315 +static int ipt_ttl_checkentry(const char *tablename,
3316 +               const struct ipt_entry *e,
3317 +               void *targinfo,
3318 +               unsigned int targinfosize,
3319 +               unsigned int hook_mask)
3320 +{
3321 +       struct ipt_TTL_info *info = targinfo;
3322 +
3323 +       if (targinfosize != IPT_ALIGN(sizeof(struct ipt_TTL_info))) {
3324 +               printk(KERN_WARNING "TTL: targinfosize %u != %Zu\n",
3325 +                               targinfosize,
3326 +                               IPT_ALIGN(sizeof(struct ipt_TTL_info)));
3327 +               return 0;       
3328 +       }       
3329 +
3330 +       if (strcmp(tablename, "mangle")) {
3331 +               printk(KERN_WARNING "TTL: can only be called from \"mangle\" table, not \"%s\"\n", tablename);
3332 +               return 0;
3333 +       }
3334 +
3335 +       if (info->mode > IPT_TTL_MAXMODE) {
3336 +               printk(KERN_WARNING "TTL: invalid or unknown Mode %u\n", 
3337 +                       info->mode);
3338 +               return 0;
3339 +       }
3340 +
3341 +       if ((info->mode != IPT_TTL_SET) && (info->ttl == 0)) {
3342 +               printk(KERN_WARNING "TTL: increment/decrement doesn't make sense with value 0\n");
3343 +               return 0;
3344 +       }
3345 +       
3346 +       return 1;
3347 +}
3348 +
3349 +static struct ipt_target ipt_TTL = { 
3350 +       .name = "TTL",
3351 +       .target = ipt_ttl_target, 
3352 +       .checkentry = ipt_ttl_checkentry, 
3353 +       .me = THIS_MODULE 
3354 +};
3355 +
3356 +static int __init init(void)
3357 +{
3358 +       return ipt_register_target(&ipt_TTL);
3359 +}
3360 +
3361 +static void __exit fini(void)
3362 +{
3363 +       ipt_unregister_target(&ipt_TTL);
3364 +}
3365 +
3366 +module_init(init);
3367 +module_exit(fini);
3368 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
3369 --- linux-2.6.6-rc1.org/net/ipv4/netfilter/ipt_connlimit.c      1970-01-01 01:00:00.000000000 +0100
3370 +++ linux-2.6.6-rc1/net/ipv4/netfilter/ipt_connlimit.c  2004-04-19 10:08:29.000000000 +0200
3371 @@ -0,0 +1,230 @@
3372 +/*
3373 + * netfilter module to limit the number of parallel tcp
3374 + * connections per IP address.
3375 + *   (c) 2000 Gerd Knorr <kraxel@bytesex.org>
3376 + *   Nov 2002: Martin Bene <martin.bene@icomedias.com>:
3377 + *             only ignore TIME_WAIT or gone connections
3378 + *
3379 + * based on ...
3380 + *
3381 + * Kernel module to match connection tracking information.
3382 + * GPL (C) 1999  Rusty Russell (rusty@rustcorp.com.au).
3383 + */
3384 +#include <linux/module.h>
3385 +#include <linux/skbuff.h>
3386 +#include <linux/list.h>
3387 +#include <linux/netfilter_ipv4/ip_conntrack.h>
3388 +#include <linux/netfilter_ipv4/ip_conntrack_core.h>
3389 +#include <linux/netfilter_ipv4/ip_conntrack_tcp.h>
3390 +#include <linux/netfilter_ipv4/ip_tables.h>
3391 +#include <linux/netfilter_ipv4/ipt_connlimit.h>
3392 +
3393 +#define DEBUG 0
3394 +
3395 +MODULE_LICENSE("GPL");
3396 +
3397 +/* we'll save the tuples of all connections we care about */
3398 +struct ipt_connlimit_conn
3399 +{
3400 +        struct list_head list;
3401 +       struct ip_conntrack_tuple tuple;
3402 +};
3403 +
3404 +struct ipt_connlimit_data {
3405 +       spinlock_t lock;
3406 +       struct list_head iphash[256];
3407 +};
3408 +
3409 +static int ipt_iphash(u_int32_t addr)
3410 +{
3411 +       int hash;
3412 +
3413 +       hash  =  addr        & 0xff;
3414 +       hash ^= (addr >>  8) & 0xff;
3415 +       hash ^= (addr >> 16) & 0xff;
3416 +       hash ^= (addr >> 24) & 0xff;
3417 +       return hash;
3418 +}
3419 +
3420 +static int count_them(struct ipt_connlimit_data *data,
3421 +                     u_int32_t addr, u_int32_t mask,
3422 +                     struct ip_conntrack *ct)
3423 +{
3424 +#if DEBUG
3425 +       const static char *tcp[] = { "none", "established", "syn_sent", "syn_recv",
3426 +                                    "fin_wait", "time_wait", "close", "close_wait",
3427 +                                    "last_ack", "listen" };
3428 +#endif
3429 +       int addit = 1, matches = 0;
3430 +       struct ip_conntrack_tuple tuple;
3431 +       struct ip_conntrack_tuple_hash *found;
3432 +       struct ipt_connlimit_conn *conn;
3433 +       struct list_head *hash,*lh;
3434 +
3435 +       spin_lock(&data->lock);
3436 +       tuple = ct->tuplehash[0].tuple;
3437 +       hash = &data->iphash[ipt_iphash(addr & mask)];
3438 +
3439 +       /* check the saved connections */
3440 +       for (lh = hash->next; lh != hash; lh = lh->next) {
3441 +               conn = list_entry(lh,struct ipt_connlimit_conn,list);
3442 +               found = ip_conntrack_find_get(&conn->tuple,ct);
3443 +               if (0 == memcmp(&conn->tuple,&tuple,sizeof(tuple)) &&
3444 +                   found != NULL &&
3445 +                   found->ctrack->proto.tcp.state != TCP_CONNTRACK_TIME_WAIT) {
3446 +                       /* Just to be sure we have it only once in the list.
3447 +                          We should'nt see tuples twice unless someone hooks this
3448 +                          into a table without "-p tcp --syn" */
3449 +                       addit = 0;
3450 +               }
3451 +#if DEBUG
3452 +               printk("ipt_connlimit [%d]: src=%u.%u.%u.%u:%d dst=%u.%u.%u.%u:%d %s\n",
3453 +                      ipt_iphash(addr & mask),
3454 +                      NIPQUAD(conn->tuple.src.ip), ntohs(conn->tuple.src.u.tcp.port),
3455 +                      NIPQUAD(conn->tuple.dst.ip), ntohs(conn->tuple.dst.u.tcp.port),
3456 +                      (NULL != found) ? tcp[found->ctrack->proto.tcp.state] : "gone");
3457 +#endif
3458 +               if (NULL == found) {
3459 +                       /* this one is gone */
3460 +                       lh = lh->prev;
3461 +                       list_del(lh->next);
3462 +                       kfree(conn);
3463 +                       continue;
3464 +               }
3465 +               if (found->ctrack->proto.tcp.state == TCP_CONNTRACK_TIME_WAIT) {
3466 +                       /* we don't care about connections which are
3467 +                          closed already -> ditch it */
3468 +                       lh = lh->prev;
3469 +                       list_del(lh->next);
3470 +                       kfree(conn);
3471 +                       nf_conntrack_put(&found->ctrack->infos[0]);
3472 +                       continue;
3473 +               }
3474 +               if ((addr & mask) == (conn->tuple.src.ip & mask)) {
3475 +                       /* same source IP address -> be counted! */
3476 +                       matches++;
3477 +               }
3478 +               nf_conntrack_put(&found->ctrack->infos[0]);
3479 +       }
3480 +       if (addit) {
3481 +               /* save the new connection in our list */
3482 +#if DEBUG
3483 +               printk("ipt_connlimit [%d]: src=%u.%u.%u.%u:%d dst=%u.%u.%u.%u:%d new\n",
3484 +                      ipt_iphash(addr & mask),
3485 +                      NIPQUAD(tuple.src.ip), ntohs(tuple.src.u.tcp.port),
3486 +                      NIPQUAD(tuple.dst.ip), ntohs(tuple.dst.u.tcp.port));
3487 +#endif
3488 +               conn = kmalloc(sizeof(*conn),GFP_ATOMIC);
3489 +               if (NULL == conn)
3490 +                       return -1;
3491 +               memset(conn,0,sizeof(*conn));
3492 +               INIT_LIST_HEAD(&conn->list);
3493 +               conn->tuple = tuple;
3494 +               list_add(&conn->list,hash);
3495 +               matches++;
3496 +       }
3497 +       spin_unlock(&data->lock);
3498 +       return matches;
3499 +}
3500 +
3501 +static int
3502 +match(const struct sk_buff *skb,
3503 +      const struct net_device *in,
3504 +      const struct net_device *out,
3505 +      const void *matchinfo,
3506 +      int offset,
3507 +      int *hotdrop)
3508 +{
3509 +       const struct ipt_connlimit_info *info = matchinfo;
3510 +       int connections, match;
3511 +       struct ip_conntrack *ct;
3512 +       enum ip_conntrack_info ctinfo;
3513 +
3514 +       ct = ip_conntrack_get((struct sk_buff *)skb, &ctinfo);
3515 +       if (NULL == ct) {
3516 +               printk("ipt_connlimit: Oops: invalid ct state ?\n");
3517 +               *hotdrop = 1;
3518 +               return 0;
3519 +       }
3520 +       connections = count_them(info->data,skb->nh.iph->saddr,info->mask,ct);
3521 +       if (-1 == connections) {
3522 +               printk("ipt_connlimit: Hmm, kmalloc failed :-(\n");
3523 +               *hotdrop = 1; /* let's free some memory :-) */
3524 +               return 0;
3525 +       }
3526 +        match = (info->inverse) ? (connections <= info->limit) : (connections > info->limit);
3527 +#if DEBUG
3528 +       printk("ipt_connlimit: src=%u.%u.%u.%u mask=%u.%u.%u.%u "
3529 +              "connections=%d limit=%d match=%s\n",
3530 +              NIPQUAD(skb->nh.iph->saddr), NIPQUAD(info->mask),
3531 +              connections, info->limit, match ? "yes" : "no");
3532 +#endif
3533 +
3534 +       return match;
3535 +}
3536 +
3537 +static int check(const char *tablename,
3538 +                const struct ipt_ip *ip,
3539 +                void *matchinfo,
3540 +                unsigned int matchsize,
3541 +                unsigned int hook_mask)
3542 +{
3543 +       struct ipt_connlimit_info *info = matchinfo;
3544 +       int i;
3545 +
3546 +       /* verify size */
3547 +       if (matchsize != IPT_ALIGN(sizeof(struct ipt_connlimit_info)))
3548 +               return 0;
3549 +
3550 +       /* refuse anything but tcp */
3551 +       if (ip->proto != IPPROTO_TCP)
3552 +               return 0;
3553 +
3554 +       /* init private data */
3555 +       info->data = kmalloc(sizeof(struct ipt_connlimit_data),GFP_KERNEL);
3556 +       spin_lock_init(&(info->data->lock));
3557 +       for (i = 0; i < 256; i++)
3558 +               INIT_LIST_HEAD(&(info->data->iphash[i]));
3559 +       
3560 +       return 1;
3561 +}
3562 +
3563 +static void destroy(void *matchinfo, unsigned int matchinfosize)
3564 +{
3565 +       struct ipt_connlimit_info *info = matchinfo;
3566 +       struct ipt_connlimit_conn *conn;
3567 +       struct list_head *hash;
3568 +       int i;
3569 +
3570 +       /* cleanup */
3571 +       for (i = 0; i < 256; i++) {
3572 +               hash = &(info->data->iphash[i]);
3573 +               while (hash != hash->next) {
3574 +                       conn = list_entry(hash->next,struct ipt_connlimit_conn,list);
3575 +                       list_del(hash->next);
3576 +                       kfree(conn);
3577 +               }
3578 +       }
3579 +       kfree(info->data);
3580 +}
3581 +
3582 +static struct ipt_match connlimit_match = { 
3583 +       .name = "connlimit",
3584 +       .match = &match,
3585 +       .checkentry = &check,
3586 +       .destroy = &destroy,
3587 +       .me = THIS_MODULE
3588 +};
3589 +
3590 +static int __init init(void)
3591 +{
3592 +       return ipt_register_match(&connlimit_match);
3593 +}
3594 +
3595 +static void __exit fini(void)
3596 +{
3597 +       ipt_unregister_match(&connlimit_match);
3598 +}
3599 +
3600 +module_init(init);
3601 +module_exit(fini);
3602 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
3603 --- linux-2.6.6-rc1.org/net/ipv4/netfilter/ipt_dstlimit.c       1970-01-01 01:00:00.000000000 +0100
3604 +++ linux-2.6.6-rc1/net/ipv4/netfilter/ipt_dstlimit.c   2004-04-19 10:08:30.000000000 +0200
3605 @@ -0,0 +1,690 @@
3606 +/* iptables match extension to limit the number of packets per second
3607 + * seperately for each destination.
3608 + *
3609 + * (C) 2003 by Harald Welte <laforge@netfilter.org>
3610 + *
3611 + * $Id$
3612 + *
3613 + * Development of this code was funded by Astaro AG, http://www.astaro.com/
3614 + *
3615 + * based on ipt_limit.c by:
3616 + * Jérôme de Vivie     <devivie@info.enserb.u-bordeaux.fr>
3617 + * Hervé Eychenne      <eychenne@info.enserb.u-bordeaux.fr>
3618 + * Rusty Russell       <rusty@rustcorp.com.au>
3619 + *
3620 + * The general idea is to create a hash table for every dstip and have a
3621 + * seperate limit counter per tuple.  This way you can do something like 'limit
3622 + * the number of syn packets for each of my internal addresses.
3623 + *
3624 + * Ideally this would just be implemented as a general 'hash' match, which would
3625 + * allow us to attach any iptables target to it's hash buckets.  But this is
3626 + * not possible in the current iptables architecture.  As always, pkttables for
3627 + * 2.7.x will help ;)
3628 + */
3629 +#include <linux/module.h>
3630 +#include <linux/skbuff.h>
3631 +#include <linux/spinlock.h>
3632 +#include <linux/random.h>
3633 +#include <linux/jhash.h>
3634 +#include <linux/slab.h>
3635 +#include <linux/vmalloc.h>
3636 +#include <linux/tcp.h>
3637 +#include <linux/udp.h>
3638 +#include <linux/proc_fs.h>
3639 +#include <linux/seq_file.h>
3640 +
3641 +#define ASSERT_READ_LOCK(x) 
3642 +#define ASSERT_WRITE_LOCK(x) 
3643 +#include <linux/netfilter_ipv4/lockhelp.h>
3644 +#include <linux/netfilter_ipv4/listhelp.h>
3645 +
3646 +#include <linux/netfilter_ipv4/ip_tables.h>
3647 +#include <linux/netfilter_ipv4/ipt_dstlimit.h>
3648 +
3649 +/* FIXME: this is just for IP_NF_ASSERRT */
3650 +#include <linux/netfilter_ipv4/ip_conntrack.h>
3651 +
3652 +#define MS2JIFFIES(x) ((x*HZ)/1000)
3653 +
3654 +MODULE_LICENSE("GPL");
3655 +MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
3656 +MODULE_DESCRIPTION("iptables match for limiting per destination");
3657 +
3658 +/* need to declare this at the top */
3659 +static struct proc_dir_entry *dstlimit_procdir;
3660 +static struct file_operations dl_file_ops;
3661 +
3662 +/* hash table crap */
3663 +
3664 +struct dsthash_dst {
3665 +       u_int32_t src_ip;
3666 +       u_int32_t dst_ip;
3667 +       u_int16_t port;
3668 +};
3669 +
3670 +struct dsthash_ent {
3671 +       /* static / read-only parts in the beginning */
3672 +       struct list_head list;
3673 +       struct dsthash_dst dst;
3674 +
3675 +       /* modified structure members in the end */
3676 +       unsigned long expires;          /* precalculated expiry time */
3677 +       struct {
3678 +               unsigned long prev;     /* last modification */
3679 +               u_int32_t credit;
3680 +               u_int32_t credit_cap, cost;
3681 +       } rateinfo;
3682 +};
3683 +
3684 +struct ipt_dstlimit_htable {
3685 +       struct list_head list;          /* global list of all htables */
3686 +       atomic_t use;
3687 +
3688 +       struct dstlimit_cfg cfg;        /* config */
3689 +
3690 +       /* used internally */
3691 +       spinlock_t lock;                /* lock for list_head */
3692 +       u_int32_t rnd;                  /* random seed for hash */
3693 +       struct timer_list timer;        /* timer for gc */
3694 +       atomic_t count;                 /* number entries in table */
3695 +
3696 +       /* seq_file stuff */
3697 +       struct proc_dir_entry *pde;
3698 +
3699 +       struct list_head hash[0];       /* hashtable itself */
3700 +};
3701 +
3702 +DECLARE_RWLOCK(dstlimit_lock);         /* protects htables list */
3703 +static LIST_HEAD(dstlimit_htables);
3704 +static kmem_cache_t *dstlimit_cachep;
3705 +
3706 +static inline int dst_cmp(const struct dsthash_ent *ent, struct dsthash_dst *b)
3707 +{
3708 +       return (ent->dst.dst_ip == b->dst_ip 
3709 +               && ent->dst.port == b->port
3710 +               && ent->dst.src_ip == b->src_ip);
3711 +}
3712 +
3713 +static inline u_int32_t
3714 +hash_dst(const struct ipt_dstlimit_htable *ht, const struct dsthash_dst *dst)
3715 +{
3716 +       return (jhash_3words(dst->dst_ip, dst->port, 
3717 +                            dst->src_ip, ht->rnd) % ht->cfg.size);
3718 +}
3719 +
3720 +static inline struct dsthash_ent *
3721 +__dsthash_find(const struct ipt_dstlimit_htable *ht, struct dsthash_dst *dst)
3722 +{
3723 +       struct dsthash_ent *ent;
3724 +       u_int32_t hash = hash_dst(ht, dst);
3725 +       MUST_BE_LOCKED(&ht->lock);
3726 +       ent = LIST_FIND(&ht->hash[hash], dst_cmp, struct dsthash_ent *, dst);
3727 +       return ent;
3728 +}
3729 +
3730 +/* allocate dsthash_ent, initialize dst, put in htable and lock it */
3731 +static struct dsthash_ent *
3732 +__dsthash_alloc_init(struct ipt_dstlimit_htable *ht, struct dsthash_dst *dst)
3733 +{
3734 +       struct dsthash_ent *ent;
3735 +
3736 +       /* initialize hash with random val at the time we allocate
3737 +        * the first hashtable entry */
3738 +       if (!ht->rnd)
3739 +               get_random_bytes(&ht->rnd, 4);
3740 +
3741 +       if (ht->cfg.max &&
3742 +           atomic_read(&ht->count) >= ht->cfg.max) {
3743 +               /* FIXME: do something. question is what.. */
3744 +               if (net_ratelimit())
3745 +                       printk(KERN_WARNING 
3746 +                               "ipt_dstlimit: max count of %u reached\n", 
3747 +                               ht->cfg.max);
3748 +               return NULL;
3749 +       }
3750 +
3751 +       ent = kmem_cache_alloc(dstlimit_cachep, GFP_ATOMIC);
3752 +       if (!ent) {
3753 +               if (net_ratelimit())
3754 +                       printk(KERN_ERR 
3755 +                               "ipt_dstlimit: can't allocate dsthash_ent\n");
3756 +               return NULL;
3757 +       }
3758 +
3759 +       atomic_inc(&ht->count);
3760 +
3761 +       ent->dst.dst_ip = dst->dst_ip;
3762 +       ent->dst.port = dst->port;
3763 +       ent->dst.src_ip = dst->src_ip;
3764 +
3765 +       list_add(&ent->list, &ht->hash[hash_dst(ht, dst)]);
3766 +
3767 +       return ent;
3768 +}
3769 +
3770 +static inline void 
3771 +__dsthash_free(struct ipt_dstlimit_htable *ht, struct dsthash_ent *ent)
3772 +{
3773 +       MUST_BE_LOCKED(&ht->lock);
3774 +
3775 +       list_del(&ent->list);
3776 +       kmem_cache_free(dstlimit_cachep, ent);
3777 +       atomic_dec(&ht->count);
3778 +}
3779 +static void htable_gc(unsigned long htlong);
3780 +
3781 +static int htable_create(struct ipt_dstlimit_info *minfo)
3782 +{
3783 +       int i;
3784 +       unsigned int size;
3785 +       struct ipt_dstlimit_htable *hinfo;
3786 +
3787 +       if (minfo->cfg.size)
3788 +               size = minfo->cfg.size;
3789 +       else {
3790 +               size = (((num_physpages << PAGE_SHIFT) / 16384)
3791 +                        / sizeof(struct list_head));
3792 +               if (num_physpages > (1024 * 1024 * 1024 / PAGE_SIZE))
3793 +                       size = 8192;
3794 +               if (size < 16)
3795 +                       size = 16;
3796 +       }
3797 +       /* FIXME: don't use vmalloc() here or anywhere else -HW */
3798 +       hinfo = vmalloc(sizeof(struct ipt_dstlimit_htable)
3799 +                       + (sizeof(struct list_head) * size));
3800 +       if (!hinfo) {
3801 +               printk(KERN_ERR "ipt_dstlimit: Unable to create hashtable\n");
3802 +               return -1;
3803 +       }
3804 +       minfo->hinfo = hinfo;
3805 +
3806 +       /* copy match config into hashtable config */
3807 +       memcpy(&hinfo->cfg, &minfo->cfg, sizeof(hinfo->cfg));
3808 +       hinfo->cfg.size = size;
3809 +       if (!hinfo->cfg.max)
3810 +               hinfo->cfg.max = 8 * hinfo->cfg.size;
3811 +       else if (hinfo->cfg.max < hinfo->cfg.size)
3812 +               hinfo->cfg.max = hinfo->cfg.size;
3813 +
3814 +       for (i = 0; i < hinfo->cfg.size; i++)
3815 +               INIT_LIST_HEAD(&hinfo->hash[i]);
3816 +
3817 +       atomic_set(&hinfo->count, 0);
3818 +       atomic_set(&hinfo->use, 1);
3819 +       hinfo->rnd = 0;
3820 +       hinfo->lock = SPIN_LOCK_UNLOCKED;
3821 +       hinfo->pde = create_proc_entry(minfo->name, 0, dstlimit_procdir);
3822 +       if (!hinfo->pde) {
3823 +               vfree(hinfo);
3824 +               return -1;
3825 +       }
3826 +       hinfo->pde->proc_fops = &dl_file_ops;
3827 +       hinfo->pde->data = hinfo;
3828 +
3829 +       init_timer(&hinfo->timer);
3830 +       hinfo->timer.expires = jiffies + MS2JIFFIES(hinfo->cfg.gc_interval);
3831 +       hinfo->timer.data = (unsigned long )hinfo;
3832 +       hinfo->timer.function = htable_gc;
3833 +       add_timer(&hinfo->timer);
3834 +
3835 +       WRITE_LOCK(&dstlimit_lock);
3836 +       list_add(&hinfo->list, &dstlimit_htables);
3837 +       WRITE_UNLOCK(&dstlimit_lock);
3838 +
3839 +       return 0;
3840 +}
3841 +
3842 +static int select_all(struct ipt_dstlimit_htable *ht, struct dsthash_ent *he)
3843 +{
3844 +       return 1;
3845 +}
3846 +
3847 +static int select_gc(struct ipt_dstlimit_htable *ht, struct dsthash_ent *he)
3848 +{
3849 +       return (jiffies >= he->expires);
3850 +}
3851 +
3852 +static void htable_selective_cleanup(struct ipt_dstlimit_htable *ht,
3853 +                               int (*select)(struct ipt_dstlimit_htable *ht, 
3854 +                                             struct dsthash_ent *he))
3855 +{
3856 +       int i;
3857 +
3858 +       IP_NF_ASSERT(ht->cfg.size && ht->cfg.max);
3859 +
3860 +       /* lock hash table and iterate over it */
3861 +       LOCK_BH(&ht->lock);
3862 +       for (i = 0; i < ht->cfg.size; i++) {
3863 +               struct dsthash_ent *dh, *n;
3864 +               list_for_each_entry_safe(dh, n, &ht->hash[i], list) {
3865 +                       if ((*select)(ht, dh))
3866 +                               __dsthash_free(ht, dh);
3867 +               }
3868 +       }
3869 +       UNLOCK_BH(&ht->lock);
3870 +}
3871 +
3872 +/* hash table garbage collector, run by timer */
3873 +static void htable_gc(unsigned long htlong)
3874 +{
3875 +       struct ipt_dstlimit_htable *ht = (struct ipt_dstlimit_htable *)htlong;
3876 +
3877 +       htable_selective_cleanup(ht, select_gc);
3878 +
3879 +       /* re-add the timer accordingly */
3880 +       ht->timer.expires = jiffies + MS2JIFFIES(ht->cfg.gc_interval);
3881 +       add_timer(&ht->timer);
3882 +}
3883 +
3884 +static void htable_destroy(struct ipt_dstlimit_htable *hinfo)
3885 +{
3886 +       /* remove timer, if it is pending */
3887 +       if (timer_pending(&hinfo->timer))
3888 +               del_timer(&hinfo->timer);
3889 +
3890 +       /* remove proc entry */
3891 +       remove_proc_entry(hinfo->pde->name, dstlimit_procdir);
3892 +
3893 +       htable_selective_cleanup(hinfo, select_all);
3894 +       vfree(hinfo);
3895 +}
3896 +
3897 +static struct ipt_dstlimit_htable *htable_find_get(char *name)
3898 +{
3899 +       struct ipt_dstlimit_htable *hinfo;
3900 +
3901 +       READ_LOCK(&dstlimit_lock);
3902 +       list_for_each_entry(hinfo, &dstlimit_htables, list) {
3903 +               if (!strcmp(name, hinfo->pde->name)) {
3904 +                       atomic_inc(&hinfo->use);
3905 +                       READ_UNLOCK(&dstlimit_lock);
3906 +                       return hinfo;
3907 +               }
3908 +       }
3909 +       READ_UNLOCK(&dstlimit_lock);
3910 +
3911 +       return NULL;
3912 +}
3913 +
3914 +static void htable_put(struct ipt_dstlimit_htable *hinfo)
3915 +{
3916 +       if (atomic_dec_and_test(&hinfo->use)) {
3917 +               WRITE_LOCK(&dstlimit_lock);
3918 +               list_del(&hinfo->list);
3919 +               WRITE_UNLOCK(&dstlimit_lock);
3920 +               htable_destroy(hinfo);
3921 +       }
3922 +}
3923 +
3924 +
3925 +/* The algorithm used is the Simple Token Bucket Filter (TBF)
3926 + * see net/sched/sch_tbf.c in the linux source tree
3927 + */
3928 +
3929 +/* Rusty: This is my (non-mathematically-inclined) understanding of
3930 +   this algorithm.  The `average rate' in jiffies becomes your initial
3931 +   amount of credit `credit' and the most credit you can ever have
3932 +   `credit_cap'.  The `peak rate' becomes the cost of passing the
3933 +   test, `cost'.
3934 +
3935 +   `prev' tracks the last packet hit: you gain one credit per jiffy.
3936 +   If you get credit balance more than this, the extra credit is
3937 +   discarded.  Every time the match passes, you lose `cost' credits;
3938 +   if you don't have that many, the test fails.
3939 +
3940 +   See Alexey's formal explanation in net/sched/sch_tbf.c.
3941 +
3942 +   To get the maximum range, we multiply by this factor (ie. you get N
3943 +   credits per jiffy).  We want to allow a rate as low as 1 per day
3944 +   (slowest userspace tool allows), which means
3945 +   CREDITS_PER_JIFFY*HZ*60*60*24 < 2^32 ie.
3946 +*/
3947 +#define MAX_CPJ (0xFFFFFFFF / (HZ*60*60*24))
3948 +
3949 +/* Repeated shift and or gives us all 1s, final shift and add 1 gives
3950 + * us the power of 2 below the theoretical max, so GCC simply does a
3951 + * shift. */
3952 +#define _POW2_BELOW2(x) ((x)|((x)>>1))
3953 +#define _POW2_BELOW4(x) (_POW2_BELOW2(x)|_POW2_BELOW2((x)>>2))
3954 +#define _POW2_BELOW8(x) (_POW2_BELOW4(x)|_POW2_BELOW4((x)>>4))
3955 +#define _POW2_BELOW16(x) (_POW2_BELOW8(x)|_POW2_BELOW8((x)>>8))
3956 +#define _POW2_BELOW32(x) (_POW2_BELOW16(x)|_POW2_BELOW16((x)>>16))
3957 +#define POW2_BELOW32(x) ((_POW2_BELOW32(x)>>1) + 1)
3958 +
3959 +#define CREDITS_PER_JIFFY POW2_BELOW32(MAX_CPJ)
3960 +
3961 +/* Precision saver. */
3962 +static inline u_int32_t
3963 +user2credits(u_int32_t user)
3964 +{
3965 +       /* If multiplying would overflow... */
3966 +       if (user > 0xFFFFFFFF / (HZ*CREDITS_PER_JIFFY))
3967 +               /* Divide first. */
3968 +               return (user / IPT_DSTLIMIT_SCALE) * HZ * CREDITS_PER_JIFFY;
3969 +
3970 +       return (user * HZ * CREDITS_PER_JIFFY) / IPT_DSTLIMIT_SCALE;
3971 +}
3972 +
3973 +static inline void rateinfo_recalc(struct dsthash_ent *dh, unsigned long now)
3974 +{
3975 +       dh->rateinfo.credit += (now - xchg(&dh->rateinfo.prev, now)) 
3976 +                                       * CREDITS_PER_JIFFY;
3977 +       if (dh->rateinfo.credit > dh->rateinfo.credit_cap)
3978 +               dh->rateinfo.credit = dh->rateinfo.credit_cap;
3979 +}
3980 +
3981 +static int
3982 +dstlimit_match(const struct sk_buff *skb,
3983 +               const struct net_device *in,
3984 +               const struct net_device *out,
3985 +               const void *matchinfo,
3986 +               int offset,
3987 +               int *hotdrop)
3988 +{
3989 +       struct ipt_dstlimit_info *r = 
3990 +               ((struct ipt_dstlimit_info *)matchinfo)->u.master;
3991 +       struct ipt_dstlimit_htable *hinfo = r->hinfo;
3992 +       unsigned long now = jiffies;
3993 +       struct dsthash_ent *dh;
3994 +       struct dsthash_dst dst;
3995 +
3996 +       memset(&dst, 0, sizeof(dst));
3997 +
3998 +       /* dest ip is always in hash */
3999 +       dst.dst_ip = skb->nh.iph->daddr;
4000 +
4001 +       /* source ip only if respective hashmode, otherwise set to
4002 +        * zero */
4003 +       if (hinfo->cfg.mode & IPT_DSTLIMIT_HASH_SIP)
4004 +               dst.src_ip = skb->nh.iph->saddr;
4005 +
4006 +       /* dest port only if respective mode */
4007 +       if (hinfo->cfg.mode & IPT_DSTLIMIT_HASH_DPT) {
4008 +               u16 ports[2];
4009 +
4010 +               /* Must not be a fragment. */
4011 +               if (offset)
4012 +                       return 0;
4013 +
4014 +               /* Must be big enough to read ports (both UDP and TCP have
4015 +                  them at the start). */
4016 +               if (skb_copy_bits(skb, skb->nh.iph->ihl*4, ports, sizeof(ports)) < 0) {
4017 +                       /* We've been asked to examine this packet, and we
4018 +                          can't.  Hence, no choice but to drop. */
4019 +                       *hotdrop = 1;
4020 +                       return 0;
4021 +               }
4022 +
4023 +               switch (skb->nh.iph->protocol) {
4024 +                       struct tcphdr *th;
4025 +                       struct udphdr *uh;
4026 +               case IPPROTO_TCP:
4027 +                       th = (void *)skb->nh.iph+skb->nh.iph->ihl*4;
4028 +                       dst.port = th->dest;
4029 +                       break;
4030 +               case IPPROTO_UDP:
4031 +                       uh = (void *)skb->nh.iph+skb->nh.iph->ihl*4;
4032 +                       dst.port = uh->dest;
4033 +                       break;
4034 +               default:
4035 +                       break;
4036 +               }
4037 +       } 
4038 +
4039 +       LOCK_BH(&hinfo->lock);
4040 +       dh = __dsthash_find(hinfo, &dst);
4041 +       if (!dh) {
4042 +               dh = __dsthash_alloc_init(hinfo, &dst);
4043 +
4044 +               if (!dh) {
4045 +                       /* enomem... don't match == DROP */
4046 +                       if (net_ratelimit())
4047 +                               printk(KERN_ERR "%s: ENOMEM\n", __FUNCTION__);
4048 +                       UNLOCK_BH(&hinfo->lock);
4049 +                       return 0;
4050 +               }
4051 +
4052 +               dh->expires = jiffies + MS2JIFFIES(hinfo->cfg.expire);
4053 +
4054 +               dh->rateinfo.prev = jiffies;
4055 +               dh->rateinfo.credit = user2credits(hinfo->cfg.avg * 
4056 +                                                       hinfo->cfg.burst);
4057 +               dh->rateinfo.credit_cap = user2credits(hinfo->cfg.avg * 
4058 +                                                       hinfo->cfg.burst);
4059 +               dh->rateinfo.cost = user2credits(hinfo->cfg.avg);
4060 +
4061 +               UNLOCK_BH(&hinfo->lock);
4062 +               return 1;
4063 +       }
4064 +
4065 +       /* update expiration timeout */
4066 +       dh->expires = now + MS2JIFFIES(hinfo->cfg.expire);
4067 +
4068 +       rateinfo_recalc(dh, now);
4069 +       if (dh->rateinfo.credit >= dh->rateinfo.cost) {
4070 +               /* We're underlimit. */
4071 +               dh->rateinfo.credit -= dh->rateinfo.cost;
4072 +               UNLOCK_BH(&hinfo->lock);
4073 +               return 1;
4074 +       }
4075 +
4076 +               UNLOCK_BH(&hinfo->lock);
4077 +
4078 +       /* default case: we're overlimit, thus don't match */
4079 +       return 0;
4080 +}
4081 +
4082 +static int
4083 +dstlimit_checkentry(const char *tablename,
4084 +                    const struct ipt_ip *ip,
4085 +                    void *matchinfo,
4086 +                    unsigned int matchsize,
4087 +                    unsigned int hook_mask)
4088 +{
4089 +       struct ipt_dstlimit_info *r = matchinfo;
4090 +
4091 +       if (matchsize != IPT_ALIGN(sizeof(struct ipt_dstlimit_info)))
4092 +               return 0;
4093 +
4094 +       /* Check for overflow. */
4095 +       if (r->cfg.burst == 0
4096 +           || user2credits(r->cfg.avg * r->cfg.burst) < 
4097 +                                       user2credits(r->cfg.avg)) {
4098 +               printk(KERN_ERR "ipt_dstlimit: Overflow, try lower: %u/%u\n",
4099 +                      r->cfg.avg, r->cfg.burst);
4100 +               return 0;
4101 +       }
4102 +
4103 +       if (r->cfg.mode == 0 
4104 +           || r->cfg.mode > (IPT_DSTLIMIT_HASH_DPT
4105 +                         |IPT_DSTLIMIT_HASH_DIP
4106 +                         |IPT_DSTLIMIT_HASH_SIP))
4107 +               return 0;
4108 +
4109 +       if (!r->cfg.gc_interval)
4110 +               return 0;
4111 +       
4112 +       if (!r->cfg.expire)
4113 +               return 0;
4114 +
4115 +       r->hinfo = htable_find_get(r->name);
4116 +       if (!r->hinfo && (htable_create(r) != 0)) {
4117 +               return 0;
4118 +       }
4119 +
4120 +       /* Ugly hack: For SMP, we only want to use one set */
4121 +       r->u.master = r;
4122 +
4123 +       return 1;
4124 +}
4125 +
4126 +static void
4127 +dstlimit_destroy(void *matchinfo, unsigned int matchsize)
4128 +{
4129 +       struct ipt_dstlimit_info *r = (struct ipt_dstlimit_info *) matchinfo;
4130 +
4131 +       htable_put(r->hinfo);
4132 +}
4133 +
4134 +static struct ipt_match ipt_dstlimit = { 
4135 +       .list = { .prev = NULL, .next = NULL }, 
4136 +       .name = "dstlimit", 
4137 +       .match = dstlimit_match, 
4138 +       .checkentry = dstlimit_checkentry, 
4139 +       .destroy = dstlimit_destroy,
4140 +       .me = THIS_MODULE 
4141 +};
4142 +
4143 +/* PROC stuff */
4144 +
4145 +static void *dl_seq_start(struct seq_file *s, loff_t *pos)
4146 +{
4147 +       struct proc_dir_entry *pde = s->private;
4148 +       struct ipt_dstlimit_htable *htable = pde->data;
4149 +       unsigned int *bucket;
4150 +
4151 +       LOCK_BH(&htable->lock);
4152 +       if (*pos >= htable->cfg.size)
4153 +               return NULL;
4154 +
4155 +       bucket = kmalloc(sizeof(unsigned int), GFP_KERNEL);
4156 +       if (!bucket)
4157 +               return ERR_PTR(-ENOMEM);
4158 +
4159 +       *bucket = *pos;
4160 +       return bucket;
4161 +}
4162 +
4163 +static void *dl_seq_next(struct seq_file *s, void *v, loff_t *pos)
4164 +{
4165 +       struct proc_dir_entry *pde = s->private;
4166 +       struct ipt_dstlimit_htable *htable = pde->data;
4167 +       unsigned int *bucket = (unsigned int *)v;
4168 +
4169 +       *pos = ++(*bucket);
4170 +       if (*pos >= htable->cfg.size) {
4171 +               kfree(v);
4172 +               return NULL;
4173 +       }
4174 +       return bucket;
4175 +}
4176 +
4177 +static void dl_seq_stop(struct seq_file *s, void *v)
4178 +{
4179 +       struct proc_dir_entry *pde = s->private;
4180 +       struct ipt_dstlimit_htable *htable = pde->data;
4181 +       unsigned int *bucket = (unsigned int *)v;
4182 +
4183 +       kfree(bucket);
4184 +
4185 +       UNLOCK_BH(&htable->lock);
4186 +}
4187 +
4188 +static inline int dl_seq_real_show(struct dsthash_ent *ent, struct seq_file *s)
4189 +{
4190 +       /* recalculate to show accurate numbers */
4191 +       rateinfo_recalc(ent, jiffies);
4192 +
4193 +       return seq_printf(s, "%ld %u.%u.%u.%u->%u.%u.%u.%u:%u %u %u %u\n",
4194 +                       (ent->expires - jiffies)/HZ,
4195 +                       NIPQUAD(ent->dst.src_ip),
4196 +                       NIPQUAD(ent->dst.dst_ip), ntohs(ent->dst.port),
4197 +                       ent->rateinfo.credit, ent->rateinfo.credit_cap,
4198 +                       ent->rateinfo.cost);
4199 +}
4200 +
4201 +static int dl_seq_show(struct seq_file *s, void *v)
4202 +{
4203 +       struct proc_dir_entry *pde = s->private;
4204 +       struct ipt_dstlimit_htable *htable = pde->data;
4205 +       unsigned int *bucket = (unsigned int *)v;
4206 +
4207 +       if (LIST_FIND_W(&htable->hash[*bucket], dl_seq_real_show,
4208 +                     struct dsthash_ent *, s)) {
4209 +               /* buffer was filled and unable to print that tuple */
4210 +               return 1;
4211 +       }
4212 +       return 0;
4213 +}
4214 +
4215 +static struct seq_operations dl_seq_ops = {
4216 +       .start = dl_seq_start,
4217 +       .next  = dl_seq_next,
4218 +       .stop  = dl_seq_stop,
4219 +       .show  = dl_seq_show
4220 +};
4221 +
4222 +static int dl_proc_open(struct inode *inode, struct file *file)
4223 +{
4224 +       int ret = seq_open(file, &dl_seq_ops);
4225 +
4226 +       if (!ret) {
4227 +               struct seq_file *sf = file->private_data;
4228 +               sf->private = PDE(inode);
4229 +       }
4230 +       return ret;
4231 +}
4232 +
4233 +static struct file_operations dl_file_ops = {
4234 +       .owner   = THIS_MODULE,
4235 +       .open    = dl_proc_open,
4236 +       .read    = seq_read,
4237 +       .llseek  = seq_lseek,
4238 +       .release = seq_release
4239 +};
4240 +
4241 +static int init_or_fini(int fini)
4242 +{
4243 +       int ret = 0;
4244 +
4245 +       if (fini)
4246 +               goto cleanup;
4247 +
4248 +       if (ipt_register_match(&ipt_dstlimit)) {
4249 +               ret = -EINVAL;
4250 +               goto cleanup_nothing;
4251 +       }
4252 +
4253 +       /* FIXME: do we really want HWCACHE_ALIGN since our objects are
4254 +        * quite small ? */
4255 +       dstlimit_cachep = kmem_cache_create("ipt_dstlimit",
4256 +                                           sizeof(struct dsthash_ent), 0,
4257 +                                           SLAB_HWCACHE_ALIGN, NULL, NULL);
4258 +       if (!dstlimit_cachep) {
4259 +               printk(KERN_ERR "Unable to create ipt_dstlimit slab cache\n");
4260 +               ret = -ENOMEM;
4261 +               goto cleanup_unreg_match;
4262 +       }
4263 +
4264 +       dstlimit_procdir = proc_mkdir("ipt_dstlimit", proc_net);
4265 +       if (!dstlimit_procdir) {
4266 +               printk(KERN_ERR "Unable to create proc dir entry\n");
4267 +               ret = -ENOMEM;
4268 +               goto cleanup_free_slab;
4269 +       }
4270 +
4271 +       return ret;
4272 +
4273 +cleanup:
4274 +       remove_proc_entry("ipt_dstlimit", proc_net);
4275 +cleanup_free_slab:
4276 +       kmem_cache_destroy(dstlimit_cachep);
4277 +cleanup_unreg_match:
4278 +       ipt_unregister_match(&ipt_dstlimit);
4279 +cleanup_nothing:
4280 +       return ret;
4281 +       
4282 +}
4283 +
4284 +static int __init init(void)
4285 +{
4286 +       return init_or_fini(0);
4287 +}
4288 +
4289 +static void __exit fini(void)
4290 +{
4291 +       init_or_fini(1);
4292 +}
4293 +
4294 +module_init(init);
4295 +module_exit(fini);
4296 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
4297 --- linux-2.6.6-rc1.org/net/ipv4/netfilter/ipt_fuzzy.c  1970-01-01 01:00:00.000000000 +0100
4298 +++ linux-2.6.6-rc1/net/ipv4/netfilter/ipt_fuzzy.c      2004-04-19 10:08:31.000000000 +0200
4299 @@ -0,0 +1,185 @@
4300 +/*
4301 + *  This module implements a simple TSK FLC 
4302 + * (Takagi-Sugeno-Kang Fuzzy Logic Controller) that aims
4303 + * to limit , in an adaptive and flexible way , the packet rate crossing 
4304 + * a given stream . It serves as an initial and very simple (but effective)
4305 + * example of how Fuzzy Logic techniques can be applied to defeat DoS attacks.
4306 + *  As a matter of fact , Fuzzy Logic can help us to insert any "behavior"  
4307 + * into our code in a precise , adaptive and efficient manner. 
4308 + *  The goal is very similar to that of "limit" match , but using techniques of
4309 + * Fuzzy Control , that allow us to shape the transfer functions precisely ,
4310 + * avoiding over and undershoots - and stuff like that .
4311 + *
4312 + *
4313 + * 2002-08-10  Hime Aguiar e Oliveira Jr. <hime@engineer.com> : Initial version.
4314 + * 2002-08-17  : Changed to eliminate floating point operations .
4315 + * 2002-08-23  : Coding style changes .
4316 +*/
4317 +
4318 +#include <linux/module.h>
4319 +#include <linux/skbuff.h>
4320 +#include <linux/ip.h>
4321 +#include <linux/random.h>
4322 +#include <net/tcp.h>
4323 +#include <linux/spinlock.h>
4324 +#include <linux/netfilter_ipv4/ip_tables.h>
4325 +#include <linux/netfilter_ipv4/ipt_fuzzy.h>
4326 +
4327 +/*
4328 + Packet Acceptance Rate - LOW and Packet Acceptance Rate - HIGH
4329 + Expressed in percentage
4330 +*/
4331 +
4332 +#define PAR_LOW                1/100
4333 +#define PAR_HIGH       1
4334 +
4335 +static spinlock_t fuzzy_lock = SPIN_LOCK_UNLOCKED ;
4336 +
4337 +MODULE_AUTHOR("Hime Aguiar e Oliveira Junior <hime@engineer.com>");
4338 +MODULE_DESCRIPTION("IP tables Fuzzy Logic Controller match module");
4339 +MODULE_LICENSE("GPL");
4340 +
4341 +static  u_int8_t mf_high(u_int32_t tx,u_int32_t mini,u_int32_t maxi)
4342 +{
4343 +       if (tx >= maxi)
4344 +               return 100;
4345 +
4346 +       if (tx <= mini)
4347 +               return 0;
4348 +
4349 +       return ( (100*(tx-mini)) / (maxi-mini) );
4350 +}
4351 +
4352 +static u_int8_t mf_low(u_int32_t tx,u_int32_t mini,u_int32_t maxi)
4353 +{
4354 +       if (tx <= mini)
4355 +               return 100;
4356 +
4357 +       if (tx >= maxi)
4358 +               return 0;
4359 +
4360 +       return ( (100*( maxi - tx ))  / ( maxi - mini ) );
4361 +}
4362 +
4363 +static int
4364 +ipt_fuzzy_match(const struct sk_buff *pskb,
4365 +              const struct net_device *in,
4366 +              const struct net_device *out,
4367 +              const void *matchinfo,
4368 +              int offset,
4369 +              int *hotdrop)
4370 +{
4371 +       /* From userspace */
4372 +       
4373 +       struct ipt_fuzzy_info *info = (struct ipt_fuzzy_info *) matchinfo;
4374 +
4375 +       u_int8_t random_number;
4376 +       unsigned long amount;
4377 +       u_int8_t howhigh, howlow;
4378 +       
4379 +
4380 +       spin_lock_bh(&fuzzy_lock); /* Rise the lock */
4381 +
4382 +       info->bytes_total += pskb->len;
4383 +       info->packets_total++;
4384 +
4385 +       info->present_time = jiffies;
4386 +       
4387 +       if (info->present_time >= info->previous_time)
4388 +               amount = info->present_time - info->previous_time;
4389 +       else { 
4390 +               /* There was a transition : I choose to re-sample 
4391 +                  and keep the old acceptance rate...
4392 +               */
4393 +
4394 +               amount = 0;
4395 +               info->previous_time = info->present_time;
4396 +               info->bytes_total = info->packets_total = 0;
4397 +       };
4398 +       
4399 +       if (amount > HZ/10) /* More than 100 ms elapsed ... */
4400 +       {
4401 +
4402 +               info->mean_rate = (u_int32_t) ((HZ*info->packets_total)  \
4403 +                                       / amount );
4404 +
4405 +               info->previous_time = info->present_time;
4406 +               info->bytes_total = info->packets_total = 0;
4407 +
4408 +               howhigh = mf_high(info->mean_rate,info->minimum_rate,info->maximum_rate);
4409 +               howlow  = mf_low(info->mean_rate,info->minimum_rate,info->maximum_rate);
4410 +
4411 +               info->acceptance_rate = (u_int8_t) \
4412 +                          (howhigh*PAR_LOW + PAR_HIGH*howlow);
4413 +
4414 +               /* In fact , the above defuzzification would require a denominator
4415 +                  proportional to (howhigh+howlow) but , in this particular case ,
4416 +                  that expression is constant .
4417 +                  An imediate consequence is that it isn't necessary to call 
4418 +                  both mf_high and mf_low - but to keep things understandable ,
4419 +                  I did so .  */ 
4420 +
4421 +       }
4422 +       
4423 +       spin_unlock_bh(&fuzzy_lock); /* Release the lock */
4424 +
4425 +
4426 +       if ( info->acceptance_rate < 100 )
4427 +       {                
4428 +               get_random_bytes((void *)(&random_number), 1);
4429 +
4430 +               /*  If within the acceptance , it can pass => don't match */
4431 +               if (random_number <= (255 * info->acceptance_rate) / 100)
4432 +                       return 0;
4433 +               else
4434 +                       return 1; /* It can't pass ( It matches ) */
4435 +       } ;
4436 +
4437 +       return 0; /* acceptance_rate == 100 % => Everything passes ... */
4438 +       
4439 +}
4440 +
4441 +static int
4442 +ipt_fuzzy_checkentry(const char *tablename,
4443 +                  const struct ipt_ip *e,
4444 +                  void *matchinfo,
4445 +                  unsigned int matchsize,
4446 +                  unsigned int hook_mask)
4447 +{
4448 +       
4449 +       const struct ipt_fuzzy_info *info = matchinfo;
4450 +
4451 +       if (matchsize != IPT_ALIGN(sizeof(struct ipt_fuzzy_info))) {
4452 +               printk("ipt_fuzzy: matchsize %u != %u\n", matchsize,
4453 +                      IPT_ALIGN(sizeof(struct ipt_fuzzy_info)));
4454 +               return 0;
4455 +       }
4456 +
4457 +       if ((info->minimum_rate < MINFUZZYRATE ) || (info->maximum_rate > MAXFUZZYRATE)
4458 +           || (info->minimum_rate >= info->maximum_rate )) {
4459 +               printk("ipt_fuzzy: BAD limits , please verify !!!\n");
4460 +               return 0;
4461 +       }
4462 +
4463 +       return 1;
4464 +}
4465 +
4466 +static struct ipt_match ipt_fuzzy_reg = { 
4467 +       .name = "fuzzy",
4468 +       .match = ipt_fuzzy_match,
4469 +       .checkentry = ipt_fuzzy_checkentry,
4470 +       .me = THIS_MODULE
4471 +};
4472 +
4473 +static int __init init(void)
4474 +{
4475 +       return ipt_register_match(&ipt_fuzzy_reg);
4476 +}
4477 +
4478 +static void __exit fini(void)
4479 +{
4480 +       ipt_unregister_match(&ipt_fuzzy_reg);
4481 +}
4482 +
4483 +module_init(init);
4484 +module_exit(fini);
4485 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
4486 --- linux-2.6.6-rc1.org/net/ipv4/netfilter/ipt_helper.c 2004-04-15 03:35:20.000000000 +0200
4487 +++ linux-2.6.6-rc1/net/ipv4/netfilter/ipt_helper.c     2004-04-19 10:08:23.000000000 +0200
4488 @@ -41,17 +41,17 @@
4489         struct ip_conntrack_expect *exp;
4490         struct ip_conntrack *ct;
4491         enum ip_conntrack_info ctinfo;
4492 -       int ret = 0;
4493 +       int ret = info->invert;
4494         
4495         ct = ip_conntrack_get((struct sk_buff *)skb, &ctinfo);
4496         if (!ct) {
4497                 DEBUGP("ipt_helper: Eek! invalid conntrack?\n");
4498 -               return 0;
4499 +               return ret;
4500         }
4501  
4502         if (!ct->master) {
4503                 DEBUGP("ipt_helper: conntrack %p has no master\n", ct);
4504 -               return 0;
4505 +               return ret;
4506         }
4507  
4508         exp = ct->master;
4509 @@ -71,8 +71,8 @@
4510         DEBUGP("master's name = %s , info->name = %s\n", 
4511                 exp->expectant->helper->name, info->name);
4512  
4513 -       ret = !strncmp(exp->expectant->helper->name, info->name, 
4514 -                      strlen(exp->expectant->helper->name)) ^ info->invert;
4515 +       ret ^= !strncmp(exp->expectant->helper->name, info->name, 
4516 +                       strlen(exp->expectant->helper->name));
4517  out_unlock:
4518         READ_UNLOCK(&ip_conntrack_lock);
4519         return ret;
4520 @@ -108,7 +108,6 @@
4521  
4522  static int __init init(void)
4523  {
4524 -       need_ip_conntrack();
4525         return ipt_register_match(&helper_match);
4526  }
4527  
4528 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
4529 --- linux-2.6.6-rc1.org/net/ipv4/netfilter/ipt_ipv4options.c    1970-01-01 01:00:00.000000000 +0100
4530 +++ linux-2.6.6-rc1/net/ipv4/netfilter/ipt_ipv4options.c        2004-04-19 10:08:32.000000000 +0200
4531 @@ -0,0 +1,172 @@
4532 +/*
4533 +  This is a module which is used to match ipv4 options.
4534 +  This file is distributed under the terms of the GNU General Public
4535 +  License (GPL). Copies of the GPL can be obtained from:
4536 +  ftp://prep.ai.mit.edu/pub/gnu/GPL
4537 +
4538 +  11-mars-2001 Fabrice MARIE <fabrice@netfilter.org> : initial development.
4539 +  12-july-2001 Fabrice MARIE <fabrice@netfilter.org> : added router-alert otions matching. Fixed a bug with no-srr
4540 +  12-august-2001 Imran Patel <ipatel@crosswinds.net> : optimization of the match.
4541 +  18-november-2001 Fabrice MARIE <fabrice@netfilter.org> : added [!] 'any' option match.
4542 +  19-february-2004 Harald Welte <laforge@netfilter.org> : merge with 2.6.x
4543 +*/
4544 +
4545 +#include <linux/module.h>
4546 +#include <linux/skbuff.h>
4547 +#include <net/ip.h>
4548 +
4549 +#include <linux/netfilter_ipv4/ip_tables.h>
4550 +#include <linux/netfilter_ipv4/ipt_ipv4options.h>
4551 +
4552 +MODULE_LICENSE("GPL");
4553 +MODULE_AUTHOR("Fabrice Marie <fabrice@netfilter.org>");
4554 +
4555 +static int
4556 +match(const struct sk_buff *skb,
4557 +      const struct net_device *in,
4558 +      const struct net_device *out,
4559 +      const void *matchinfo,
4560 +      int offset,
4561 +      int *hotdrop)
4562 +{
4563 +       const struct ipt_ipv4options_info *info = matchinfo;   /* match info for rule */
4564 +       const struct iphdr *iph = skb->nh.iph;
4565 +       const struct ip_options *opt;
4566 +
4567 +       if (iph->ihl * 4 == sizeof(struct iphdr)) {
4568 +               /* No options, so we match only the "DONTs" and the "IGNOREs" */
4569 +
4570 +               if (((info->options & IPT_IPV4OPTION_MATCH_ANY_OPT) == IPT_IPV4OPTION_MATCH_ANY_OPT) ||
4571 +                   ((info->options & IPT_IPV4OPTION_MATCH_SSRR) == IPT_IPV4OPTION_MATCH_SSRR) ||
4572 +                   ((info->options & IPT_IPV4OPTION_MATCH_LSRR) == IPT_IPV4OPTION_MATCH_LSRR) ||
4573 +                   ((info->options & IPT_IPV4OPTION_MATCH_RR) == IPT_IPV4OPTION_MATCH_RR) ||
4574 +                   ((info->options & IPT_IPV4OPTION_MATCH_TIMESTAMP) == IPT_IPV4OPTION_MATCH_TIMESTAMP) ||
4575 +                    ((info->options & IPT_IPV4OPTION_MATCH_ROUTER_ALERT) == IPT_IPV4OPTION_MATCH_ROUTER_ALERT))
4576 +                       return 0;
4577 +               return 1;
4578 +       }
4579 +       else {
4580 +               if ((info->options & IPT_IPV4OPTION_MATCH_ANY_OPT) == IPT_IPV4OPTION_MATCH_ANY_OPT)
4581 +                       /* there are options, and we don't need to care which one */
4582 +                       return 1;
4583 +               else {
4584 +                       if ((info->options & IPT_IPV4OPTION_DONT_MATCH_ANY_OPT) == IPT_IPV4OPTION_DONT_MATCH_ANY_OPT)
4585 +                               /* there are options but we don't want any ! */
4586 +                               return 0;
4587 +               }
4588 +       }
4589 +
4590 +       opt = &(IPCB(skb)->opt);
4591 +
4592 +       /* source routing */
4593 +       if ((info->options & IPT_IPV4OPTION_MATCH_SSRR) == IPT_IPV4OPTION_MATCH_SSRR) {
4594 +               if (!((opt->srr) & (opt->is_strictroute)))
4595 +                       return 0;
4596 +       }
4597 +       else if ((info->options & IPT_IPV4OPTION_MATCH_LSRR) == IPT_IPV4OPTION_MATCH_LSRR) {
4598 +               if (!((opt->srr) & (!opt->is_strictroute)))
4599 +                       return 0;
4600 +       }
4601 +       else if ((info->options & IPT_IPV4OPTION_DONT_MATCH_SRR) == IPT_IPV4OPTION_DONT_MATCH_SRR) {
4602 +               if (opt->srr)
4603 +                       return 0;
4604 +       }
4605 +       /* record route */
4606 +       if ((info->options & IPT_IPV4OPTION_MATCH_RR) == IPT_IPV4OPTION_MATCH_RR) {
4607 +               if (!opt->rr)
4608 +                       return 0;
4609 +       }
4610 +       else if ((info->options & IPT_IPV4OPTION_DONT_MATCH_RR) == IPT_IPV4OPTION_DONT_MATCH_RR) {
4611 +               if (opt->rr)
4612 +                       return 0;
4613 +       }
4614 +       /* timestamp */
4615 +       if ((info->options & IPT_IPV4OPTION_MATCH_TIMESTAMP) == IPT_IPV4OPTION_MATCH_TIMESTAMP) {
4616 +               if (!opt->ts)
4617 +                       return 0;
4618 +       }
4619 +       else if ((info->options & IPT_IPV4OPTION_DONT_MATCH_TIMESTAMP) == IPT_IPV4OPTION_DONT_MATCH_TIMESTAMP) {
4620 +               if (opt->ts)
4621 +                       return 0;
4622 +       }
4623 +       /* router-alert option  */
4624 +       if ((info->options & IPT_IPV4OPTION_MATCH_ROUTER_ALERT) == IPT_IPV4OPTION_MATCH_ROUTER_ALERT) {
4625 +               if (!opt->router_alert)
4626 +                       return 0;
4627 +       }
4628 +       else if ((info->options & IPT_IPV4OPTION_DONT_MATCH_ROUTER_ALERT) == IPT_IPV4OPTION_DONT_MATCH_ROUTER_ALERT) {
4629 +               if (opt->router_alert)
4630 +                       return 0;
4631 +       }
4632 +
4633 +       /* we match ! */
4634 +       return 1;
4635 +}
4636 +
4637 +static int
4638 +checkentry(const char *tablename,
4639 +          const struct ipt_ip *ip,
4640 +          void *matchinfo,
4641 +          unsigned int matchsize,
4642 +          unsigned int hook_mask)
4643 +{
4644 +       const struct ipt_ipv4options_info *info = matchinfo;   /* match info for rule */
4645 +       /* Check the size */
4646 +       if (matchsize != IPT_ALIGN(sizeof(struct ipt_ipv4options_info)))
4647 +               return 0;
4648 +       /* Now check the coherence of the data ... */
4649 +       if (((info->options & IPT_IPV4OPTION_MATCH_ANY_OPT) == IPT_IPV4OPTION_MATCH_ANY_OPT) &&
4650 +           (((info->options & IPT_IPV4OPTION_DONT_MATCH_SRR) == IPT_IPV4OPTION_DONT_MATCH_SRR) ||
4651 +            ((info->options & IPT_IPV4OPTION_DONT_MATCH_RR) == IPT_IPV4OPTION_DONT_MATCH_RR) ||
4652 +            ((info->options & IPT_IPV4OPTION_DONT_MATCH_TIMESTAMP) == IPT_IPV4OPTION_DONT_MATCH_TIMESTAMP) ||
4653 +            ((info->options & IPT_IPV4OPTION_DONT_MATCH_ROUTER_ALERT) == IPT_IPV4OPTION_DONT_MATCH_ROUTER_ALERT) ||
4654 +            ((info->options & IPT_IPV4OPTION_DONT_MATCH_ANY_OPT) == IPT_IPV4OPTION_DONT_MATCH_ANY_OPT)))
4655 +               return 0; /* opposites */
4656 +       if (((info->options & IPT_IPV4OPTION_DONT_MATCH_ANY_OPT) == IPT_IPV4OPTION_DONT_MATCH_ANY_OPT) &&
4657 +           (((info->options & IPT_IPV4OPTION_MATCH_LSRR) == IPT_IPV4OPTION_MATCH_LSRR) ||
4658 +            ((info->options & IPT_IPV4OPTION_MATCH_SSRR) == IPT_IPV4OPTION_MATCH_SSRR) ||
4659 +            ((info->options & IPT_IPV4OPTION_MATCH_RR) == IPT_IPV4OPTION_MATCH_RR) ||
4660 +            ((info->options & IPT_IPV4OPTION_MATCH_TIMESTAMP) == IPT_IPV4OPTION_MATCH_TIMESTAMP) ||
4661 +            ((info->options & IPT_IPV4OPTION_MATCH_ROUTER_ALERT) == IPT_IPV4OPTION_MATCH_ROUTER_ALERT) ||
4662 +            ((info->options & IPT_IPV4OPTION_MATCH_ANY_OPT) == IPT_IPV4OPTION_MATCH_ANY_OPT)))
4663 +               return 0; /* opposites */
4664 +       if (((info->options & IPT_IPV4OPTION_MATCH_SSRR) == IPT_IPV4OPTION_MATCH_SSRR) &&
4665 +           ((info->options & IPT_IPV4OPTION_MATCH_LSRR) == IPT_IPV4OPTION_MATCH_LSRR))
4666 +               return 0; /* cannot match in the same time loose and strict source routing */
4667 +       if ((((info->options & IPT_IPV4OPTION_MATCH_SSRR) == IPT_IPV4OPTION_MATCH_SSRR) ||
4668 +            ((info->options & IPT_IPV4OPTION_MATCH_LSRR) == IPT_IPV4OPTION_MATCH_LSRR)) &&
4669 +           ((info->options & IPT_IPV4OPTION_DONT_MATCH_SRR) == IPT_IPV4OPTION_DONT_MATCH_SRR))
4670 +               return 0; /* opposites */
4671 +       if (((info->options & IPT_IPV4OPTION_MATCH_RR) == IPT_IPV4OPTION_MATCH_RR) &&
4672 +           ((info->options & IPT_IPV4OPTION_DONT_MATCH_RR) == IPT_IPV4OPTION_DONT_MATCH_RR))
4673 +               return 0; /* opposites */
4674 +       if (((info->options & IPT_IPV4OPTION_MATCH_TIMESTAMP) == IPT_IPV4OPTION_MATCH_TIMESTAMP) &&
4675 +           ((info->options & IPT_IPV4OPTION_DONT_MATCH_TIMESTAMP) == IPT_IPV4OPTION_DONT_MATCH_TIMESTAMP))
4676 +               return 0; /* opposites */
4677 +       if (((info->options & IPT_IPV4OPTION_MATCH_ROUTER_ALERT) == IPT_IPV4OPTION_MATCH_ROUTER_ALERT) &&
4678 +           ((info->options & IPT_IPV4OPTION_DONT_MATCH_ROUTER_ALERT) == IPT_IPV4OPTION_DONT_MATCH_ROUTER_ALERT))
4679 +               return 0; /* opposites */
4680 +
4681 +       /* everything looks ok. */
4682 +       return 1;
4683 +}
4684 +
4685 +static struct ipt_match ipv4options_match = { 
4686 +       .name = "ipv4options",
4687 +       .match = match,
4688 +       .checkentry = checkentry,
4689 +       .me = THIS_MODULE
4690 +};
4691 +
4692 +static int __init init(void)
4693 +{
4694 +       return ipt_register_match(&ipv4options_match);
4695 +}
4696 +
4697 +static void __exit fini(void)
4698 +{
4699 +       ipt_unregister_match(&ipv4options_match);
4700 +}
4701 +
4702 +module_init(init);
4703 +module_exit(fini);
4704 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
4705 --- linux-2.6.6-rc1.org/net/ipv4/netfilter/ipt_mport.c  1970-01-01 01:00:00.000000000 +0100
4706 +++ linux-2.6.6-rc1/net/ipv4/netfilter/ipt_mport.c      2004-04-19 10:08:33.000000000 +0200
4707 @@ -0,0 +1,116 @@
4708 +/* Kernel module to match one of a list of TCP/UDP ports: ports are in
4709 +   the same place so we can treat them as equal. */
4710 +#include <linux/module.h>
4711 +#include <linux/types.h>
4712 +#include <linux/udp.h>
4713 +#include <linux/skbuff.h>
4714 +
4715 +#include <linux/netfilter_ipv4/ipt_mport.h>
4716 +#include <linux/netfilter_ipv4/ip_tables.h>
4717 +
4718 +MODULE_LICENSE("GPL");
4719 +
4720 +#if 0
4721 +#define duprintf(format, args...) printk(format , ## args)
4722 +#else
4723 +#define duprintf(format, args...)
4724 +#endif
4725 +
4726 +/* Returns 1 if the port is matched by the test, 0 otherwise. */
4727 +static inline int
4728 +ports_match(const struct ipt_mport *minfo, u_int16_t src, u_int16_t dst)
4729 +{
4730 +       unsigned int i;
4731 +        unsigned int m;
4732 +        u_int16_t pflags = minfo->pflags;
4733 +       for (i=0, m=1; i<IPT_MULTI_PORTS; i++, m<<=1) {
4734 +                u_int16_t s, e;
4735 +
4736 +                if (pflags & m
4737 +                    && minfo->ports[i] == 65535)
4738 +                        return 0;
4739 +
4740 +                s = minfo->ports[i];
4741 +
4742 +                if (pflags & m) {
4743 +                        e = minfo->ports[++i];
4744 +                        m <<= 1;
4745 +                } else
4746 +                        e = s;
4747 +
4748 +                if (minfo->flags & IPT_MPORT_SOURCE
4749 +                    && src >= s && src <= e)
4750 +                        return 1;
4751 +
4752 +               if (minfo->flags & IPT_MPORT_DESTINATION
4753 +                   && dst >= s && dst <= e)
4754 +                       return 1;
4755 +       }
4756 +
4757 +       return 0;
4758 +}
4759 +
4760 +static int
4761 +match(const struct sk_buff *skb,
4762 +      const struct net_device *in,
4763 +      const struct net_device *out,
4764 +      const void *matchinfo,
4765 +      int offset,
4766 +      int *hotdrop)
4767 +{
4768 +       u16 ports[2];
4769 +       const struct ipt_mport *minfo = matchinfo;
4770 +
4771 +       if (offset)
4772 +               return 0;
4773 +
4774 +       /* Must be big enough to read ports (both UDP and TCP have
4775 +           them at the start). */
4776 +       if (skb_copy_bits(skb, skb->nh.iph->ihl*4, ports, sizeof(ports)) < 0) {
4777 +               /* We've been asked to examine this packet, and we
4778 +                  can't.  Hence, no choice but to drop. */
4779 +                       duprintf("ipt_multiport:"
4780 +                                " Dropping evil offset=0 tinygram.\n");
4781 +                       *hotdrop = 1;
4782 +                       return 0;
4783 +       }
4784 +
4785 +       return ports_match(minfo, ntohs(ports[0]), ntohs(ports[1]));
4786 +}
4787 +
4788 +/* Called when user tries to insert an entry of this type. */
4789 +static int
4790 +checkentry(const char *tablename,
4791 +          const struct ipt_ip *ip,
4792 +          void *matchinfo,
4793 +          unsigned int matchsize,
4794 +          unsigned int hook_mask)
4795 +{
4796 +       if (matchsize != IPT_ALIGN(sizeof(struct ipt_mport)))
4797 +               return 0;
4798 +
4799 +       /* Must specify proto == TCP/UDP, no unknown flags or bad count */
4800 +       return (ip->proto == IPPROTO_TCP || ip->proto == IPPROTO_UDP)
4801 +               && !(ip->invflags & IPT_INV_PROTO)
4802 +               && matchsize == IPT_ALIGN(sizeof(struct ipt_mport));
4803 +}
4804 +
4805 +static struct ipt_match mport_match = { 
4806 +       .name = "mport",
4807 +       .match = &match,
4808 +       .checkentry = &checkentry,
4809 +       .me = THIS_MODULE
4810 +};
4811 +
4812 +static int __init init(void)
4813 +{
4814 +       return ipt_register_match(&mport_match);
4815 +}
4816 +
4817 +static void __exit fini(void)
4818 +{
4819 +       ipt_unregister_match(&mport_match);
4820 +}
4821 +
4822 +module_init(init);
4823 +module_exit(fini);
4824 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
4825 --- linux-2.6.6-rc1.org/net/ipv4/netfilter/ipt_nth.c    1970-01-01 01:00:00.000000000 +0100
4826 +++ linux-2.6.6-rc1/net/ipv4/netfilter/ipt_nth.c        2004-04-19 10:08:34.000000000 +0200
4827 @@ -0,0 +1,166 @@
4828 +/*
4829 +  This is a module which is used for match support for every Nth packet
4830 +  This file is distributed under the terms of the GNU General Public
4831 +  License (GPL). Copies of the GPL can be obtained from:
4832 +     ftp://prep.ai.mit.edu/pub/gnu/GPL
4833 +
4834 +  2001-07-18 Fabrice MARIE <fabrice@netfilter.org> : initial implementation.
4835 +  2001-09-20 Richard Wagner (rwagner@cloudnet.com)
4836 +        * added support for multiple counters
4837 +        * added support for matching on individual packets
4838 +          in the counter cycle
4839 +  2004-02-19 Harald Welte <laforge@netfilter.org>
4840 +       * port to 2.6.x
4841 +
4842 +*/
4843 +
4844 +#include <linux/module.h>
4845 +#include <linux/skbuff.h>
4846 +#include <linux/ip.h>
4847 +#include <net/tcp.h>
4848 +#include <linux/spinlock.h>
4849 +#include <linux/netfilter_ipv4/ip_tables.h>
4850 +#include <linux/netfilter_ipv4/ipt_nth.h>
4851 +
4852 +MODULE_LICENSE("GPL");
4853 +MODULE_AUTHOR("Fabrice Marie <fabrice@netfilter.org>");
4854 +
4855 +/*
4856 + * State information.
4857 + */
4858 +struct state {
4859 +       spinlock_t lock;
4860 +       u_int16_t number;
4861 +};
4862 +
4863 +static struct state states[IPT_NTH_NUM_COUNTERS];
4864 +
4865 +static int
4866 +ipt_nth_match(const struct sk_buff *pskb,
4867 +             const struct net_device *in,
4868 +             const struct net_device *out,
4869 +             const void *matchinfo,
4870 +             int offset,
4871 +             int *hotdrop)
4872 +{
4873 +       /* Parameters from userspace */
4874 +       const struct ipt_nth_info *info = matchinfo;
4875 +        unsigned counter = info->counter;
4876 +               if((counter < 0) || (counter >= IPT_NTH_NUM_COUNTERS)) 
4877 +       {
4878 +                       printk(KERN_WARNING "nth: invalid counter %u. counter between 0 and %u\n", counter, IPT_NTH_NUM_COUNTERS-1);
4879 +               return 0;
4880 +        };
4881 +
4882 +        spin_lock(&states[counter].lock);
4883 +
4884 +        /* Are we matching every nth packet?*/
4885 +        if (info->packet == 0xFF)
4886 +        {
4887 +               /* We're matching every nth packet and only every nth packet*/
4888 +               /* Do we match or invert match? */
4889 +               if (info->not == 0)
4890 +               {
4891 +                       if (states[counter].number == 0)
4892 +                       {
4893 +                               ++states[counter].number;
4894 +                               goto match;
4895 +                       }
4896 +                       if (states[counter].number >= info->every)
4897 +                               states[counter].number = 0; /* reset the counter */
4898 +                       else
4899 +                               ++states[counter].number;
4900 +                       goto dontmatch;
4901 +               }
4902 +               else
4903 +               {
4904 +                       if (states[counter].number == 0)
4905 +                       {
4906 +                               ++states[counter].number;
4907 +                               goto dontmatch;
4908 +                       }
4909 +                       if (states[counter].number >= info->every)
4910 +                               states[counter].number = 0;
4911 +                       else
4912 +                               ++states[counter].number;
4913 +                       goto match;
4914 +               }
4915 +        }
4916 +        else
4917 +        {
4918 +               /* We're using the --packet, so there must be a rule for every value */
4919 +               if (states[counter].number == info->packet)
4920 +               {
4921 +                       /* only increment the counter when a match happens */
4922 +                       if (states[counter].number >= info->every)
4923 +                               states[counter].number = 0; /* reset the counter */
4924 +                       else
4925 +                               ++states[counter].number;
4926 +                       goto match;
4927 +               }
4928 +               else
4929 +                       goto dontmatch;
4930 +       }
4931 +
4932 + dontmatch:
4933 +       /* don't match */
4934 +       spin_unlock(&states[counter].lock);
4935 +       return 0;
4936 +
4937 + match:
4938 +       spin_unlock(&states[counter].lock);
4939 +       return 1;
4940 +}
4941 +
4942 +static int
4943 +ipt_nth_checkentry(const char *tablename,
4944 +                  const struct ipt_ip *e,
4945 +                  void *matchinfo,
4946 +                  unsigned int matchsize,
4947 +                  unsigned int hook_mask)
4948 +{
4949 +       /* Parameters from userspace */
4950 +       const struct ipt_nth_info *info = matchinfo;
4951 +        unsigned counter = info->counter;
4952 +        if((counter < 0) || (counter >= IPT_NTH_NUM_COUNTERS)) 
4953 +       {
4954 +               printk(KERN_WARNING "nth: invalid counter %u. counter between 0 and %u\n", counter, IPT_NTH_NUM_COUNTERS-1);
4955 +                       return 0;
4956 +               };
4957 +
4958 +       if (matchsize != IPT_ALIGN(sizeof(struct ipt_nth_info))) {
4959 +               printk("nth: matchsize %u != %u\n", matchsize,
4960 +                      IPT_ALIGN(sizeof(struct ipt_nth_info)));
4961 +               return 0;
4962 +       }
4963 +
4964 +       states[counter].number = info->startat;
4965 +
4966 +       return 1;
4967 +}
4968 +
4969 +static struct ipt_match ipt_nth_reg = { 
4970 +       .name = "nth",
4971 +       .match = ipt_nth_match,
4972 +       .checkentry = ipt_nth_checkentry,
4973 +       .me = THIS_MODULE
4974 +};
4975 +
4976 +static int __init init(void)
4977 +{
4978 +       unsigned counter;
4979 +
4980 +       memset(&states, 0, sizeof(states));
4981 +        for (counter = 0; counter < IPT_NTH_NUM_COUNTERS; counter++) 
4982 +               spin_lock_init(&(states[counter].lock));
4983 +
4984 +       return ipt_register_match(&ipt_nth_reg);
4985 +}
4986 +
4987 +static void __exit fini(void)
4988 +{
4989 +       ipt_unregister_match(&ipt_nth_reg);
4990 +}
4991 +
4992 +module_init(init);
4993 +module_exit(fini);
4994 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
4995 --- linux-2.6.6-rc1.org/net/ipv4/netfilter/ipt_osf.c    1970-01-01 01:00:00.000000000 +0100
4996 +++ linux-2.6.6-rc1/net/ipv4/netfilter/ipt_osf.c        2004-04-19 10:08:35.000000000 +0200
4997 @@ -0,0 +1,866 @@
4998 +/*
4999 + * ipt_osf.c
5000 + *
5001 + * Copyright (c) 2003 Evgeniy Polyakov <johnpol@2ka.mipt.ru>
5002 + *
5003 + *
5004 + * This program is free software; you can redistribute it and/or modify
5005 + * it under the terms of the GNU General Public License as published by
5006 + * the Free Software Foundation; either version 2 of the License, or
5007 + * (at your option) any later version.
5008 + *
5009 + * This program is distributed in the hope that it will be useful,
5010 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
5011 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
5012 + * GNU General Public License for more details.
5013 + *
5014 + * You should have received a copy of the GNU General Public License
5015 + * along with this program; if not, write to the Free Software
5016 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
5017 + */
5018 +
5019 +/*
5020 + * OS fingerprint matching module.
5021 + * It simply compares various parameters from SYN packet with
5022 + * some hardcoded ones.
5023 + *
5024 + * Original table was created by Michal Zalewski <lcamtuf@coredump.cx>
5025 + * for his p0f.
5026 + */
5027 +
5028 +#include <linux/config.h>
5029 +#include <linux/kernel.h>
5030 +#include <linux/types.h>
5031 +#include <linux/string.h>
5032 +#include <linux/smp.h>
5033 +#include <linux/module.h>
5034 +#include <linux/skbuff.h>
5035 +#include <linux/file.h>
5036 +#include <linux/ip.h>
5037 +#include <linux/proc_fs.h>
5038 +#include <linux/fs.h>
5039 +#include <linux/slab.h>
5040 +#include <linux/spinlock.h>
5041 +#include <linux/ctype.h>
5042 +#include <linux/list.h>
5043 +#include <linux/if.h>
5044 +#include <linux/tcp.h>
5045 +
5046 +#include <net/sock.h>
5047 +#include <net/ip.h>
5048 +
5049 +#include <linux/netfilter_ipv4/ip_tables.h>
5050 +
5051 +#include <linux/netfilter_ipv4/ipt_osf.h>
5052 +
5053 +#define OSF_DEBUG
5054 +
5055 +#ifdef OSF_DEBUG
5056 +#define log(x...)              printk(KERN_INFO "ipt_osf: " x)
5057 +#define loga(x...)             printk(x)
5058 +#else
5059 +#define log(x...)              do {} while(0)
5060 +#define loga(x...)             do {} while(0)
5061 +#endif
5062 +
5063 +#define FMATCH_WRONG           0
5064 +#define FMATCH_OK              1
5065 +#define FMATCH_OPT_WRONG       2
5066 +
5067 +#define OPTDEL                 ','
5068 +#define OSFPDEL                ':'
5069 +#define MAXOPTSTRLEN           128
5070 +#define OSFFLUSH               "FLUSH"
5071 +
5072 +static rwlock_t osf_lock = RW_LOCK_UNLOCKED;
5073 +static spinlock_t ipt_osf_netlink_lock = SPIN_LOCK_UNLOCKED;
5074 +static struct list_head        finger_list;    
5075 +static int match(const struct sk_buff *, const struct net_device *, const struct net_device *,
5076 +                     const void *, int, 
5077 +                     const void *, u_int16_t, 
5078 +                     int *);
5079 +static int checkentry(const char *, const struct ipt_ip *, void *,
5080 +                          unsigned int, unsigned int);
5081 +
5082 +static unsigned long seq, ipt_osf_groups = 1;
5083 +static struct sock *nts;
5084 +
5085 +static struct ipt_match osf_match = 
5086 +{ 
5087 +       { NULL, NULL }, 
5088 +       "osf", 
5089 +       &match, 
5090 +       &checkentry, 
5091 +       NULL, 
5092 +       THIS_MODULE 
5093 +};
5094 +
5095 +static void ipt_osf_nlsend(struct osf_finger *f, const struct sk_buff *sk)
5096 +{
5097 +       unsigned int size;
5098 +       struct sk_buff *skb;
5099 +       struct ipt_osf_nlmsg *data;
5100 +       struct nlmsghdr *nlh;
5101 +
5102 +       size = NLMSG_SPACE(sizeof(struct ipt_osf_nlmsg));
5103 +
5104 +       skb = alloc_skb(size, GFP_ATOMIC);
5105 +       if (!skb)
5106 +       {
5107 +               log("skb_alloc() failed.\n");
5108 +               return;
5109 +       }
5110 +       
5111 +       nlh = NLMSG_PUT(skb, 0, seq++, NLMSG_DONE, size - sizeof(*nlh));
5112 +       
5113 +       data = (struct ipt_osf_nlmsg *)NLMSG_DATA(nlh);
5114 +
5115 +       memcpy(&data->f, f, sizeof(struct osf_finger));
5116 +       memcpy(&data->ip, sk->nh.iph, sizeof(struct iphdr));
5117 +       memcpy(&data->tcp, (struct tcphdr *)((u_int32_t *)sk->nh.iph + sk->nh.iph->ihl), sizeof(struct tcphdr));
5118 +
5119 +       NETLINK_CB(skb).dst_groups = ipt_osf_groups;
5120 +       netlink_broadcast(nts, skb, 0, ipt_osf_groups, GFP_ATOMIC);
5121 +
5122 +nlmsg_failure:
5123 +       return;
5124 +}
5125 +
5126 +static inline int smart_dec(const struct sk_buff *skb, unsigned long flags, unsigned char f_ttl)
5127 +{
5128 +       struct iphdr *ip = skb->nh.iph;
5129 +
5130 +       if (flags & IPT_OSF_SMART)
5131 +       {
5132 +               struct in_device *in_dev = in_dev_get(skb->dev);
5133 +
5134 +               for_ifa(in_dev)
5135 +               {
5136 +                       if (inet_ifa_match(ip->saddr, ifa))
5137 +                       {
5138 +                               in_dev_put(in_dev);
5139 +                               return (ip->ttl == f_ttl);
5140 +                       }
5141 +               }
5142 +               endfor_ifa(in_dev);
5143 +               
5144 +               in_dev_put(in_dev);
5145 +               return (ip->ttl <= f_ttl);
5146 +       }
5147 +       else
5148 +               return (ip->ttl == f_ttl);
5149 +}
5150 +
5151 +static int
5152 +match(const struct sk_buff *skb, const struct net_device *in, const struct net_device *out,
5153 +      const void *matchinfo, int offset,
5154 +      const void *hdr, u_int16_t datalen,
5155 +      int *hotdrop)
5156 +{
5157 +       struct ipt_osf_info *info = (struct ipt_osf_info *)matchinfo;
5158 +       struct iphdr *ip = skb->nh.iph;
5159 +       struct tcphdr *tcp;
5160 +       int fmatch = FMATCH_WRONG, fcount = 0;
5161 +       unsigned long totlen, optsize = 0, window;
5162 +       unsigned char df, *optp = NULL, *_optp = NULL;
5163 +       char check_WSS = 0;
5164 +       struct list_head *ent;
5165 +       struct osf_finger *f;
5166 +
5167 +       if (!ip || !info)
5168 +               return 0;
5169 +                               
5170 +       tcp = (struct tcphdr *)((u_int32_t *)ip + ip->ihl);
5171 +
5172 +       if (!tcp->syn)
5173 +               return 0;
5174 +       
5175 +       totlen = ntohs(ip->tot_len);
5176 +       df = ((ntohs(ip->frag_off) & IP_DF)?1:0);
5177 +       window = ntohs(tcp->window);
5178 +       
5179 +       if (tcp->doff*4 > sizeof(struct tcphdr))
5180 +       {
5181 +               _optp = optp = (char *)(tcp+1);
5182 +               optsize = tcp->doff*4 - sizeof(struct tcphdr);
5183 +       }
5184 +
5185 +       
5186 +       /* Actually we can create hash/table of all genres and search
5187 +        * only in appropriate part, but here is initial variant,
5188 +        * so will use slow path.
5189 +        */
5190 +       read_lock(&osf_lock);
5191 +       list_for_each(ent, &finger_list)
5192 +       {
5193 +               f = list_entry(ent, struct osf_finger, flist);
5194 +       
5195 +               if (!(info->flags & IPT_OSF_LOG) && strcmp(info->genre, f->genre)) 
5196 +                       continue;
5197 +
5198 +               optp = _optp;
5199 +               fmatch = FMATCH_WRONG;
5200 +
5201 +               if (totlen == f->ss && df == f->df && 
5202 +                       smart_dec(skb, info->flags, f->ttl))
5203 +               {
5204 +                       unsigned long foptsize;
5205 +                       int optnum;
5206 +                       unsigned short mss = 0;
5207 +
5208 +                       check_WSS = 0;
5209 +
5210 +                       switch (f->wss.wc)
5211 +                       {
5212 +                               case 0:   check_WSS = 0; break;
5213 +                               case 'S': check_WSS = 1; break;
5214 +                               case 'T': check_WSS = 2; break;
5215 +                               case '%': check_WSS = 3; break;
5216 +                               default: log("Wrong fingerprint wss.wc=%d, %s - %s\n", 
5217 +                                                        f->wss.wc, f->genre, f->details);
5218 +                                        check_WSS = 4;
5219 +                                        break;
5220 +                       }
5221 +                       if (check_WSS == 4)
5222 +                               continue;
5223 +
5224 +                       /* Check options */
5225 +
5226 +                       foptsize = 0;
5227 +                       for (optnum=0; optnum<f->opt_num; ++optnum)
5228 +                               foptsize += f->opt[optnum].length;
5229 +
5230 +                               
5231 +                       if (foptsize > MAX_IPOPTLEN || optsize > MAX_IPOPTLEN || optsize != foptsize)
5232 +                               continue;
5233 +
5234 +                       if (!optp)
5235 +                       {
5236 +                               fmatch = FMATCH_OK;
5237 +                               loga("\tYEP : matching without options.\n");
5238 +                               if ((info->flags & IPT_OSF_LOG) && 
5239 +                                       info->loglevel == IPT_OSF_LOGLEVEL_FIRST)
5240 +                                       break;
5241 +                               else
5242 +                                       continue;
5243 +                       }
5244 +                       
5245 +
5246 +                       for (optnum=0; optnum<f->opt_num; ++optnum)
5247 +                       {
5248 +                               if (f->opt[optnum].kind == (*optp)) 
5249 +                               {
5250 +                                       unsigned char len = f->opt[optnum].length;
5251 +                                       unsigned char *optend = optp + len;
5252 +                                       int loop_cont = 0;
5253 +
5254 +                                       fmatch = FMATCH_OK;
5255 +
5256 +
5257 +                                       switch (*optp)
5258 +                                       {
5259 +                                               case OSFOPT_MSS:
5260 +                                                       mss = ntohs(*(unsigned short *)(optp+2));
5261 +                                                       break;
5262 +                                               case OSFOPT_TS:
5263 +                                                       loop_cont = 1;
5264 +                                                       break;
5265 +                                       }
5266 +                                       
5267 +                                       if (loop_cont)
5268 +                                       {
5269 +                                               optp = optend;
5270 +                                               continue;
5271 +                                       }
5272 +                                       
5273 +                                       if (len != 1)
5274 +                                       {
5275 +                                               /* Skip kind and length fields*/
5276 +                                               optp += 2; 
5277 +
5278 +                                               if (f->opt[optnum].wc.val != 0)
5279 +                                               {
5280 +                                                       unsigned long tmp = 0;
5281 +                                                       
5282 +                                                       /* Hmmm... It looks a bit ugly. :) */
5283 +                                                       memcpy(&tmp, optp, 
5284 +                                                               (len > sizeof(unsigned long)?
5285 +                                                                       sizeof(unsigned long):len));
5286 +                                                       /* 2 + 2: optlen(2 bytes) + 
5287 +                                                        *      kind(1 byte) + length(1 byte) */
5288 +                                                       if (len == 4) 
5289 +                                                               tmp = ntohs(tmp);
5290 +                                                       else
5291 +                                                               tmp = ntohl(tmp);
5292 +
5293 +                                                       if (f->opt[optnum].wc.wc == '%')
5294 +                                                       {
5295 +                                                               if ((tmp % f->opt[optnum].wc.val) != 0)
5296 +                                                                       fmatch = FMATCH_OPT_WRONG;
5297 +                                                       }
5298 +                                                       else if (tmp != f->opt[optnum].wc.val)
5299 +                                                               fmatch = FMATCH_OPT_WRONG;
5300 +                                               }
5301 +                                       }
5302 +
5303 +                                       optp = optend;
5304 +                               }
5305 +                               else
5306 +                                       fmatch = FMATCH_OPT_WRONG;
5307 +
5308 +                               if (fmatch != FMATCH_OK)
5309 +                                       break;
5310 +                       }
5311 +
5312 +                       if (fmatch != FMATCH_OPT_WRONG)
5313 +                       {
5314 +                               fmatch = FMATCH_WRONG;
5315 +
5316 +                               switch (check_WSS)
5317 +                               {
5318 +                                       case 0:
5319 +                                               if (f->wss.val == 0 || window == f->wss.val)
5320 +                                                       fmatch = FMATCH_OK;
5321 +                                               break;
5322 +                                       case 1: /* MSS */
5323 +/* Lurked in OpenBSD */
5324 +#define SMART_MSS      1460
5325 +                                               if (window == f->wss.val*mss || 
5326 +                                                       window == f->wss.val*SMART_MSS)
5327 +                                                       fmatch = FMATCH_OK;
5328 +                                               break;
5329 +                                       case 2: /* MTU */
5330 +                                               if (window == f->wss.val*(mss+40) ||
5331 +                                                       window == f->wss.val*(SMART_MSS+40))
5332 +                                                       fmatch = FMATCH_OK;
5333 +                                               break;
5334 +                                       case 3: /* MOD */
5335 +                                               if ((window % f->wss.val) == 0)
5336 +                                                       fmatch = FMATCH_OK;
5337 +                                               break;
5338 +                               }
5339 +                       }
5340 +                                       
5341 +
5342 +                       if (fmatch == FMATCH_OK)
5343 +                       {
5344 +                               fcount++;
5345 +                               log("%s [%s:%s:%s] : %u.%u.%u.%u:%u -> %u.%u.%u.%u:%u hops=%d\n", 
5346 +                                       f->genre, f->version,
5347 +                                       f->subtype, f->details,
5348 +                                       NIPQUAD(ip->saddr), ntohs(tcp->source),
5349 +                                       NIPQUAD(ip->daddr), ntohs(tcp->dest),
5350 +                                       f->ttl - ip->ttl);
5351 +                               if (info->flags & IPT_OSF_NETLINK)
5352 +                               {
5353 +                                       spin_lock_bh(&ipt_osf_netlink_lock);
5354 +                                       ipt_osf_nlsend(f, skb);
5355 +                                       spin_unlock_bh(&ipt_osf_netlink_lock);
5356 +                               }
5357 +                               if ((info->flags & IPT_OSF_LOG) && 
5358 +                                       info->loglevel == IPT_OSF_LOGLEVEL_FIRST)
5359 +                                       break;
5360 +                       }
5361 +               }
5362 +       }
5363 +       if (!fcount && (info->flags & (IPT_OSF_LOG | IPT_OSF_NETLINK)))
5364 +       {
5365 +               unsigned char opt[4 * 15 - sizeof(struct tcphdr)];
5366 +               unsigned int i, optsize;
5367 +               struct osf_finger fg;
5368 +
5369 +               memset(&fg, 0, sizeof(fg));
5370 +
5371 +               if ((info->flags & IPT_OSF_LOG))
5372 +                       log("Unknown: %lu:%d:%d:%lu:", window, ip->ttl, df, totlen);
5373 +               if (optp)
5374 +               {
5375 +                       optsize = tcp->doff * 4 - sizeof(struct tcphdr);
5376 +                       if (skb_copy_bits(skb, ip->ihl*4 + sizeof(struct tcphdr),
5377 +                                         opt, optsize) < 0)
5378 +                       {
5379 +                               if (info->flags & IPT_OSF_LOG)
5380 +                                       loga("TRUNCATED");
5381 +                               if (info->flags & IPT_OSF_NETLINK)
5382 +                                       strcpy(fg.details, "TRUNCATED");
5383 +                       }
5384 +                       else
5385 +                       {
5386 +                               for (i = 0; i < optsize; i++)
5387 +                               {
5388 +                                       if (info->flags & IPT_OSF_LOG)
5389 +                                               loga("%02X", opt[i]);
5390 +                               }
5391 +                               if (info->flags & IPT_OSF_NETLINK)
5392 +                                       memcpy(fg.details, opt, MAXDETLEN);
5393 +                       }
5394 +               }
5395 +               if ((info->flags & IPT_OSF_LOG))
5396 +                       loga(" %u.%u.%u.%u:%u -> %u.%u.%u.%u:%u\n", 
5397 +                               NIPQUAD(ip->saddr), ntohs(tcp->source),
5398 +                               NIPQUAD(ip->daddr), ntohs(tcp->dest));
5399 +               
5400 +               if (info->flags & IPT_OSF_NETLINK)
5401 +               {
5402 +                       fg.wss.val      = window;
5403 +                       fg.ttl          = ip->ttl;
5404 +                       fg.df           = df;
5405 +                       fg.ss           = totlen;
5406 +                       strncpy(fg.genre, "Unknown", MAXGENRELEN);
5407 +
5408 +                       spin_lock_bh(&ipt_osf_netlink_lock);
5409 +                       ipt_osf_nlsend(&fg, skb);
5410 +                       spin_unlock_bh(&ipt_osf_netlink_lock);
5411 +               }
5412 +       }
5413 +
5414 +       read_unlock(&osf_lock);
5415 +
5416 +       return (fmatch == FMATCH_OK)?1:0;
5417 +}
5418 +
5419 +static int
5420 +checkentry(const char *tablename,
5421 +           const struct ipt_ip *ip,
5422 +           void *matchinfo,
5423 +           unsigned int matchsize,
5424 +           unsigned int hook_mask)
5425 +{
5426 +       if (matchsize != IPT_ALIGN(sizeof(struct ipt_osf_info)))
5427 +               return 0;
5428 +       if (ip->proto != IPPROTO_TCP)
5429 +              return 0;
5430 +
5431 +       return 1;
5432 +}
5433 +
5434 +static char * osf_strchr(char *ptr, char c)
5435 +{
5436 +       char *tmp;
5437 +
5438 +       tmp = strchr(ptr, c);
5439 +
5440 +       while (tmp && tmp+1 && isspace(*(tmp+1)))
5441 +               tmp++;
5442 +
5443 +       return tmp;
5444 +}
5445 +
5446 +static struct osf_finger * finger_alloc(void)
5447 +{
5448 +       struct osf_finger *f;
5449 +
5450 +       f = kmalloc(sizeof(struct osf_finger), GFP_KERNEL);
5451 +       if (f)
5452 +               memset(f, 0, sizeof(struct osf_finger));
5453 +       
5454 +       return f;
5455 +}
5456 +
5457 +static void finger_free(struct osf_finger *f)
5458 +{
5459 +       memset(f, 0, sizeof(struct osf_finger));
5460 +       kfree(f);
5461 +}
5462 +
5463 +
5464 +static void osf_parse_opt(struct osf_opt *opt, int *optnum, char *obuf, int olen)
5465 +{
5466 +       int i, op;
5467 +       char *ptr, wc;
5468 +       unsigned long val;
5469 +
5470 +       ptr = &obuf[0];
5471 +       i = 0;
5472 +       while (ptr != NULL && i < olen)
5473 +       {
5474 +               val = 0;
5475 +               op = 0;
5476 +               wc = 0;
5477 +               switch (obuf[i])
5478 +               {
5479 +                       case 'N': 
5480 +                               op = OSFOPT_NOP;
5481 +                               ptr = osf_strchr(&obuf[i], OPTDEL);
5482 +                               if (ptr)
5483 +                               {
5484 +                                       *ptr = '\0';
5485 +                                       ptr++;
5486 +                                       i += (int)(ptr-&obuf[i]);
5487 +
5488 +                               }
5489 +                               else
5490 +                                       i++;
5491 +                               break;
5492 +                       case 'S': 
5493 +                               op = OSFOPT_SACKP;
5494 +                               ptr = osf_strchr(&obuf[i], OPTDEL);
5495 +                               if (ptr)
5496 +                               {
5497 +                                       *ptr = '\0';
5498 +                                       ptr++;
5499 +                                       i += (int)(ptr-&obuf[i]);
5500 +
5501 +                               }
5502 +                               else
5503 +                                       i++;
5504 +                               break;
5505 +                       case 'T': 
5506 +                               op = OSFOPT_TS;
5507 +                               ptr = osf_strchr(&obuf[i], OPTDEL);
5508 +                               if (ptr)
5509 +                               {
5510 +                                       *ptr = '\0';
5511 +                                       ptr++;
5512 +                                       i += (int)(ptr-&obuf[i]);
5513 +
5514 +                               }
5515 +                               else
5516 +                                       i++;
5517 +                               break;
5518 +                       case 'W': 
5519 +                               op = OSFOPT_WSO;
5520 +                               ptr = osf_strchr(&obuf[i], OPTDEL);
5521 +                               if (ptr)
5522 +                               {
5523 +                                       switch (obuf[i+1])
5524 +                                       {
5525 +                                               case '%':       wc = '%'; break;
5526 +                                               case 'S':       wc = 'S'; break;
5527 +                                               case 'T':       wc = 'T'; break;
5528 +                                               default:        wc = 0; break;
5529 +                                       }
5530 +                                       
5531 +                                       *ptr = '\0';
5532 +                                       ptr++;
5533 +                                       if (wc)
5534 +                                               val = simple_strtoul(&obuf[i+2], NULL, 10);
5535 +                                       else
5536 +                                               val = simple_strtoul(&obuf[i+1], NULL, 10);
5537 +                                       i += (int)(ptr-&obuf[i]);
5538 +
5539 +                               }
5540 +                               else
5541 +                                       i++;
5542 +                               break;
5543 +                       case 'M': 
5544 +                               op = OSFOPT_MSS;
5545 +                               ptr = osf_strchr(&obuf[i], OPTDEL);
5546 +                               if (ptr)
5547 +                               {
5548 +                                       if (obuf[i+1] == '%')
5549 +                                               wc = '%';
5550 +                                       *ptr = '\0';
5551 +                                       ptr++;
5552 +                                       if (wc)
5553 +                                               val = simple_strtoul(&obuf[i+2], NULL, 10);
5554 +                                       else
5555 +                                               val = simple_strtoul(&obuf[i+1], NULL, 10);
5556 +                                       i += (int)(ptr-&obuf[i]);
5557 +
5558 +                               }
5559 +                               else
5560 +                                       i++;
5561 +                               break;
5562 +                       case 'E': 
5563 +                               op = OSFOPT_EOL;
5564 +                               ptr = osf_strchr(&obuf[i], OPTDEL);
5565 +                               if (ptr)
5566 +                               {
5567 +                                       *ptr = '\0';
5568 +                                       ptr++;
5569 +                                       i += (int)(ptr-&obuf[i]);
5570 +
5571 +                               }
5572 +                               else
5573 +                                       i++;
5574 +                               break;
5575 +                       default:
5576 +                               ptr = osf_strchr(&obuf[i], OPTDEL);
5577 +                               if (ptr)
5578 +                               {
5579 +                                       ptr++;
5580 +                                       i += (int)(ptr-&obuf[i]);
5581 +
5582 +                               }
5583 +                               else
5584 +                                       i++;
5585 +                               break;
5586 +               }
5587 +
5588 +               opt[*optnum].kind       = IANA_opts[op].kind;
5589 +               opt[*optnum].length     = IANA_opts[op].length;
5590 +               opt[*optnum].wc.wc      = wc;
5591 +               opt[*optnum].wc.val     = val;
5592 +
5593 +               (*optnum)++;
5594 +       }
5595 +}
5596 +
5597 +static int osf_proc_read(char *buf, char **start, off_t off, int count, int *eof, void *data)
5598 +{
5599 +       struct list_head *ent;
5600 +       struct osf_finger *f = NULL;
5601 +       int i;
5602 +       
5603 +       *eof = 1;
5604 +       count = 0;
5605 +
5606 +       read_lock_bh(&osf_lock);
5607 +       list_for_each(ent, &finger_list)
5608 +       {
5609 +               f = list_entry(ent, struct osf_finger, flist);
5610 +
5611 +               log("%s [%s]", f->genre, f->details);
5612 +               
5613 +               count += sprintf(buf+count, "%s - %s[%s] : %s", 
5614 +                                       f->genre, f->version,
5615 +                                       f->subtype, f->details);
5616 +               
5617 +               if (f->opt_num)
5618 +               {
5619 +                       loga(" OPT: ");
5620 +                       //count += sprintf(buf+count, " OPT: ");
5621 +                       for (i=0; i<f->opt_num; ++i)
5622 +                       {
5623 +                               //count += sprintf(buf+count, "%d.%c%lu; ", 
5624 +                               //      f->opt[i].kind, (f->opt[i].wc.wc)?f->opt[i].wc.wc:' ', f->opt[i].wc.val);
5625 +                               loga("%d.%c%lu; ", 
5626 +                                       f->opt[i].kind, (f->opt[i].wc.wc)?f->opt[i].wc.wc:' ', f->opt[i].wc.val);
5627 +                       }
5628 +               }
5629 +               loga("\n");
5630 +               count += sprintf(buf+count, "\n");
5631 +       }
5632 +       read_unlock_bh(&osf_lock);
5633 +
5634 +       return count;
5635 +}
5636 +
5637 +static int osf_proc_write(struct file *file, const char *buffer, unsigned long count, void *data)
5638 +{
5639 +       int cnt;
5640 +       unsigned long i;
5641 +       char obuf[MAXOPTSTRLEN];
5642 +       struct osf_finger *finger;
5643 +       struct list_head *ent, *n;
5644 +
5645 +       char *pbeg, *pend;
5646 +
5647 +       if (count == strlen(OSFFLUSH) && !strncmp(buffer, OSFFLUSH, strlen(OSFFLUSH)))
5648 +       {
5649 +               int i = 0;
5650 +               write_lock_bh(&osf_lock);
5651 +               list_for_each_safe(ent, n, &finger_list)
5652 +               {
5653 +                       i++;
5654 +                       finger = list_entry(ent, struct osf_finger, flist);
5655 +                       list_del(&finger->flist);
5656 +                       finger_free(finger);
5657 +               }
5658 +               write_unlock_bh(&osf_lock);
5659 +       
5660 +               log("Flushed %d entries.\n", i);
5661 +               
5662 +               return count;
5663 +       }
5664 +
5665 +       
5666 +       cnt = 0;
5667 +       for (i=0; i<count && buffer[i] != '\0'; ++i)
5668 +               if (buffer[i] == ':')
5669 +                       cnt++;
5670 +
5671 +       if (cnt != 8 || i != count)
5672 +       {
5673 +               log("Wrong input line cnt=%d[8], len=%lu[%lu]\n", 
5674 +                       cnt, i, count);
5675 +               return count;
5676 +       }
5677 +
5678 +       memset(obuf, 0, sizeof(obuf));
5679 +       
5680 +       finger = finger_alloc();
5681 +       if (!finger)
5682 +       {
5683 +               log("Failed to allocate new fingerprint entry.\n");
5684 +               return -ENOMEM;
5685 +       }
5686 +
5687 +       pbeg = (char *)buffer;
5688 +       pend = osf_strchr(pbeg, OSFPDEL);
5689 +       if (pend)
5690 +       {
5691 +               *pend = '\0';
5692 +               if (pbeg[0] == 'S')
5693 +               {
5694 +                       finger->wss.wc = 'S';
5695 +                       if (pbeg[1] == '%')
5696 +                               finger->wss.val = simple_strtoul(pbeg+2, NULL, 10);
5697 +                       else if (pbeg[1] == '*')
5698 +                               finger->wss.val = 0;
5699 +                       else 
5700 +                               finger->wss.val = simple_strtoul(pbeg+1, NULL, 10);
5701 +               }
5702 +               else if (pbeg[0] == 'T')
5703 +               {
5704 +                       finger->wss.wc = 'T';
5705 +                       if (pbeg[1] == '%')
5706 +                               finger->wss.val = simple_strtoul(pbeg+2, NULL, 10);
5707 +                       else if (pbeg[1] == '*')
5708 +                               finger->wss.val = 0;
5709 +                       else 
5710 +                               finger->wss.val = simple_strtoul(pbeg+1, NULL, 10);
5711 +               }
5712 +               else if (pbeg[0] == '%')
5713 +               {
5714 +                       finger->wss.wc = '%';
5715 +                       finger->wss.val = simple_strtoul(pbeg+1, NULL, 10);
5716 +               }
5717 +               else if (isdigit(pbeg[0]))
5718 +               {
5719 +                       finger->wss.wc = 0;
5720 +                       finger->wss.val = simple_strtoul(pbeg, NULL, 10);
5721 +               }
5722 +
5723 +               pbeg = pend+1;
5724 +       }
5725 +       pend = osf_strchr(pbeg, OSFPDEL);
5726 +       if (pend)
5727 +       {
5728 +               *pend = '\0';
5729 +               finger->ttl = simple_strtoul(pbeg, NULL, 10);
5730 +               pbeg = pend+1;
5731 +       }
5732 +       pend = osf_strchr(pbeg, OSFPDEL);
5733 +       if (pend)
5734 +       {
5735 +               *pend = '\0';
5736 +               finger->df = simple_strtoul(pbeg, NULL, 10);
5737 +               pbeg = pend+1;
5738 +       }
5739 +       pend = osf_strchr(pbeg, OSFPDEL);
5740 +       if (pend)
5741 +       {
5742 +               *pend = '\0';
5743 +               finger->ss = simple_strtoul(pbeg, NULL, 10);
5744 +               pbeg = pend+1;
5745 +       }
5746 +
5747 +       pend = osf_strchr(pbeg, OSFPDEL);
5748 +       if (pend)
5749 +       {
5750 +               *pend = '\0';
5751 +               cnt = snprintf(obuf, sizeof(obuf), "%s", pbeg);
5752 +               pbeg = pend+1;
5753 +       }
5754 +
5755 +       pend = osf_strchr(pbeg, OSFPDEL);
5756 +       if (pend)
5757 +       {
5758 +               *pend = '\0';
5759 +               if (pbeg[0] == '@' || pbeg[0] == '*')
5760 +                       cnt = snprintf(finger->genre, sizeof(finger->genre), "%s", pbeg+1);
5761 +               else
5762 +                       cnt = snprintf(finger->genre, sizeof(finger->genre), "%s", pbeg);
5763 +               pbeg = pend+1;
5764 +       }
5765 +       
5766 +       pend = osf_strchr(pbeg, OSFPDEL);
5767 +       if (pend)
5768 +       {
5769 +               *pend = '\0';
5770 +               cnt = snprintf(finger->version, sizeof(finger->version), "%s", pbeg);
5771 +               pbeg = pend+1;
5772 +       }
5773 +       
5774 +       pend = osf_strchr(pbeg, OSFPDEL);
5775 +       if (pend)
5776 +       {
5777 +               *pend = '\0';
5778 +               cnt = snprintf(finger->subtype, sizeof(finger->subtype), "%s", pbeg);
5779 +               pbeg = pend+1;
5780 +       }
5781 +
5782 +       cnt = snprintf(finger->details, 
5783 +                       ((count - (pbeg - buffer)+1) > MAXDETLEN)?MAXDETLEN:(count - (pbeg - buffer)+1), 
5784 +                       "%s", pbeg);
5785 +       
5786 +       log("%s - %s[%s] : %s\n", 
5787 +               finger->genre, finger->version,
5788 +               finger->subtype, finger->details);
5789 +       
5790 +       osf_parse_opt(finger->opt, &finger->opt_num, obuf, sizeof(obuf));
5791 +       
5792 +
5793 +       write_lock_bh(&osf_lock);
5794 +       list_add_tail(&finger->flist, &finger_list);
5795 +       write_unlock_bh(&osf_lock);
5796 +
5797 +       return count;
5798 +}
5799 +
5800 +static int __init osf_init(void)
5801 +{
5802 +       int err;
5803 +       struct proc_dir_entry *p;
5804 +
5805 +       log("Startng OS fingerprint matching module.\n");
5806 +
5807 +       INIT_LIST_HEAD(&finger_list);
5808 +       
5809 +       err = ipt_register_match(&osf_match);
5810 +       if (err)
5811 +       {
5812 +               log("Failed to register OS fingerprint matching module.\n");
5813 +               return -ENXIO;
5814 +       }
5815 +
5816 +       p = create_proc_entry("sys/net/ipv4/osf", S_IFREG | 0644, NULL);
5817 +       if (!p)
5818 +       {
5819 +               ipt_unregister_match(&osf_match);
5820 +               return -ENXIO;
5821 +       }
5822 +
5823 +       p->write_proc = osf_proc_write;
5824 +       p->read_proc  = osf_proc_read;
5825 +       
5826 +       nts = netlink_kernel_create(NETLINK_NFLOG, NULL);
5827 +       if (!nts)
5828 +       {
5829 +               log("netlink_kernel_create() failed\n");
5830 +               remove_proc_entry("sys/net/ipv4/osf", NULL);
5831 +               ipt_unregister_match(&osf_match);
5832 +               return -ENOMEM;
5833 +       }
5834 +
5835 +       return 0;
5836 +}
5837 +
5838 +static void __exit osf_fini(void)
5839 +{
5840 +       struct list_head *ent, *n;
5841 +       struct osf_finger *f;
5842 +       
5843 +       remove_proc_entry("sys/net/ipv4/osf", NULL);
5844 +       ipt_unregister_match(&osf_match);
5845 +//     if (nts && nts->socket)
5846 +//             sock_release(nts->socket);
5847 +
5848 +       list_for_each_safe(ent, n, &finger_list)
5849 +       {
5850 +               f = list_entry(ent, struct osf_finger, flist);
5851 +               list_del(&f->flist);
5852 +               finger_free(f);
5853 +       }
5854 +       
5855 +       log("OS fingerprint matching module finished.\n");
5856 +}
5857 +
5858 +module_init(osf_init);
5859 +module_exit(osf_fini);
5860 +
5861 +MODULE_LICENSE("GPL");
5862 +MODULE_AUTHOR("Evgeniy Polyakov <johnpol@2ka.mipt.ru>");
5863 +MODULE_DESCRIPTION("Passive OS fingerprint matching.");
5864 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
5865 --- linux-2.6.6-rc1.org/net/ipv4/netfilter/ipt_pool.c   1970-01-01 01:00:00.000000000 +0100
5866 +++ linux-2.6.6-rc1/net/ipv4/netfilter/ipt_pool.c       2004-04-19 10:08:36.000000000 +0200
5867 @@ -0,0 +1,71 @@
5868 +/* Kernel module to match an IP address pool. */
5869 +
5870 +#include <linux/module.h>
5871 +#include <linux/ip.h>
5872 +#include <linux/skbuff.h>
5873 +
5874 +#include <linux/netfilter_ipv4/ip_tables.h>
5875 +#include <linux/netfilter_ipv4/ip_pool.h>
5876 +#include <linux/netfilter_ipv4/ipt_pool.h>
5877 +
5878 +static inline int match_pool(
5879 +       ip_pool_t index,
5880 +       __u32 addr,
5881 +       int inv
5882 +) {
5883 +       if (ip_pool_match(index, ntohl(addr)))
5884 +               inv = !inv;
5885 +       return inv;
5886 +}
5887 +
5888 +static int match(
5889 +       const struct sk_buff *skb,
5890 +       const struct net_device *in,
5891 +       const struct net_device *out,
5892 +       const void *matchinfo,
5893 +       int offset,
5894 +       const void *hdr,
5895 +       u_int16_t datalen,
5896 +       int *hotdrop
5897 +) {
5898 +       const struct ipt_pool_info *info = matchinfo;
5899 +       const struct iphdr *iph = skb->nh.iph;
5900 +
5901 +       if (info->src != IP_POOL_NONE && !match_pool(info->src, iph->saddr,
5902 +                                               info->flags&IPT_POOL_INV_SRC))
5903 +               return 0;
5904 +
5905 +       if (info->dst != IP_POOL_NONE && !match_pool(info->dst, iph->daddr,
5906 +                                               info->flags&IPT_POOL_INV_DST))
5907 +               return 0;
5908 +
5909 +       return 1;
5910 +}
5911 +
5912 +static int checkentry(
5913 +       const char *tablename,
5914 +       const struct ipt_ip *ip,
5915 +       void *matchinfo,
5916 +       unsigned int matchsize,
5917 +       unsigned int hook_mask
5918 +) {
5919 +       if (matchsize != IPT_ALIGN(sizeof(struct ipt_pool_info)))
5920 +               return 0;
5921 +       return 1;
5922 +}
5923 +
5924 +static struct ipt_match pool_match
5925 += { { NULL, NULL }, "pool", &match, &checkentry, NULL, THIS_MODULE };
5926 +
5927 +static int __init init(void)
5928 +{
5929 +       return ipt_register_match(&pool_match);
5930 +}
5931 +
5932 +static void __exit fini(void)
5933 +{
5934 +       ipt_unregister_match(&pool_match);
5935 +}
5936 +
5937 +module_init(init);
5938 +module_exit(fini);
5939 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
5940 --- linux-2.6.6-rc1.org/net/ipv4/netfilter/ipt_psd.c    1970-01-01 01:00:00.000000000 +0100
5941 +++ linux-2.6.6-rc1/net/ipv4/netfilter/ipt_psd.c        2004-04-19 10:08:37.000000000 +0200
5942 @@ -0,0 +1,361 @@
5943 +/*
5944 +  This is a module which is used for PSD (portscan detection)
5945 +  Derived from scanlogd v2.1 written by Solar Designer <solar@false.com>
5946 +  and LOG target module.
5947 +
5948 +  Copyright (C) 2000,2001 astaro AG
5949 +
5950 +  This file is distributed under the terms of the GNU General Public
5951 +  License (GPL). Copies of the GPL can be obtained from:
5952 +     ftp://prep.ai.mit.edu/pub/gnu/GPL
5953 +
5954 +  2000-05-04 Markus Hennig <hennig@astaro.de> : initial
5955 +  2000-08-18 Dennis Koslowski <koslowski@astaro.de> : first release
5956 +  2000-12-01 Dennis Koslowski <koslowski@astaro.de> : UDP scans detection added
5957 +  2001-01-02 Dennis Koslowski <koslowski@astaro.de> : output modified
5958 +  2001-02-04 Jan Rekorajski <baggins@pld.org.pl> : converted from target to match
5959 +*/
5960 +
5961 +#include <linux/module.h>
5962 +#include <linux/skbuff.h>
5963 +#include <linux/ip.h>
5964 +#include <net/tcp.h>
5965 +#include <linux/spinlock.h>
5966 +#include <linux/netfilter_ipv4/ip_tables.h>
5967 +#include <linux/netfilter_ipv4/ipt_psd.h>
5968 +
5969 +#if 0
5970 +#define DEBUGP printk
5971 +#else
5972 +#define DEBUGP(format, args...)
5973 +#endif
5974 +
5975 +MODULE_LICENSE("GPL");
5976 +MODULE_AUTHOR("Dennis Koslowski <koslowski@astaro.com>");
5977 +
5978 +#define HF_DADDR_CHANGING   0x01
5979 +#define HF_SPORT_CHANGING   0x02
5980 +#define HF_TOS_CHANGING            0x04
5981 +#define HF_TTL_CHANGING            0x08
5982 +            
5983 +/*
5984 + * Information we keep per each target port
5985 + */
5986 +struct port {
5987 +       u_int16_t number;      /* port number */ 
5988 +       u_int8_t proto;        /* protocol number */
5989 +       u_int8_t and_flags;    /* tcp ANDed flags */
5990 +       u_int8_t or_flags;     /* tcp ORed flags */
5991 +};
5992 +
5993 +/*
5994 + * Information we keep per each source address.
5995 + */
5996 +struct host {
5997 +       struct host *next;              /* Next entry with the same hash */
5998 +       clock_t timestamp;              /* Last update time */
5999 +       struct in_addr src_addr;        /* Source address */
6000 +       struct in_addr dest_addr;       /* Destination address */
6001 +       unsigned short src_port;        /* Source port */
6002 +       int count;                      /* Number of ports in the list */
6003 +       int weight;                     /* Total weight of ports in the list */
6004 +       struct port ports[SCAN_MAX_COUNT - 1];  /* List of ports */
6005 +       unsigned char tos;              /* TOS */
6006 +       unsigned char ttl;              /* TTL */
6007 +       unsigned char flags;            /* HF_ flags bitmask */
6008 +};
6009 +
6010 +/*
6011 + * State information.
6012 + */
6013 +static struct {
6014 +       spinlock_t lock;
6015 +       struct host list[LIST_SIZE];    /* List of source addresses */
6016 +       struct host *hash[HASH_SIZE];   /* Hash: pointers into the list */
6017 +       int index;                      /* Oldest entry to be replaced */
6018 +} state;
6019 +
6020 +/*
6021 + * Convert an IP address into a hash table index.
6022 + */
6023 +static inline int hashfunc(struct in_addr addr)
6024 +{
6025 +       unsigned int value;
6026 +       int hash;
6027 +
6028 +       value = addr.s_addr;
6029 +       hash = 0;
6030 +       do {
6031 +               hash ^= value;
6032 +       } while ((value >>= HASH_LOG));
6033 +
6034 +       return hash & (HASH_SIZE - 1);
6035 +}
6036 +
6037 +static int
6038 +ipt_psd_match(const struct sk_buff *pskb,
6039 +             const struct net_device *in,
6040 +             const struct net_device *out,
6041 +             const void *matchinfo,
6042 +             int offset,
6043 +             const void *hdr,
6044 +             u_int16_t datalen,
6045 +             int *hotdrop)
6046 +{
6047 +       struct iphdr *ip_hdr;
6048 +       struct tcphdr *tcp_hdr;
6049 +       struct in_addr addr;
6050 +       u_int16_t src_port,dest_port;
6051 +       u_int8_t tcp_flags, proto;
6052 +       clock_t now;
6053 +       struct host *curr, *last, **head;
6054 +       int hash, index, count;
6055 +
6056 +       /* Parameters from userspace */
6057 +       const struct ipt_psd_info *psdinfo = matchinfo;
6058 +
6059 +       /* IP header */
6060 +       ip_hdr = pskb->nh.iph;
6061 +
6062 +       /* Sanity check */
6063 +       if (ntohs(ip_hdr->frag_off) & IP_OFFSET) {
6064 +               DEBUGP("PSD: sanity check failed\n");
6065 +               return 0;
6066 +       }
6067 +
6068 +       /* TCP or UDP ? */
6069 +       proto = ip_hdr->protocol;
6070 +
6071 +       if (proto != IPPROTO_TCP && proto != IPPROTO_UDP) {
6072 +               DEBUGP("PSD: protocol not supported\n");
6073 +               return 0;
6074 +       }
6075 +
6076 +       /* Get the source address, source & destination ports, and TCP flags */
6077 +
6078 +       addr.s_addr = ip_hdr->saddr;
6079 +
6080 +       tcp_hdr = (struct tcphdr*)((u_int32_t *)ip_hdr + ip_hdr->ihl);
6081 +
6082 +       /* Yep, it´s dirty */
6083 +       src_port = tcp_hdr->source;
6084 +       dest_port = tcp_hdr->dest;
6085 +
6086 +       if (proto == IPPROTO_TCP) {
6087 +               tcp_flags = *((u_int8_t*)tcp_hdr + 13);
6088 +       }
6089 +       else {
6090 +               tcp_flags = 0x00;
6091 +       }
6092 +
6093 +       /* We're using IP address 0.0.0.0 for a special purpose here, so don't let
6094 +        * them spoof us. [DHCP needs this feature - HW] */
6095 +       if (!addr.s_addr) {
6096 +               DEBUGP("PSD: spoofed source address (0.0.0.0)\n");
6097 +               return 0;
6098 +       }
6099 +
6100 +       /* Use jiffies here not to depend on someone setting the time while we're
6101 +        * running; we need to be careful with possible return value overflows. */
6102 +       now = jiffies;
6103 +
6104 +       spin_lock(&state.lock);
6105 +
6106 +       /* Do we know this source address already? */
6107 +       count = 0;
6108 +       last = NULL;
6109 +       if ((curr = *(head = &state.hash[hash = hashfunc(addr)])))
6110 +               do {
6111 +                       if (curr->src_addr.s_addr == addr.s_addr) break;
6112 +                       count++;
6113 +                       if (curr->next) last = curr;
6114 +               } while ((curr = curr->next));
6115 +
6116 +       if (curr) {
6117 +
6118 +               /* We know this address, and the entry isn't too old. Update it. */
6119 +               if (now - curr->timestamp <= (psdinfo->delay_threshold*HZ)/100 &&
6120 +                   time_after_eq(now, curr->timestamp)) {
6121 +
6122 +                       /* Just update the appropriate list entry if we've seen this port already */
6123 +                       for (index = 0; index < curr->count; index++) {
6124 +                               if (curr->ports[index].number == dest_port) {
6125 +                                       curr->ports[index].proto = proto;
6126 +                                       curr->ports[index].and_flags &= tcp_flags;
6127 +                                       curr->ports[index].or_flags |= tcp_flags;
6128 +                                       goto out_no_match;
6129 +                               }
6130 +                       }
6131 +
6132 +                       /* TCP/ACK and/or TCP/RST to a new port? This could be an outgoing connection. */
6133 +                       if (proto == IPPROTO_TCP && (tcp_hdr->ack || tcp_hdr->rst))
6134 +                               goto out_no_match;
6135 +
6136 +                       /* Packet to a new port, and not TCP/ACK: update the timestamp */
6137 +                       curr->timestamp = now;
6138 +
6139 +                       /* Logged this scan already? Then drop the packet. */
6140 +                       if (curr->weight >= psdinfo->weight_threshold)
6141 +                               goto out_match;
6142 +
6143 +                       /* Specify if destination address, source port, TOS or TTL are not fixed */
6144 +                       if (curr->dest_addr.s_addr != ip_hdr->daddr)
6145 +                               curr->flags |= HF_DADDR_CHANGING;
6146 +                       if (curr->src_port != src_port)
6147 +                               curr->flags |= HF_SPORT_CHANGING;
6148 +                       if (curr->tos != ip_hdr->tos)
6149 +                               curr->flags |= HF_TOS_CHANGING;
6150 +                       if (curr->ttl != ip_hdr->ttl)
6151 +                               curr->flags |= HF_TTL_CHANGING;
6152 +
6153 +                       /* Update the total weight */
6154 +                       curr->weight += (ntohs(dest_port) < 1024) ?
6155 +                               psdinfo->lo_ports_weight : psdinfo->hi_ports_weight;
6156 +
6157 +                       /* Got enough destination ports to decide that this is a scan? */
6158 +                       /* Then log it and drop the packet. */
6159 +                       if (curr->weight >= psdinfo->weight_threshold)
6160 +                               goto out_match;
6161 +
6162 +                       /* Remember the new port */
6163 +                       if (curr->count < SCAN_MAX_COUNT) {
6164 +                               curr->ports[curr->count].number = dest_port;
6165 +                               curr->ports[curr->count].proto = proto;
6166 +                               curr->ports[curr->count].and_flags = tcp_flags;
6167 +                               curr->ports[curr->count].or_flags = tcp_flags;
6168 +                               curr->count++;
6169 +                       }
6170 +
6171 +                       goto out_no_match;
6172 +               }
6173 +
6174 +               /* We know this address, but the entry is outdated. Mark it unused, and
6175 +                * remove from the hash table. We'll allocate a new entry instead since
6176 +                * this one might get re-used too soon. */
6177 +               curr->src_addr.s_addr = 0;
6178 +               if (last)
6179 +                       last->next = last->next->next;
6180 +               else if (*head)
6181 +                       *head = (*head)->next;
6182 +               last = NULL;
6183 +       }
6184 +
6185 +       /* We don't need an ACK from a new source address */
6186 +       if (proto == IPPROTO_TCP && tcp_hdr->ack)
6187 +               goto out_no_match;
6188 +
6189 +       /* Got too many source addresses with the same hash value? Then remove the
6190 +        * oldest one from the hash table, so that they can't take too much of our
6191 +        * CPU time even with carefully chosen spoofed IP addresses. */
6192 +       if (count >= HASH_MAX && last) last->next = NULL;
6193 +
6194 +       /* We're going to re-use the oldest list entry, so remove it from the hash
6195 +        * table first (if it is really already in use, and isn't removed from the
6196 +        * hash table already because of the HASH_MAX check above). */
6197 +
6198 +       /* First, find it */
6199 +       if (state.list[state.index].src_addr.s_addr)
6200 +               head = &state.hash[hashfunc(state.list[state.index].src_addr)];
6201 +       else
6202 +               head = &last;
6203 +       last = NULL;
6204 +       if ((curr = *head))
6205 +       do {
6206 +               if (curr == &state.list[state.index]) break;
6207 +               last = curr;
6208 +       } while ((curr = curr->next));
6209 +
6210 +       /* Then, remove it */
6211 +       if (curr) {
6212 +               if (last)
6213 +                       last->next = last->next->next;
6214 +               else if (*head)
6215 +                       *head = (*head)->next;
6216 +       }
6217 +
6218 +       /* Get our list entry */
6219 +       curr = &state.list[state.index++];
6220 +       if (state.index >= LIST_SIZE) state.index = 0;
6221 +
6222 +       /* Link it into the hash table */
6223 +       head = &state.hash[hash];
6224 +       curr->next = *head;
6225 +       *head = curr;
6226 +
6227 +       /* And fill in the fields */
6228 +       curr->timestamp = now;
6229 +       curr->src_addr = addr;
6230 +       curr->dest_addr.s_addr = ip_hdr->daddr;
6231 +       curr->src_port = src_port;
6232 +       curr->count = 1;
6233 +       curr->weight = (ntohs(dest_port) < 1024) ?
6234 +               psdinfo->lo_ports_weight : psdinfo->hi_ports_weight;
6235 +       curr->ports[0].number = dest_port;
6236 +       curr->ports[0].proto = proto;
6237 +       curr->ports[0].and_flags = tcp_flags;
6238 +       curr->ports[0].or_flags = tcp_flags;
6239 +       curr->tos = ip_hdr->tos;
6240 +       curr->ttl = ip_hdr->ttl;
6241 +
6242 +out_no_match:
6243 +       spin_unlock(&state.lock);
6244 +       return 0;
6245 +
6246 +out_match:
6247 +       spin_unlock(&state.lock);
6248 +       return 1;
6249 +}
6250 +
6251 +static int ipt_psd_checkentry(const char *tablename,
6252 +                             const struct ipt_ip *e,
6253 +                             void *matchinfo,
6254 +                             unsigned int matchsize,
6255 +                             unsigned int hook_mask)
6256 +{
6257 +/*     const struct ipt_psd_info *psdinfo = targinfo;*/
6258 +
6259 +       /* we accept TCP only */
6260 +/*     if (e->ip.proto != IPPROTO_TCP) { */
6261 +/*             DEBUGP("PSD: specified protocol may be TCP only\n"); */
6262 +/*             return 0; */
6263 +/*     } */
6264 +
6265 +       if (matchsize != IPT_ALIGN(sizeof(struct ipt_psd_info))) {
6266 +               DEBUGP("PSD: matchsize %u != %u\n",
6267 +                      matchsize,
6268 +                      IPT_ALIGN(sizeof(struct ipt_psd_info)));
6269 +               return 0;
6270 +       }
6271 +
6272 +       return 1;
6273 +}
6274 +
6275 +static struct ipt_match ipt_psd_reg = { 
6276 +       {NULL, NULL},
6277 +       "psd",
6278 +       ipt_psd_match,
6279 +       ipt_psd_checkentry,
6280 +       NULL,
6281 +       THIS_MODULE };
6282 +
6283 +static int __init init(void)
6284 +{
6285 +       if (ipt_register_match(&ipt_psd_reg))
6286 +               return -EINVAL;
6287 +
6288 +       memset(&state, 0, sizeof(state));
6289 +
6290 +       spin_lock_init(&(state.lock));
6291 +
6292 +       printk("netfilter PSD loaded - (c) astaro AG\n");
6293 +       return 0;
6294 +}
6295 +
6296 +static void __exit fini(void)
6297 +{
6298 +       ipt_unregister_match(&ipt_psd_reg);
6299 +       printk("netfilter PSD unloaded - (c) astaro AG\n");
6300 +}
6301 +
6302 +module_init(init);
6303 +module_exit(fini);
6304 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
6305 --- linux-2.6.6-rc1.org/net/ipv4/netfilter/ipt_quota.c  1970-01-01 01:00:00.000000000 +0100
6306 +++ linux-2.6.6-rc1/net/ipv4/netfilter/ipt_quota.c      2004-04-19 10:08:37.000000000 +0200
6307 @@ -0,0 +1,91 @@
6308 +/* 
6309 + * netfilter module to enforce network quotas
6310 + *
6311 + * Sam Johnston <samj@samj.net>
6312 + */
6313 +#include <linux/module.h>
6314 +#include <linux/skbuff.h>
6315 +#include <linux/spinlock.h>
6316 +#include <linux/interrupt.h>
6317 +
6318 +#include <linux/netfilter_ipv4/ip_tables.h>
6319 +#include <linux/netfilter_ipv4/ipt_quota.h>
6320 +
6321 +MODULE_LICENSE("GPL");
6322 +MODULE_AUTHOR("Sam Johnston <samj@samj.net>");
6323 +
6324 +static spinlock_t quota_lock = SPIN_LOCK_UNLOCKED;
6325 +
6326 +static int
6327 +match(const struct sk_buff *skb,
6328 +      const struct net_device *in,
6329 +      const struct net_device *out,
6330 +      const void *matchinfo,
6331 +      int offset, int *hotdrop)
6332 +{
6333 +        struct ipt_quota_info *q = (struct ipt_quota_info *) matchinfo;
6334 +       unsigned int datalen;
6335 +
6336 +       if (skb->len < sizeof(struct iphdr))
6337 +               return NF_ACCEPT;
6338 +       
6339 +       datalen = skb->len - skb->nh.iph->ihl*4;
6340 +
6341 +        spin_lock_bh(&quota_lock);
6342 +
6343 +        if (q->quota >= datalen) {
6344 +                /* we can afford this one */
6345 +                q->quota -= datalen;
6346 +                spin_unlock_bh(&quota_lock);
6347 +
6348 +#ifdef DEBUG_IPT_QUOTA
6349 +                printk("IPT Quota OK: %llu datlen %d \n", q->quota, datalen);
6350 +#endif
6351 +                return 1;
6352 +        }
6353 +
6354 +        /* so we do not allow even small packets from now on */
6355 +        q->quota = 0;
6356 +
6357 +#ifdef DEBUG_IPT_QUOTA
6358 +        printk("IPT Quota Failed: %llu datlen %d \n", q->quota, datalen);
6359 +#endif
6360 +
6361 +        spin_unlock_bh(&quota_lock);
6362 +        return 0;
6363 +}
6364 +
6365 +static int
6366 +checkentry(const char *tablename,
6367 +           const struct ipt_ip *ip,
6368 +           void *matchinfo, unsigned int matchsize, unsigned int hook_mask)
6369 +{
6370 +        /* TODO: spinlocks? sanity checks? */
6371 +        if (matchsize != IPT_ALIGN(sizeof (struct ipt_quota_info)))
6372 +                return 0;
6373 +
6374 +        return 1;
6375 +}
6376 +
6377 +static struct ipt_match quota_match = {
6378 +       .name = "quota",
6379 +       .match = match,
6380 +       .checkentry = checkentry,
6381 +       .me = THIS_MODULE
6382 +};
6383 +
6384 +static int __init
6385 +init(void)
6386 +{
6387 +        return ipt_register_match(&quota_match);
6388 +}
6389 +
6390 +static void __exit
6391 +fini(void)
6392 +{
6393 +        ipt_unregister_match(&quota_match);
6394 +}
6395 +
6396 +module_init(init);
6397 +module_exit(fini);
6398 +
6399 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
6400 --- linux-2.6.6-rc1.org/net/ipv4/netfilter/ipt_random.c 1970-01-01 01:00:00.000000000 +0100
6401 +++ linux-2.6.6-rc1/net/ipv4/netfilter/ipt_random.c     2004-04-19 10:08:38.000000000 +0200
6402 @@ -0,0 +1,96 @@
6403 +/*
6404 +  This is a module which is used for a "random" match support.
6405 +  This file is distributed under the terms of the GNU General Public
6406 +  License (GPL). Copies of the GPL can be obtained from:
6407 +     ftp://prep.ai.mit.edu/pub/gnu/GPL
6408 +
6409 +  2001-10-14 Fabrice MARIE <fabrice@netfilter.org> : initial implementation.
6410 +*/
6411 +
6412 +#include <linux/module.h>
6413 +#include <linux/skbuff.h>
6414 +#include <linux/ip.h>
6415 +#include <linux/random.h>
6416 +#include <net/tcp.h>
6417 +#include <linux/spinlock.h>
6418 +#include <linux/netfilter_ipv4/ip_tables.h>
6419 +#include <linux/netfilter_ipv4/ipt_random.h>
6420 +
6421 +MODULE_LICENSE("GPL");
6422 +
6423 +static int
6424 +ipt_rand_match(const struct sk_buff *pskb,
6425 +              const struct net_device *in,
6426 +              const struct net_device *out,
6427 +              const void *matchinfo,
6428 +              int offset,
6429 +              const void *hdr,
6430 +              u_int16_t datalen,
6431 +              int *hotdrop)
6432 +{
6433 +       /* Parameters from userspace */
6434 +       const struct ipt_rand_info *info = matchinfo;
6435 +       u_int8_t random_number;
6436 +
6437 +       /* get 1 random number from the kernel random number generation routine */
6438 +       get_random_bytes((void *)(&random_number), 1);
6439 +
6440 +       /* Do we match ? */
6441 +       if (random_number <= info->average)
6442 +               return 1;
6443 +       else
6444 +               return 0;
6445 +}
6446 +
6447 +static int
6448 +ipt_rand_checkentry(const char *tablename,
6449 +                  const struct ipt_ip *e,
6450 +                  void *matchinfo,
6451 +                  unsigned int matchsize,
6452 +                  unsigned int hook_mask)
6453 +{
6454 +       /* Parameters from userspace */
6455 +       const struct ipt_rand_info *info = matchinfo;
6456 +
6457 +       if (matchsize != IPT_ALIGN(sizeof(struct ipt_rand_info))) {
6458 +               printk("ipt_random: matchsize %u != %u\n", matchsize,
6459 +                      IPT_ALIGN(sizeof(struct ipt_rand_info)));
6460 +               return 0;
6461 +       }
6462 +
6463 +       /* must be  1 <= average % <= 99 */
6464 +       /* 1  x 2.55 = 2   */
6465 +       /* 99 x 2.55 = 252 */
6466 +       if ((info->average < 2) || (info->average > 252)) {
6467 +               printk("ipt_random:  invalid average %u\n", info->average);
6468 +               return 0;
6469 +       }
6470 +
6471 +       return 1;
6472 +}
6473 +
6474 +static struct ipt_match ipt_rand_reg = { 
6475 +       {NULL, NULL},
6476 +       "random",
6477 +       ipt_rand_match,
6478 +       ipt_rand_checkentry,
6479 +       NULL,
6480 +       THIS_MODULE };
6481 +
6482 +static int __init init(void)
6483 +{
6484 +       if (ipt_register_match(&ipt_rand_reg))
6485 +               return -EINVAL;
6486 +
6487 +       printk("ipt_random match loaded\n");
6488 +       return 0;
6489 +}
6490 +
6491 +static void __exit fini(void)
6492 +{
6493 +       ipt_unregister_match(&ipt_rand_reg);
6494 +       printk("ipt_random match unloaded\n");
6495 +}
6496 +
6497 +module_init(init);
6498 +module_exit(fini);
6499 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
6500 --- linux-2.6.6-rc1.org/net/ipv4/netfilter/ipt_realm.c  1970-01-01 01:00:00.000000000 +0100
6501 +++ linux-2.6.6-rc1/net/ipv4/netfilter/ipt_realm.c      2004-04-19 10:08:39.000000000 +0200
6502 @@ -0,0 +1,78 @@
6503 +/* IP tables module for matching the routing realm
6504 + *
6505 + * $Id$
6506 + *
6507 + * (C) 2003 by Sampsa Ranta <sampsa@netsonic.fi>
6508 + *
6509 + * This program is free software; you can redistribute it and/or modify
6510 + * it under the terms of the GNU General Public License version 2 as
6511 + * published by the Free Software Foundation.
6512 + */
6513 +
6514 +#include <linux/module.h>
6515 +#include <linux/skbuff.h>
6516 +#include <linux/netdevice.h>
6517 +#include <net/route.h>
6518 +
6519 +#include <linux/netfilter_ipv4/ipt_realm.h>
6520 +#include <linux/netfilter_ipv4/ip_tables.h>
6521 +
6522 +MODULE_AUTHOR("Sampsa Ranta <sampsa@netsonic.fi>");
6523 +MODULE_LICENSE("GPL");
6524 +
6525 +static int
6526 +match(const struct sk_buff *skb,
6527 +      const struct net_device *in,
6528 +      const struct net_device *out,
6529 +      const void *matchinfo,
6530 +      int offset,
6531 +      int *hotdrop)
6532 +{
6533 +       const struct ipt_realm_info *info = matchinfo;
6534 +       struct dst_entry *dst = skb->dst;
6535 +    
6536 +       if (!dst)
6537 +               return 0;
6538 +
6539 +       return (info->id == (dst->tclassid & info->mask)) ^ info->invert;
6540 +}
6541 +
6542 +static int check(const char *tablename,
6543 +                 const struct ipt_ip *ip,
6544 +                 void *matchinfo,
6545 +                 unsigned int matchsize,
6546 +                 unsigned int hook_mask)
6547 +{
6548 +       if (hook_mask
6549 +           & ~((1 << NF_IP_POST_ROUTING) | (1 << NF_IP_FORWARD) |
6550 +               (1 << NF_IP_LOCAL_OUT)| (1 << NF_IP_LOCAL_IN))) {
6551 +               printk("ipt_realm: only valid for POST_ROUTING, LOCAL_OUT, "
6552 +                      "LOCAL_IN or FORWARD.\n");
6553 +               return 0;
6554 +       }
6555 +
6556 +       if (matchsize != IPT_ALIGN(sizeof(struct ipt_realm_info)))
6557 +               return 0;
6558 +
6559 +       return 1;
6560 +}
6561 +
6562 +static struct ipt_match realm_match = {
6563 +       .name = "realm",
6564 +       .match = match, 
6565 +       .checkentry = check,
6566 +       .me = THIS_MODULE
6567 +};
6568 +
6569 +static int __init init(void)
6570 +{
6571 +       return ipt_register_match(&realm_match);
6572 +}
6573 +
6574 +static void __exit fini(void)
6575 +{
6576 +       ipt_unregister_match(&realm_match);
6577 +}
6578 +
6579 +module_init(init);
6580 +module_exit(fini);
6581 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
6582 --- linux-2.6.6-rc1.org/net/ipv4/netfilter/ipt_sctp.c   1970-01-01 01:00:00.000000000 +0100
6583 +++ linux-2.6.6-rc1/net/ipv4/netfilter/ipt_sctp.c       2004-04-19 10:08:40.000000000 +0200
6584 @@ -0,0 +1,199 @@
6585 +#include <linux/module.h>
6586 +#include <linux/skbuff.h>
6587 +#include <net/ip.h>
6588 +#include <linux/sctp.h>
6589 +
6590 +#include <linux/netfilter_ipv4/ip_tables.h>
6591 +#include <linux/netfilter_ipv4/ipt_sctp.h>
6592 +
6593 +#if 0
6594 +#define duprintf(format, args...) printk(format , ## args)
6595 +#else
6596 +#define duprintf(format, args...)
6597 +#endif
6598 +
6599 +#define SCCHECK(cond, option, flag, invflag) (!((flag) & (option)) \
6600 +                                             || (!!((invflag) & (option)) ^ (cond)))
6601 +
6602 +static int
6603 +match_flags(const struct ipt_sctp_flag_info *flag_info,
6604 +           const int flag_count,
6605 +           u_int8_t chunktype,
6606 +           u_int8_t chunkflags)
6607 +{
6608 +       int i;
6609 +
6610 +       for (i = 0; i < flag_count; i++) {
6611 +               if (flag_info[i].chunktype == chunktype) {
6612 +                       return (chunkflags & flag_info[i].flag_mask) == flag_info[i].flag;
6613 +               }
6614 +       }
6615 +
6616 +       return 1;
6617 +}
6618 +
6619 +static int
6620 +match_packet(const struct sk_buff *skb,
6621 +            const u_int32_t *chunkmap,
6622 +            int chunk_match_type,
6623 +            const struct ipt_sctp_flag_info *flag_info,
6624 +            const int flag_count,
6625 +            int *hotdrop)
6626 +{
6627 +       int offset;
6628 +       u_int32_t chunkmapcopy[256 / sizeof (u_int32_t)];
6629 +       sctp_chunkhdr_t sch;
6630 +
6631 +       int i = 0;
6632 +
6633 +       if (chunk_match_type == SCTP_CHUNK_MATCH_ALL) {
6634 +               SCTP_CHUNKMAP_COPY(chunkmapcopy, chunkmap);
6635 +       }
6636 +
6637 +       offset = skb->nh.iph->ihl * 4 + sizeof (sctp_sctphdr_t);
6638 +       do {
6639 +               if (skb_copy_bits(skb, offset, &sch, sizeof(sch)) < 0) {
6640 +                       duprintf("Dropping invalid SCTP packet.\n");
6641 +                       *hotdrop = 1;
6642 +                       return 0;
6643 +               }
6644 +
6645 +               duprintf("Chunk num: %d\toffset: %d\ttype: %d\tlength: %d\tflags: %x\n", 
6646 +                               ++i, offset, sch.type, htons(sch.length), sch.flags);
6647 +
6648 +               offset += (htons(sch.length) + 3) & ~3;
6649 +
6650 +               duprintf("skb->len: %d\toffset: %d\n", skb->len, offset);
6651 +
6652 +               if (SCTP_CHUNKMAP_IS_SET(chunkmap, sch.type)) {
6653 +                       switch (chunk_match_type) {
6654 +                       case SCTP_CHUNK_MATCH_ANY:
6655 +                               if (match_flags(flag_info, flag_count, 
6656 +                                       sch.type, sch.flags)) {
6657 +                                       return 1;
6658 +                               }
6659 +                               break;
6660 +
6661 +                       case SCTP_CHUNK_MATCH_ALL:
6662 +                               if (match_flags(flag_info, flag_count, 
6663 +                                       sch.type, sch.flags)) {
6664 +                                       SCTP_CHUNKMAP_CLEAR(chunkmapcopy, sch.type);
6665 +                               }
6666 +                               break;
6667 +
6668 +                       case SCTP_CHUNK_MATCH_ONLY:
6669 +                               if (!match_flags(flag_info, flag_count, 
6670 +                                       sch.type, sch.flags)) {
6671 +                                       return 0;
6672 +                               }
6673 +                               break;
6674 +                       }
6675 +               } else {
6676 +                       switch (chunk_match_type) {
6677 +                       case SCTP_CHUNK_MATCH_ONLY:
6678 +                               return 0;
6679 +                       }
6680 +               }
6681 +       } while (offset < skb->len);
6682 +
6683 +       switch (chunk_match_type) {
6684 +       case SCTP_CHUNK_MATCH_ALL:
6685 +               return SCTP_CHUNKMAP_IS_CLEAR(chunkmap);
6686 +       case SCTP_CHUNK_MATCH_ANY:
6687 +               return 0;
6688 +       case SCTP_CHUNK_MATCH_ONLY:
6689 +               return 1;
6690 +       }
6691 +
6692 +       /* This will never be reached, but required to stop compiler whine */
6693 +       return 0;
6694 +}
6695 +
6696 +static int
6697 +match(const struct sk_buff *skb,
6698 +      const struct net_device *in,
6699 +      const struct net_device *out,
6700 +      const void *matchinfo,
6701 +      int offset,
6702 +      int *hotdrop)
6703 +{
6704 +       const struct ipt_sctp_info *info;
6705 +       sctp_sctphdr_t sh;
6706 +
6707 +       info = (const struct ipt_sctp_info *)matchinfo;
6708 +
6709 +       if (offset) {
6710 +               duprintf("Dropping non-first fragment.. FIXME\n");
6711 +               return 0;
6712 +       }
6713 +       
6714 +       if (skb_copy_bits(skb, skb->nh.iph->ihl*4, &sh, sizeof(sh)) < 0) {
6715 +               duprintf("Dropping evil TCP offset=0 tinygram.\n");
6716 +               *hotdrop = 1;
6717 +               return 0;
6718 +               }
6719 +       duprintf("spt: %d\tdpt: %d\n", ntohs(sh.source), ntohs(sh.dest));
6720 +
6721 +       return  SCCHECK(((ntohs(sh.source) >= info->spts[0]) 
6722 +                       && (ntohs(sh.source) <= info->spts[1])), 
6723 +                       IPT_SCTP_SRC_PORTS, info->flags, info->invflags)
6724 +               && SCCHECK(((ntohs(sh.dest) >= info->dpts[0]) 
6725 +                       && (ntohs(sh.dest) <= info->dpts[1])), 
6726 +                       IPT_SCTP_DEST_PORTS, info->flags, info->invflags)
6727 +               && SCCHECK(match_packet(skb, info->chunkmap, info->chunk_match_type,
6728 +                                       info->flag_info, info->flag_count, 
6729 +                                       hotdrop),
6730 +                          IPT_SCTP_CHUNK_TYPES, info->flags, info->invflags);
6731 +}
6732 +
6733 +static int
6734 +checkentry(const char *tablename,
6735 +          const struct ipt_ip *ip,
6736 +          void *matchinfo,
6737 +          unsigned int matchsize,
6738 +          unsigned int hook_mask)
6739 +{
6740 +       const struct ipt_sctp_info *info;
6741 +
6742 +       info = (const struct ipt_sctp_info *)matchinfo;
6743 +
6744 +       return ip->proto == IPPROTO_SCTP
6745 +               && !(ip->invflags & IPT_INV_PROTO)
6746 +               && matchsize == IPT_ALIGN(sizeof(struct ipt_sctp_info))
6747 +               && !(info->flags & ~IPT_SCTP_VALID_FLAGS)
6748 +               && !(info->invflags & ~IPT_SCTP_VALID_FLAGS)
6749 +               && !(info->invflags & ~info->flags)
6750 +               && ((!(info->flags & IPT_SCTP_CHUNK_TYPES)) || 
6751 +                       (info->chunk_match_type &
6752 +                               (SCTP_CHUNK_MATCH_ALL 
6753 +                               | SCTP_CHUNK_MATCH_ANY
6754 +                               | SCTP_CHUNK_MATCH_ONLY)));
6755 +}
6756 +
6757 +static struct ipt_match sctp_match = 
6758 +{ 
6759 +       .list = { NULL, NULL},
6760 +       .name = "sctp",
6761 +       .match = &match,
6762 +       .checkentry = &checkentry,
6763 +       .destroy = NULL,
6764 +       .me = THIS_MODULE
6765 +};
6766 +
6767 +static int __init init(void)
6768 +{
6769 +       return ipt_register_match(&sctp_match);
6770 +}
6771 +
6772 +static void __exit fini(void)
6773 +{
6774 +       ipt_unregister_match(&sctp_match);
6775 +}
6776 +
6777 +module_init(init);
6778 +module_exit(fini);
6779 +
6780 +MODULE_LICENSE("GPL");
6781 +MODULE_AUTHOR("Kiran Kumar Immidi");
6782 +MODULE_DESCRIPTION("Match for SCTP protocol packets");
6783 +
6784 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
6785 --- linux-2.6.6-rc1.org/net/ipv4/netfilter/ipt_time.c   1970-01-01 01:00:00.000000000 +0100
6786 +++ linux-2.6.6-rc1/net/ipv4/netfilter/ipt_time.c       2004-04-19 10:08:41.000000000 +0200
6787 @@ -0,0 +1,185 @@
6788 +/*
6789 +  This is a module which is used for time matching
6790 +  It is using some modified code from dietlibc (localtime() function)
6791 +  that you can find at http://www.fefe.de/dietlibc/
6792 +  This file is distributed under the terms of the GNU General Public
6793 +  License (GPL). Copies of the GPL can be obtained from: ftp://prep.ai.mit.edu/pub/gnu/GPL
6794 +  2001-05-04 Fabrice MARIE <fabrice@netfilter.org> : initial development.
6795 +  2001-21-05 Fabrice MARIE <fabrice@netfilter.org> : bug fix in the match code,
6796 +     thanks to "Zeng Yu" <zengy@capitel.com.cn> for bug report.
6797 +  2001-26-09 Fabrice MARIE <fabrice@netfilter.org> : force the match to be in LOCAL_IN or PRE_ROUTING only.
6798 +  2001-30-11 Fabrice : added the possibility to use the match in FORWARD/OUTPUT with a little hack,
6799 +     added Nguyen Dang Phuoc Dong <dongnd@tlnet.com.vn> patch to support timezones.
6800 +*/
6801 +
6802 +#include <linux/module.h>
6803 +#include <linux/skbuff.h>
6804 +#include <linux/netfilter_ipv4/ip_tables.h>
6805 +#include <linux/netfilter_ipv4/ipt_time.h>
6806 +#include <linux/time.h>
6807 +
6808 +MODULE_AUTHOR("Fabrice MARIE <fabrice@netfilter.org>");
6809 +MODULE_DESCRIPTION("Match arrival timestamp");
6810 +MODULE_LICENSE("GPL");
6811 +
6812 +struct tm
6813 +{
6814 +       int tm_sec;                   /* Seconds.     [0-60] (1 leap second) */
6815 +       int tm_min;                   /* Minutes.     [0-59] */
6816 +       int tm_hour;                  /* Hours.       [0-23] */
6817 +       int tm_mday;                  /* Day.         [1-31] */
6818 +       int tm_mon;                   /* Month.       [0-11] */
6819 +       int tm_year;                  /* Year - 1900.  */
6820 +       int tm_wday;                  /* Day of week. [0-6] */
6821 +       int tm_yday;                  /* Days in year.[0-365] */
6822 +       int tm_isdst;                 /* DST.         [-1/0/1]*/
6823 +
6824 +       long int tm_gmtoff;           /* we don't care, we count from GMT */
6825 +       const char *tm_zone;          /* we don't care, we count from GMT */
6826 +};
6827 +
6828 +void
6829 +localtime(const time_t *timepr, struct tm *r);
6830 +
6831 +static int
6832 +match(const struct sk_buff *skb,
6833 +      const struct net_device *in,
6834 +      const struct net_device *out,
6835 +      const void *matchinfo,
6836 +      int offset,
6837 +      const void *hdr,
6838 +      u_int16_t datalen,
6839 +      int *hotdrop)
6840 +{
6841 +       const struct ipt_time_info *info = matchinfo;   /* match info for rule */
6842 +       struct tm currenttime;                          /* time human readable */
6843 +       u_int8_t days_of_week[7] = {64, 32, 16, 8, 4, 2, 1};
6844 +       u_int16_t packet_time;
6845 +       struct timeval kerneltimeval;
6846 +       time_t packet_local_time;
6847 +
6848 +       /* if kerneltime=1, we don't read the skb->timestamp but kernel time instead */
6849 +       if (info->kerneltime)
6850 +       {
6851 +               do_gettimeofday(&kerneltimeval);
6852 +               packet_local_time = kerneltimeval.tv_sec;
6853 +       }
6854 +       else
6855 +               packet_local_time = skb->stamp.tv_sec;
6856 +
6857 +       /* Transform the timestamp of the packet, in a human readable form */
6858 +       localtime(&packet_local_time, &currenttime);
6859 +
6860 +       /* check if we match this timestamp, we start by the days... */
6861 +       if ((days_of_week[currenttime.tm_wday] & info->days_match) != days_of_week[currenttime.tm_wday])
6862 +               return 0; /* the day doesn't match */
6863 +
6864 +       /* ... check the time now */
6865 +       packet_time = (currenttime.tm_hour * 60) + currenttime.tm_min;
6866 +       if ((packet_time < info->time_start) || (packet_time > info->time_stop))
6867 +               return 0;
6868 +
6869 +       /* here we match ! */
6870 +       return 1;
6871 +}
6872 +
6873 +static int
6874 +checkentry(const char *tablename,
6875 +           const struct ipt_ip *ip,
6876 +           void *matchinfo,
6877 +           unsigned int matchsize,
6878 +           unsigned int hook_mask)
6879 +{
6880 +       struct ipt_time_info *info = matchinfo;   /* match info for rule */
6881 +
6882 +       /* First, check that we are in the correct hook */
6883 +       /* PRE_ROUTING, LOCAL_IN or FROWARD */
6884 +       if (hook_mask
6885 +            & ~((1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_LOCAL_IN) | (1 << NF_IP_FORWARD) | (1 << NF_IP_LOCAL_OUT)))
6886 +       {
6887 +               printk("ipt_time: error, only valid for PRE_ROUTING, LOCAL_IN, FORWARD and OUTPUT)\n");
6888 +               return 0;
6889 +       }
6890 +       /* we use the kerneltime if we are in forward or output */
6891 +       info->kerneltime = 1;
6892 +       if (hook_mask & ~((1 << NF_IP_FORWARD) | (1 << NF_IP_LOCAL_OUT))) 
6893 +               /* if not, we use the skb time */
6894 +               info->kerneltime = 0;
6895 +
6896 +       /* Check the size */
6897 +       if (matchsize != IPT_ALIGN(sizeof(struct ipt_time_info)))
6898 +               return 0;
6899 +       /* Now check the coherence of the data ... */
6900 +       if ((info->time_start > 1439) ||        /* 23*60+59 = 1439*/
6901 +           (info->time_stop  > 1439))
6902 +       {
6903 +               printk(KERN_WARNING "ipt_time: invalid argument\n");
6904 +               return 0;
6905 +       }
6906 +
6907 +       return 1;
6908 +}
6909 +
6910 +static struct ipt_match time_match
6911 += { { NULL, NULL }, "time", &match, &checkentry, NULL, THIS_MODULE };
6912 +
6913 +static int __init init(void)
6914 +{
6915 +       printk("ipt_time loading\n");
6916 +       return ipt_register_match(&time_match);
6917 +}
6918 +
6919 +static void __exit fini(void)
6920 +{
6921 +       ipt_unregister_match(&time_match);
6922 +       printk("ipt_time unloaded\n");
6923 +}
6924 +
6925 +module_init(init);
6926 +module_exit(fini);
6927 +
6928 +
6929 +/* The part below is borowed and modified from dietlibc */
6930 +
6931 +/* seconds per day */
6932 +#define SPD 24*60*60
6933 +
6934 +void
6935 +localtime(const time_t *timepr, struct tm *r) {
6936 +       time_t i;
6937 +       time_t timep;
6938 +       extern struct timezone sys_tz;
6939 +       const unsigned int __spm[12] =
6940 +               { 0,
6941 +                 (31),
6942 +                 (31+28),
6943 +                 (31+28+31),
6944 +                 (31+28+31+30),
6945 +                 (31+28+31+30+31),
6946 +                 (31+28+31+30+31+30),
6947 +                 (31+28+31+30+31+30+31),
6948 +                 (31+28+31+30+31+30+31+31),
6949 +                 (31+28+31+30+31+30+31+31+30),
6950 +                 (31+28+31+30+31+30+31+31+30+31),
6951 +                 (31+28+31+30+31+30+31+31+30+31+30),
6952 +               };
6953 +       register time_t work;
6954 +
6955 +       timep = (*timepr) - (sys_tz.tz_minuteswest * 60);
6956 +       work=timep%(SPD);
6957 +       r->tm_sec=work%60; work/=60;
6958 +       r->tm_min=work%60; r->tm_hour=work/60;
6959 +       work=timep/(SPD);
6960 +       r->tm_wday=(4+work)%7;
6961 +       for (i=1970; ; ++i) {
6962 +               register time_t k= (!(i%4) && ((i%100) || !(i%400)))?366:365;
6963 +               if (work>k)
6964 +                       work-=k;
6965 +               else
6966 +                       break;
6967 +       }
6968 +       r->tm_year=i-1900;
6969 +       for (i=11; i && __spm[i]>work; --i) ;
6970 +       r->tm_mon=i;
6971 +       r->tm_mday=work-__spm[i]+1;
6972 +}
6973 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
6974 --- linux-2.6.6-rc1.org/net/ipv4/netfilter/ipt_u32.c    1970-01-01 01:00:00.000000000 +0100
6975 +++ linux-2.6.6-rc1/net/ipv4/netfilter/ipt_u32.c        2004-04-19 10:08:46.000000000 +0200
6976 @@ -0,0 +1,211 @@
6977 +/* Kernel module to match u32 packet content. */
6978 +
6979 +/* 
6980 +U32 tests whether quantities of up to 4 bytes extracted from a packet 
6981 +have specified values.  The specification of what to extract is general 
6982 +enough to find data at given offsets from tcp headers or payloads.
6983 +
6984 + --u32 tests
6985 + The argument amounts to a program in a small language described below.
6986 + tests := location = value |  tests && location = value
6987 + value := range | value , range
6988 + range := number | number : number
6989 +  a single number, n, is interpreted the same as n:n
6990 +  n:m is interpreted as the range of numbers >=n and <=m
6991 + location := number | location operator number
6992 + operator := & | << | >> | @
6993 +
6994 + The operators &, <<, >>, && mean the same as in c.  The = is really a set
6995 + membership operator and the value syntax describes a set.  The @ operator
6996 + is what allows moving to the next header and is described further below.
6997 +
6998 + *** Until I can find out how to avoid it, there are some artificial limits
6999 + on the size of the tests:
7000 + - no more than 10 ='s (and 9 &&'s) in the u32 argument
7001 + - no more than 10 ranges (and 9 commas) per value
7002 + - no more than 10 numbers (and 9 operators) per location
7003 +
7004 + To describe the meaning of location, imagine the following machine that
7005 + interprets it.  There are three registers:
7006 +  A is of type char*, initially the address of the IP header
7007 +  B and C are unsigned 32 bit integers, initially zero
7008 +
7009 +  The instructions are:
7010 +   number      B = number;
7011 +               C = (*(A+B)<<24)+(*(A+B+1)<<16)+(*(A+B+2)<<8)+*(A+B+3)
7012 +   &number     C = C&number
7013 +   <<number    C = C<<number
7014 +   >>number    C = C>>number
7015 +   @number     A = A+C; then do the instruction number
7016 +  Any access of memory outside [skb->head,skb->end] causes the match to fail.
7017 +  Otherwise the result of the computation is the final value of C.
7018 +
7019 + Whitespace is allowed but not required in the tests.
7020 + However the characters that do occur there are likely to require
7021 + shell quoting, so it's a good idea to enclose the arguments in quotes.
7022 +
7023 +Example:
7024 + match IP packets with total length >= 256
7025 + The IP header contains a total length field in bytes 2-3.
7026 + --u32 "0&0xFFFF=0x100:0xFFFF" 
7027 + read bytes 0-3
7028 + AND that with FFFF (giving bytes 2-3),
7029 + and test whether that's in the range [0x100:0xFFFF]
7030 +
7031 +Example: (more realistic, hence more complicated)
7032 + match icmp packets with icmp type 0
7033 + First test that it's an icmp packet, true iff byte 9 (protocol) = 1
7034 + --u32 "6&0xFF=1 && ...
7035 + read bytes 6-9, use & to throw away bytes 6-8 and compare the result to 1
7036 + Next test that it's not a fragment.
7037 +  (If so it might be part of such a packet but we can't always tell.)
7038 +  n.b. This test is generally needed if you want to match anything
7039 +  beyond the IP header.
7040 + The last 6 bits of byte 6 and all of byte 7 are 0 iff this is a complete
7041 + packet (not a fragment).  Alternatively, you can allow first fragments
7042 + by only testing the last 5 bits of byte 6.
7043 + ... 4&0x3FFF=0 && ...
7044 + Last test: the first byte past the IP header (the type) is 0
7045 + This is where we have to use the @syntax.  The length of the IP header
7046 + (IHL) in 32 bit words is stored in the right half of byte 0 of the
7047 + IP header itself.
7048 + ... 0>>22&0x3C@0>>24=0"
7049 + The first 0 means read bytes 0-3,
7050 + >>22 means shift that 22 bits to the right.  Shifting 24 bits would give
7051 +   the first byte, so only 22 bits is four times that plus a few more bits.
7052 + &3C then eliminates the two extra bits on the right and the first four 
7053 + bits of the first byte.
7054 + For instance, if IHL=5 then the IP header is 20 (4 x 5) bytes long.
7055 + In this case bytes 0-1 are (in binary) xxxx0101 yyzzzzzz, 
7056 + >>22 gives the 10 bit value xxxx0101yy and &3C gives 010100.
7057 + @ means to use this number as a new offset into the packet, and read
7058 + four bytes starting from there.  This is the first 4 bytes of the icmp
7059 + payload, of which byte 0 is the icmp type.  Therefore we simply shift
7060 + the value 24 to the right to throw out all but the first byte and compare
7061 + the result with 0.
7062 +
7063 +Example: 
7064 + tcp payload bytes 8-12 is any of 1, 2, 5 or 8
7065 + First we test that the packet is a tcp packet (similar to icmp).
7066 + --u32 "6&0xFF=6 && ...
7067 + Next, test that it's not a fragment (same as above).
7068 + ... 0>>22&0x3C@12>>26&0x3C@8=1,2,5,8"
7069 + 0>>22&3C as above computes the number of bytes in the IP header.
7070 + @ makes this the new offset into the packet, which is the start of the
7071 + tcp header.  The length of the tcp header (again in 32 bit words) is
7072 + the left half of byte 12 of the tcp header.  The 12>>26&3C
7073 + computes this length in bytes (similar to the IP header before).
7074 + @ makes this the new offset, which is the start of the tcp payload.
7075 + Finally 8 reads bytes 8-12 of the payload and = checks whether the
7076 + result is any of 1, 2, 5 or 8
7077 +*/
7078 +
7079 +#include <linux/module.h>
7080 +#include <linux/skbuff.h>
7081 +
7082 +#include <linux/netfilter_ipv4/ipt_u32.h>
7083 +#include <linux/netfilter_ipv4/ip_tables.h>
7084 +
7085 +/* #include <asm-i386/timex.h> for timing */
7086 +
7087 +MODULE_AUTHOR("Don Cohen <don@isis.cs3-inc.com>");
7088 +MODULE_DESCRIPTION("IP tables u32 matching module");
7089 +MODULE_LICENSE("GPL");
7090 +
7091 +static int
7092 +match(const struct sk_buff *skb,
7093 +      const struct net_device *in,
7094 +      const struct net_device *out,
7095 +      const void *matchinfo,
7096 +      int offset,
7097 +      const void *hdr,
7098 +      u_int16_t datalen,
7099 +      int *hotdrop)
7100 +{
7101 +       const struct ipt_u32 *data = matchinfo;
7102 +       int testind, i;
7103 +       unsigned char* origbase = (char*)skb->nh.iph;
7104 +       unsigned char* base = origbase;
7105 +       unsigned char* head = skb->head;
7106 +       unsigned char* end = skb->end;
7107 +       int nnums, nvals;
7108 +       u_int32_t pos, val;
7109 +       /* unsigned long long cycles1, cycles2, cycles3, cycles4;
7110 +          cycles1 = get_cycles(); */
7111 +
7112 +       for (testind=0; testind < data->ntests; testind++) {
7113 +               base = origbase; /* reset for each test */
7114 +               pos = data->tests[testind].location[0].number;
7115 +               if (base+pos+3 > end || base+pos < head) 
7116 +                       return 0;
7117 +               val = (base[pos]<<24) + (base[pos+1]<<16) +
7118 +                       (base[pos+2]<<8) + base[pos+3];
7119 +               nnums = data->tests[testind].nnums;
7120 +               for (i=1; i < nnums; i++) {
7121 +                       u_int32_t number = data->tests[testind].location[i].number;
7122 +                       switch (data->tests[testind].location[i].nextop) {
7123 +                       case IPT_U32_AND: 
7124 +                               val = val & number; 
7125 +                               break;
7126 +                       case IPT_U32_LEFTSH: 
7127 +                               val = val << number;
7128 +                               break;
7129 +                       case IPT_U32_RIGHTSH: 
7130 +                               val = val >> number; 
7131 +                               break;
7132 +                       case IPT_U32_AT:
7133 +                               base = base + val;
7134 +                               pos = number;
7135 +                               if (base+pos+3 > end || base+pos < head) 
7136 +                                       return 0;
7137 +                               val = (base[pos]<<24) + (base[pos+1]<<16) +
7138 +                                       (base[pos+2]<<8) + base[pos+3];
7139 +                               break;
7140 +                       }
7141 +               }
7142 +               nvals = data->tests[testind].nvalues;
7143 +               for (i=0; i < nvals; i++) {
7144 +                       if ((data->tests[testind].value[i].min <= val) &&
7145 +                           (val <= data->tests[testind].value[i].max)) {
7146 +                               break;
7147 +                       }
7148 +               }
7149 +               if (i >= data->tests[testind].nvalues) {
7150 +                       /* cycles2 = get_cycles(); 
7151 +                          printk("failed %d in %d cycles\n", testind, 
7152 +                                 cycles2-cycles1); */
7153 +                       return 0;
7154 +               }
7155 +       }
7156 +       /* cycles2 = get_cycles();
7157 +          printk("succeeded in %d cycles\n", cycles2-cycles1); */
7158 +       return 1;
7159 +}
7160 +
7161 +static int
7162 +checkentry(const char *tablename,
7163 +           const struct ipt_ip *ip,
7164 +           void *matchinfo,
7165 +           unsigned int matchsize,
7166 +           unsigned int hook_mask)
7167 +{
7168 +       if (matchsize != IPT_ALIGN(sizeof(struct ipt_u32)))
7169 +               return 0;
7170 +       return 1;
7171 +}
7172 +
7173 +static struct ipt_match u32_match
7174 += { { NULL, NULL }, "u32", &match, &checkentry, NULL, THIS_MODULE };
7175 +
7176 +static int __init init(void)
7177 +{
7178 +       return ipt_register_match(&u32_match);
7179 +}
7180 +
7181 +static void __exit fini(void)
7182 +{
7183 +       ipt_unregister_match(&u32_match);
7184 +}
7185 +
7186 +module_init(init);
7187 +module_exit(fini);
7188 diff -Nur linux-2.6.6-rc1.org/net/ipv6/ip6_tunnel.c linux-2.6.6-rc1/net/ipv6/ip6_tunnel.c
7189 --- linux-2.6.6-rc1.org/net/ipv6/ip6_tunnel.c   2004-04-15 03:33:53.000000000 +0200
7190 +++ linux-2.6.6-rc1/net/ipv6/ip6_tunnel.c       2004-04-19 10:08:24.000000000 +0200
7191 @@ -715,13 +715,7 @@
7192         ipv6h->nexthdr = proto;
7193         ipv6_addr_copy(&ipv6h->saddr, &fl.fl6_src);
7194         ipv6_addr_copy(&ipv6h->daddr, &fl.fl6_dst);
7195 -#ifdef CONFIG_NETFILTER
7196 -       nf_conntrack_put(skb->nfct);
7197 -       skb->nfct = NULL;
7198 -#ifdef CONFIG_NETFILTER_DEBUG
7199 -       skb->nf_debug = 0;
7200 -#endif
7201 -#endif
7202 +       nf_reset(skb);
7203         pkt_len = skb->len;
7204         err = NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, 
7205                       skb->dst->dev, dst_output);
7206 diff -Nur linux-2.6.6-rc1.org/net/ipv6/netfilter/Kconfig linux-2.6.6-rc1/net/ipv6/netfilter/Kconfig
7207 --- linux-2.6.6-rc1.org/net/ipv6/netfilter/Kconfig      2004-04-19 09:59:33.000000000 +0200
7208 +++ linux-2.6.6-rc1/net/ipv6/netfilter/Kconfig  2004-04-19 10:08:38.000000000 +0200
7209 @@ -230,5 +230,30 @@
7210           <file:Documentation/modules.txt>.  If unsure, say `N'.
7211           help
7212  
7213 +config IP6_NF_TARGET_HL
7214 +       tristate  'HL target support'
7215 +       depends on IP6_NF_MANGLE
7216 +         help
7217 +
7218 +config IP6_NF_TARGET_REJECT
7219 +       tristate  'REJECT target support'
7220 +       depends on IP6_NF_FILTER
7221 +         help
7222 +
7223 +config IP6_NF_MATCH_FUZZY
7224 +       tristate  'Fuzzy match support'
7225 +       depends on IP6_NF_FILTER
7226 +         help
7227 +
7228 +config IP6_NF_MATCH_NTH
7229 +       tristate  'Nth match support'
7230 +       depends on IP6_NF_IPTABLES
7231 +         help
7232 +
7233 +config IP6_NF_MATCH_RANDOM
7234 +       tristate  'Random match support'
7235 +       depends on IP6_NF_IPTABLES
7236 +         help
7237 +
7238  endmenu
7239  
7240 diff -Nur linux-2.6.6-rc1.org/net/ipv6/netfilter/Makefile linux-2.6.6-rc1/net/ipv6/netfilter/Makefile
7241 --- linux-2.6.6-rc1.org/net/ipv6/netfilter/Makefile     2004-04-19 09:59:33.000000000 +0200
7242 +++ linux-2.6.6-rc1/net/ipv6/netfilter/Makefile 2004-04-19 10:08:38.000000000 +0200
7243 @@ -8,6 +8,7 @@
7244  obj-$(CONFIG_IP6_NF_MATCH_MARK) += ip6t_mark.o
7245  obj-$(CONFIG_IP6_NF_MATCH_LENGTH) += ip6t_length.o
7246  obj-$(CONFIG_IP6_NF_MATCH_MAC) += ip6t_mac.o
7247 +obj-$(CONFIG_IP6_NF_MATCH_FUZZY) += ip6t_fuzzy.o
7248  obj-$(CONFIG_IP6_NF_MATCH_RT) += ip6t_rt.o
7249  obj-$(CONFIG_IP6_NF_MATCH_OPTS) += ip6t_hbh.o ip6t_dst.o
7250  obj-$(CONFIG_IP6_NF_MATCH_IPV6HEADER) += ip6t_ipv6header.o
7251 @@ -19,7 +20,13 @@
7252  obj-$(CONFIG_IP6_NF_FILTER) += ip6table_filter.o
7253  obj-$(CONFIG_IP6_NF_MANGLE) += ip6table_mangle.o
7254  obj-$(CONFIG_IP6_NF_TARGET_MARK) += ip6t_MARK.o
7255 +obj-$(CONFIG_IP6_NF_TARGET_REJECT) += ip6t_REJECT.o
7256  obj-$(CONFIG_IP6_NF_QUEUE) += ip6_queue.o
7257  obj-$(CONFIG_IP6_NF_TARGET_LOG) += ip6t_LOG.o
7258 +
7259 +obj-$(CONFIG_IP6_NF_MATCH_RANDOM) += ip6t_random.o
7260 +
7261 +obj-$(CONFIG_IP6_NF_MATCH_NTH) += ip6t_nth.o
7262 +obj-$(CONFIG_IP6_NF_TARGET_HL) += ip6t_HL.o
7263  obj-$(CONFIG_IP6_NF_RAW) += ip6table_raw.o
7264  obj-$(CONFIG_IP6_NF_MATCH_HL) += ip6t_hl.o
7265 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
7266 --- linux-2.6.6-rc1.org/net/ipv6/netfilter/ip6t_HL.c    1970-01-01 01:00:00.000000000 +0100
7267 +++ linux-2.6.6-rc1/net/ipv6/netfilter/ip6t_HL.c        2004-04-19 10:08:26.000000000 +0200
7268 @@ -0,0 +1,105 @@
7269 +/* 
7270 + * Hop Limit modification target for ip6tables
7271 + * Maciej Soltysiak <solt@dns.toxicfilms.tv>
7272 + * Based on HW's TTL module
7273 + *
7274 + * This software is distributed under the terms of GNU GPL
7275 + */
7276 +
7277 +#include <linux/module.h>
7278 +#include <linux/skbuff.h>
7279 +#include <linux/ip.h>
7280 +
7281 +#include <linux/netfilter_ipv6/ip6_tables.h>
7282 +#include <linux/netfilter_ipv6/ip6t_HL.h>
7283 +
7284 +MODULE_AUTHOR("Maciej Soltysiak <solt@dns.toxicfilms.tv>");
7285 +MODULE_DESCRIPTION("IP tables Hop Limit modification module");
7286 +MODULE_LICENSE("GPL");
7287 +
7288 +static unsigned int ip6t_hl_target(struct sk_buff **pskb, unsigned int hooknum,
7289 +               const struct net_device *in, const struct net_device *out,
7290 +               const void *targinfo, void *userinfo)
7291 +{
7292 +       struct ipv6hdr *ip6h = (*pskb)->nh.ipv6h;
7293 +       const struct ip6t_HL_info *info = targinfo;
7294 +       u_int16_t diffs[2];
7295 +       int new_hl;
7296 +                        
7297 +       switch (info->mode) {
7298 +               case IP6T_HL_SET:
7299 +                       new_hl = info->hop_limit;
7300 +                       break;
7301 +               case IP6T_HL_INC:
7302 +                       new_hl = ip6h->hop_limit + info->hop_limit;
7303 +                       if (new_hl > 255)
7304 +                               new_hl = 255;
7305 +                       break;
7306 +               case IP6T_HL_DEC:
7307 +                       new_hl = ip6h->hop_limit + info->hop_limit;
7308 +                       if (new_hl < 0)
7309 +                               new_hl = 0;
7310 +                       break;
7311 +               default:
7312 +                       new_hl = ip6h->hop_limit;
7313 +                       break;
7314 +       }
7315 +
7316 +       if (new_hl != ip6h->hop_limit) {
7317 +               diffs[0] = htons(((unsigned)ip6h->hop_limit) << 8) ^ 0xFFFF;
7318 +               ip6h->hop_limit = new_hl;
7319 +               diffs[1] = htons(((unsigned)ip6h->hop_limit) << 8);
7320 +       }
7321 +
7322 +       return IP6T_CONTINUE;
7323 +}
7324 +
7325 +static int ip6t_hl_checkentry(const char *tablename,
7326 +               const struct ip6t_entry *e,
7327 +               void *targinfo,
7328 +               unsigned int targinfosize,
7329 +               unsigned int hook_mask)
7330 +{
7331 +       struct ip6t_HL_info *info = targinfo;
7332 +
7333 +       if (targinfosize != IP6T_ALIGN(sizeof(struct ip6t_HL_info))) {
7334 +               printk(KERN_WARNING "HL: targinfosize %u != %Zu\n",
7335 +                               targinfosize,
7336 +                               IP6T_ALIGN(sizeof(struct ip6t_HL_info)));
7337 +               return 0;       
7338 +       }       
7339 +
7340 +       if (strcmp(tablename, "mangle")) {
7341 +               printk(KERN_WARNING "HL: can only be called from \"mangle\" table, not \"%s\"\n", tablename);
7342 +               return 0;
7343 +       }
7344 +
7345 +       if (info->mode > IP6T_HL_MAXMODE) {
7346 +               printk(KERN_WARNING "HL: invalid or unknown Mode %u\n", 
7347 +                       info->mode);
7348 +               return 0;
7349 +       }
7350 +
7351 +       if ((info->mode != IP6T_HL_SET) && (info->hop_limit == 0)) {
7352 +               printk(KERN_WARNING "HL: increment/decrement doesn't make sense with value 0\n");
7353 +               return 0;
7354 +       }
7355 +       
7356 +       return 1;
7357 +}
7358 +
7359 +static struct ip6t_target ip6t_HL = { { NULL, NULL }, "HL", 
7360 +       ip6t_hl_target, ip6t_hl_checkentry, NULL, THIS_MODULE };
7361 +
7362 +static int __init init(void)
7363 +{
7364 +       return ip6t_register_target(&ip6t_HL);
7365 +}
7366 +
7367 +static void __exit fini(void)
7368 +{
7369 +       ip6t_unregister_target(&ip6t_HL);
7370 +}
7371 +
7372 +module_init(init);
7373 +module_exit(fini);
7374 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
7375 --- linux-2.6.6-rc1.org/net/ipv6/netfilter/ip6t_REJECT.c        1970-01-01 01:00:00.000000000 +0100
7376 +++ linux-2.6.6-rc1/net/ipv6/netfilter/ip6t_REJECT.c    2004-04-19 10:08:28.000000000 +0200
7377 @@ -0,0 +1,458 @@
7378 +/*
7379 + * IP6 tables REJECT target module
7380 + * Linux INET6 implementation
7381 + *
7382 + * Copyright (C)2003 USAGI/WIDE Project
7383 + *
7384 + * Authors:
7385 + *     Yasuyuki Kozakai        <yasuyuki.kozakai@toshiba.co.jp>
7386 + *
7387 + * Based on net/ipv4/netfilter/ipt_REJECT.c
7388 + *
7389 + * This program is free software; you can redistribute it and/or
7390 + * modify it under the terms of the GNU General Public License
7391 + * as published by the Free Software Foundation; either version
7392 + * 2 of the License, or (at your option) any later version.
7393 + */
7394 +
7395 +#include <linux/config.h>
7396 +#include <linux/module.h>
7397 +#include <linux/skbuff.h>
7398 +#include <linux/icmpv6.h>
7399 +#include <net/ipv6.h>
7400 +#include <net/tcp.h>
7401 +#include <net/icmp.h>
7402 +#include <net/ip6_fib.h>
7403 +#include <net/ip6_route.h>
7404 +#include <net/flow.h>
7405 +#include <linux/netfilter_ipv6/ip6_tables.h>
7406 +#include <linux/netfilter_ipv6/ip6t_REJECT.h>
7407 +
7408 +MODULE_AUTHOR("Yasuyuki KOZAKAI <yasuyuki.kozakai@toshiba.co.jp>");
7409 +MODULE_DESCRIPTION("IP6 tables REJECT target module");
7410 +MODULE_LICENSE("GPL");
7411 +
7412 +#if 0
7413 +#define DEBUGP printk
7414 +#else
7415 +#define DEBUGP(format, args...)
7416 +#endif
7417 +
7418 +#if 0
7419 +static void connection_attach(struct sk_buff *new_skb, struct nf_ct_info *nfct)
7420 +{
7421 +       void (*attach)(struct sk_buff *, struct nf_ct_info *);
7422 +       if (nfct && (attach = ip6_ct_attach) != NULL) {
7423 +               mb();
7424 +               attach(new_skb, nfct);
7425 +       }
7426 +}
7427 +#endif
7428 +
7429 +static int maybe_reroute(struct sk_buff *skb)
7430 +{
7431 +       if (skb->nfcache & NFC_ALTERED){
7432 +               if (ip6_route_me_harder(skb) != 0){
7433 +                       kfree_skb(skb);
7434 +                       return -EINVAL;
7435 +               }
7436 +       }
7437 +
7438 +       return dst_output(skb);
7439 +}
7440 +
7441 +/* Send RST reply */
7442 +static void send_reset(struct sk_buff *oldskb)
7443 +{
7444 +       struct sk_buff *nskb;
7445 +       struct tcphdr otcph, *tcph;
7446 +       unsigned int otcplen, tcphoff, hh_len;
7447 +       int needs_ack;
7448 +       struct ipv6hdr *oip6h = oldskb->nh.ipv6h, *ip6h;
7449 +       struct dst_entry *dst = NULL;
7450 +       u8 proto;
7451 +       struct flowi fl;
7452 +       proto = oip6h->nexthdr;
7453 +       int err;
7454 +
7455 +       if ((!(ipv6_addr_type(&oip6h->saddr) & IPV6_ADDR_UNICAST)) ||
7456 +           (!(ipv6_addr_type(&oip6h->daddr) & IPV6_ADDR_UNICAST))) {
7457 +               DEBUGP("ip6t_REJECT: addr is not unicast.\n");
7458 +               return;
7459 +       }
7460 +
7461 +       tcphoff = ipv6_skip_exthdr(oldskb, ((u8*)(oip6h+1) - oldskb->data),
7462 +                                  &proto, oldskb->len - ((u8*)(oip6h+1)
7463 +                                                         - oldskb->data));
7464 +
7465 +       if ((tcphoff < 0) || (tcphoff > oldskb->len)) {
7466 +               DEBUGP("ip6t_REJECT: Can't get TCP header.\n");
7467 +               return;
7468 +       }
7469 +
7470 +       otcplen = oldskb->len - tcphoff;
7471 +
7472 +       /* IP header checks: fragment, too short. */
7473 +       if ((proto != IPPROTO_TCP) || (otcplen < sizeof(struct tcphdr))) {
7474 +               DEBUGP("ip6t_REJECT: proto(%d) != IPPROTO_TCP, or too short. otcplen = %d\n",
7475 +                       proto, otcplen);
7476 +               return;
7477 +       }
7478 +
7479 +       if (skb_copy_bits(oldskb, tcphoff, &otcph, sizeof(struct tcphdr))) {
7480 +               if (net_ratelimit())
7481 +                       printk("ip6t_REJECT: Can't copy tcp header\n");
7482 +               return;
7483 +       }
7484 +
7485 +       /* No RST for RST. */
7486 +       if (otcph.rst) {
7487 +               DEBUGP("ip6t_REJECT: RST is set\n");
7488 +               return;
7489 +       }
7490 +
7491 +       /* Check checksum. */
7492 +       if (csum_ipv6_magic(&oip6h->saddr, &oip6h->daddr, otcplen, IPPROTO_TCP,
7493 +                           skb_checksum(oldskb, tcphoff, otcplen, 0))) {
7494 +               DEBUGP("ip6t_REJECT: TCP checksum is invalid\n");
7495 +               return;
7496 +       }
7497 +
7498 +       memset(&fl, 0, sizeof(fl));
7499 +       fl.proto = IPPROTO_TCP;
7500 +       ipv6_addr_copy(&fl.fl6_src, &oip6h->daddr);
7501 +       ipv6_addr_copy(&fl.fl6_dst, &oip6h->saddr);
7502 +       fl.fl_ip_sport = otcph.dest;
7503 +       fl.fl_ip_dport = otcph.source;
7504 +       err = ip6_dst_lookup(NULL, &dst, &fl);
7505 +       if (err) {
7506 +               if (net_ratelimit())
7507 +                       printk("ip6t_REJECT: can't find dst. err = %d\n", err);
7508 +               return;
7509 +       }
7510 +
7511 +       hh_len = (dst->dev->hard_header_len + 15)&~15;
7512 +       nskb = alloc_skb(hh_len + 15 + dst->header_len + sizeof(struct ipv6hdr)
7513 +                        + sizeof(struct tcphdr) + dst->trailer_len,
7514 +                        GFP_ATOMIC);
7515 +
7516 +       if (!nskb) {
7517 +               if (net_ratelimit())
7518 +                       printk("ip6t_REJECT: Can't alloc skb\n");
7519 +               dst_release(dst);
7520 +               return;
7521 +       }
7522 +
7523 +       nskb->dst = dst;
7524 +       dst_hold(dst);
7525 +
7526 +       skb_reserve(nskb, hh_len + dst->header_len);
7527 +
7528 +       ip6h = nskb->nh.ipv6h = (struct ipv6hdr *)
7529 +                                       skb_put(nskb, sizeof(struct ipv6hdr));
7530 +       ip6h->version = 6;
7531 +       ip6h->hop_limit = dst_metric(dst, RTAX_HOPLIMIT);
7532 +       ip6h->nexthdr = IPPROTO_TCP;
7533 +       ip6h->payload_len = htons(sizeof(struct tcphdr));
7534 +       ipv6_addr_copy(&ip6h->saddr, &oip6h->daddr);
7535 +       ipv6_addr_copy(&ip6h->daddr, &oip6h->saddr);
7536 +
7537 +       tcph = (struct tcphdr *)skb_put(nskb, sizeof(struct tcphdr));
7538 +       /* Truncate to length (no data) */
7539 +       tcph->doff = sizeof(struct tcphdr)/4;
7540 +       tcph->source = otcph.dest;
7541 +       tcph->dest = otcph.source;
7542 +
7543 +       if (otcph.ack) {
7544 +               needs_ack = 0;
7545 +               tcph->seq = otcph.ack_seq;
7546 +               tcph->ack_seq = 0;
7547 +       } else {
7548 +               needs_ack = 1;
7549 +               tcph->ack_seq = htonl(ntohl(otcph.seq) + otcph.syn + otcph.fin
7550 +                                     + otcplen - (otcph.doff<<2));
7551 +               tcph->seq = 0;
7552 +       }
7553 +
7554 +       /* Reset flags */
7555 +       ((u_int8_t *)tcph)[13] = 0;
7556 +       tcph->rst = 1;
7557 +       tcph->ack = needs_ack;
7558 +       tcph->window = 0;
7559 +       tcph->urg_ptr = 0;
7560 +       tcph->check = 0;
7561 +
7562 +       /* Adjust TCP checksum */
7563 +       tcph->check = csum_ipv6_magic(&nskb->nh.ipv6h->saddr,
7564 +                                     &nskb->nh.ipv6h->daddr,
7565 +                                     sizeof(struct tcphdr), IPPROTO_TCP,
7566 +                                     csum_partial((char *)tcph,
7567 +                                                  sizeof(struct tcphdr), 0));
7568 +
7569 +#if 0
7570 +       connection_attach(nskb, oldskb->nfct);
7571 +#endif
7572 +
7573 +       NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, nskb, NULL, nskb->dst->dev,
7574 +               maybe_reroute);
7575 +
7576 +       dst_release(dst);
7577 +}
7578 +
7579 +static void send_unreach(struct sk_buff *skb_in, unsigned char code)
7580 +{
7581 +       struct ipv6hdr *ip6h, *hdr = skb_in->nh.ipv6h;
7582 +       struct icmp6hdr *icmp6h;
7583 +       struct dst_entry *dst = NULL;
7584 +       struct rt6_info *rt;
7585 +       int tmo;
7586 +       __u32 csum;
7587 +       unsigned int len, datalen, hh_len;
7588 +       int saddr_type, daddr_type;
7589 +       unsigned int ptr, ip6off;
7590 +       u8 proto;
7591 +       struct flowi fl;
7592 +       struct sk_buff *nskb;
7593 +       char *data;
7594 +
7595 +       saddr_type = ipv6_addr_type(&hdr->saddr);
7596 +       daddr_type = ipv6_addr_type(&hdr->daddr);
7597 +
7598 +       if ((!(saddr_type & IPV6_ADDR_UNICAST)) ||
7599 +           (!(daddr_type & IPV6_ADDR_UNICAST))) {
7600 +               DEBUGP("ip6t_REJECT: addr is not unicast.\n");
7601 +               return;
7602 +       }
7603 +
7604 +       ip6off = skb_in->nh.raw - skb_in->data;
7605 +       proto = hdr->nexthdr;
7606 +       ptr = ipv6_skip_exthdr(skb_in, ip6off + sizeof(struct ipv6hdr), &proto,
7607 +                              skb_in->len - ip6off);
7608 +
7609 +       if ((ptr < 0) || (ptr > skb_in->len)) {
7610 +               ptr = ip6off + sizeof(struct ipv6hdr);
7611 +               proto = hdr->nexthdr;
7612 +       } else if (proto == IPPROTO_ICMPV6) {
7613 +                u8 type;
7614 +
7615 +                if (skb_copy_bits(skb_in, ptr + offsetof(struct icmp6hdr,
7616 +                                                     icmp6_type), &type, 1)) {
7617 +                       DEBUGP("ip6t_REJECT: Can't get ICMPv6 type\n");
7618 +                       return;
7619 +               }
7620 +
7621 +               if (!(type & ICMPV6_INFOMSG_MASK)) {
7622 +                       DEBUGP("ip6t_REJECT: no reply to icmp error\n");
7623 +                       return;
7624 +               }
7625 +        } else if (proto == IPPROTO_UDP) {
7626 +               int plen = skb_in->len - (ptr - ip6off);
7627 +               uint16_t check;
7628 +
7629 +               if (plen < sizeof(struct udphdr)) {
7630 +                       DEBUGP("ip6t_REJECT: too short\n");
7631 +                       return;
7632 +               }
7633 +
7634 +               if (skb_copy_bits(skb_in, ptr + offsetof(struct udphdr, check),
7635 +                                 &check, 2)) {
7636 +                       if (net_ratelimit())
7637 +                               printk("ip6t_REJECT: can't get copy from skb");
7638 +                       return;
7639 +               }
7640 +
7641 +               if (check &&
7642 +                   csum_ipv6_magic(&hdr->saddr, &hdr->daddr, plen,
7643 +                                   IPPROTO_UDP,
7644 +                                   skb_checksum(skb_in, ptr, plen, 0))) {
7645 +                       DEBUGP("ip6t_REJECT: UDP checksum is invalid.\n");
7646 +                       return;
7647 +               }
7648 +       }
7649 +
7650 +       memset(&fl, 0, sizeof(fl));
7651 +       fl.proto = IPPROTO_ICMPV6;
7652 +       ipv6_addr_copy(&fl.fl6_src, &hdr->daddr);
7653 +       ipv6_addr_copy(&fl.fl6_dst, &hdr->saddr);
7654 +       fl.fl_icmp_type = ICMPV6_DEST_UNREACH;
7655 +       fl.fl_icmp_code = code;
7656 +
7657 +       if (ip6_dst_lookup(NULL, &dst, &fl)) {
7658 +               return;
7659 +       }
7660 +
7661 +       rt = (struct rt6_info *)dst;
7662 +       tmo = 1*HZ;
7663 +
7664 +       if (rt->rt6i_dst.plen < 128)
7665 +               tmo >>= ((128 - rt->rt6i_dst.plen)>>5);
7666 +
7667 +       if (!xrlim_allow(dst, tmo)) {
7668 +               if (net_ratelimit())
7669 +                       printk("ip6t_REJECT: rate limitted\n");
7670 +               goto dst_release_out;
7671 +       }
7672 +
7673 +       len = skb_in->len + sizeof(struct ipv6hdr) + sizeof(struct icmp6hdr);
7674 +
7675 +       if (len > dst_pmtu(dst))
7676 +               len = dst_pmtu(dst);
7677 +       if (len > IPV6_MIN_MTU)
7678 +               len = IPV6_MIN_MTU;
7679 +
7680 +       datalen = len - sizeof(struct ipv6hdr) - sizeof(struct icmp6hdr);
7681 +       hh_len = (rt->u.dst.dev->hard_header_len + 15)&~15;
7682 +
7683 +       nskb = alloc_skb(hh_len + 15 + dst->header_len + dst->trailer_len + len,
7684 +                        GFP_ATOMIC);
7685 +
7686 +       if (!nskb) {
7687 +               if (net_ratelimit())
7688 +                       printk("ip6t_REJECT: can't alloc skb\n");
7689 +               goto dst_release_out;
7690 +       }
7691 +
7692 +       nskb->priority = 0;
7693 +       nskb->dst = dst;
7694 +       dst_hold(dst);
7695 +
7696 +       skb_reserve(nskb, hh_len + dst->header_len);
7697 +
7698 +       ip6h = nskb->nh.ipv6h = (struct ipv6hdr *)
7699 +                                       skb_put(nskb, sizeof(struct ipv6hdr));
7700 +       ip6h->version = 6;
7701 +       ip6h->hop_limit = dst_metric(dst, RTAX_HOPLIMIT);
7702 +       ip6h->nexthdr = IPPROTO_ICMPV6;
7703 +       ip6h->payload_len = htons(datalen + sizeof(struct icmp6hdr));
7704 +       ipv6_addr_copy(&ip6h->saddr, &hdr->daddr);
7705 +       ipv6_addr_copy(&ip6h->daddr, &hdr->saddr);
7706 +
7707 +       icmp6h = (struct icmp6hdr *) skb_put(nskb, sizeof(struct icmp6hdr));
7708 +       icmp6h->icmp6_type = ICMPV6_DEST_UNREACH;
7709 +       icmp6h->icmp6_code = code;
7710 +       icmp6h->icmp6_cksum = 0;
7711 +
7712 +       data = skb_put(nskb, datalen);
7713 +
7714 +       csum = csum_partial((unsigned char *)icmp6h, sizeof(struct icmp6hdr), 0);
7715 +       csum = skb_copy_and_csum_bits(skb_in, ip6off, data, datalen, csum);
7716 +       icmp6h->icmp6_cksum = csum_ipv6_magic(&hdr->saddr, &hdr->daddr,
7717 +                                            datalen + sizeof(struct icmp6hdr),
7718 +                                            IPPROTO_ICMPV6, csum);
7719 +
7720 +#if 0
7721 +       connection_attach(nskb, skb_in->nfct);
7722 +#endif
7723 +       NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, nskb, NULL, nskb->dst->dev,
7724 +               maybe_reroute);
7725 +
7726 +dst_release_out:
7727 +       dst_release(dst);
7728 +}
7729 +
7730 +static unsigned int reject6_target(struct sk_buff **pskb,
7731 +                          unsigned int hooknum,
7732 +                          const struct net_device *in,
7733 +                          const struct net_device *out,
7734 +                          const void *targinfo,
7735 +                          void *userinfo)
7736 +{
7737 +       const struct ip6t_reject_info *reject = targinfo;
7738 +
7739 +       DEBUGP(KERN_DEBUG "%s: medium point\n", __FUNCTION__);
7740 +       /* WARNING: This code causes reentry within ip6tables.
7741 +          This means that the ip6tables jump stack is now crap.  We
7742 +          must return an absolute verdict. --RR */
7743 +       switch (reject->with) {
7744 +       case IP6T_ICMP6_NO_ROUTE:
7745 +               send_unreach(*pskb, ICMPV6_NOROUTE);
7746 +               break;
7747 +       case IP6T_ICMP6_ADM_PROHIBITED:
7748 +               send_unreach(*pskb, ICMPV6_ADM_PROHIBITED);
7749 +               break;
7750 +       case IP6T_ICMP6_NOT_NEIGHBOUR:
7751 +               send_unreach(*pskb, ICMPV6_NOT_NEIGHBOUR);
7752 +               break;
7753 +       case IP6T_ICMP6_ADDR_UNREACH:
7754 +               send_unreach(*pskb, ICMPV6_ADDR_UNREACH);
7755 +               break;
7756 +       case IP6T_ICMP6_PORT_UNREACH:
7757 +               send_unreach(*pskb, ICMPV6_PORT_UNREACH);
7758 +               break;
7759 +       case IP6T_ICMP6_ECHOREPLY:
7760 +               /* Do nothing */
7761 +               break;
7762 +       case IP6T_TCP_RESET:
7763 +               send_reset(*pskb);
7764 +               break;
7765 +       default:
7766 +               if (net_ratelimit())
7767 +                       printk(KERN_WARNING "ip6t_REJECT: case %u not handled yet\n", reject->with);
7768 +               break;
7769 +       }
7770 +
7771 +       return NF_DROP;
7772 +}
7773 +
7774 +static int check(const char *tablename,
7775 +                const struct ip6t_entry *e,
7776 +                void *targinfo,
7777 +                unsigned int targinfosize,
7778 +                unsigned int hook_mask)
7779 +{
7780 +       const struct ip6t_reject_info *rejinfo = targinfo;
7781 +
7782 +       if (targinfosize != IP6T_ALIGN(sizeof(struct ip6t_reject_info))) {
7783 +               DEBUGP("ip6t_REJECT: targinfosize %u != 0\n", targinfosize);
7784 +               return 0;
7785 +       }
7786 +
7787 +       /* Only allow these for packet filtering. */
7788 +       if (strcmp(tablename, "filter") != 0) {
7789 +               DEBUGP("ip6t_REJECT: bad table `%s'.\n", tablename);
7790 +               return 0;
7791 +       }
7792 +
7793 +       if ((hook_mask & ~((1 << NF_IP6_LOCAL_IN)
7794 +                          | (1 << NF_IP6_FORWARD)
7795 +                          | (1 << NF_IP6_LOCAL_OUT))) != 0) {
7796 +               DEBUGP("ip6t_REJECT: bad hook mask %X\n", hook_mask);
7797 +               return 0;
7798 +       }
7799 +
7800 +       if (rejinfo->with == IP6T_ICMP6_ECHOREPLY) {
7801 +               printk("ip6t_REJECT: ECHOREPLY is not supported.\n");
7802 +               return 0;
7803 +       } else if (rejinfo->with == IP6T_TCP_RESET) {
7804 +               /* Must specify that it's a TCP packet */
7805 +               if (e->ipv6.proto != IPPROTO_TCP
7806 +                   || (e->ipv6.invflags & IP6T_INV_PROTO)) {
7807 +                       DEBUGP("ip6t_REJECT: TCP_RESET illegal for non-tcp\n");
7808 +                       return 0;
7809 +               }
7810 +       }
7811 +
7812 +       return 1;
7813 +}
7814 +
7815 +static struct ip6t_target ip6t_reject_reg = {
7816 +       .name           = "REJECT",
7817 +       .target         = reject6_target,
7818 +       .checkentry     = check,
7819 +       .me             = THIS_MODULE
7820 +};
7821 +
7822 +static int __init init(void)
7823 +{
7824 +       if (ip6t_register_target(&ip6t_reject_reg))
7825 +               return -EINVAL;
7826 +       return 0;
7827 +}
7828 +
7829 +static void __exit fini(void)
7830 +{
7831 +       ip6t_unregister_target(&ip6t_reject_reg);
7832 +}
7833 +
7834 +module_init(init);
7835 +module_exit(fini);
7836 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
7837 --- linux-2.6.6-rc1.org/net/ipv6/netfilter/ip6t_fuzzy.c 1970-01-01 01:00:00.000000000 +0100
7838 +++ linux-2.6.6-rc1/net/ipv6/netfilter/ip6t_fuzzy.c     2004-04-19 10:08:31.000000000 +0200
7839 @@ -0,0 +1,189 @@
7840 +/*
7841 + * This module implements a simple TSK FLC
7842 + * (Takagi-Sugeno-Kang Fuzzy Logic Controller) that aims
7843 + * to limit , in an adaptive and flexible way , the packet rate crossing
7844 + * a given stream . It serves as an initial and very simple (but effective)
7845 + * example of how Fuzzy Logic techniques can be applied to defeat DoS attacks.
7846 + *  As a matter of fact , Fuzzy Logic can help us to insert any "behavior"
7847 + * into our code in a precise , adaptive and efficient manner.
7848 + *  The goal is very similar to that of "limit" match , but using techniques of
7849 + * Fuzzy Control , that allow us to shape the transfer functions precisely ,
7850 + * avoiding over and undershoots - and stuff like that .
7851 + *
7852 + *
7853 + * 2002-08-10  Hime Aguiar e Oliveira Jr. <hime@engineer.com> : Initial version.
7854 + * 2002-08-17  : Changed to eliminate floating point operations .
7855 + * 2002-08-23  : Coding style changes .
7856 + * 2003-04-08  Maciej Soltysiak <solt@dns.toxicilms.tv> : IPv6 Port
7857 + */
7858 +
7859 +#include <linux/module.h>
7860 +#include <linux/skbuff.h>
7861 +#include <linux/ipv6.h>
7862 +#include <linux/random.h>
7863 +#include <net/tcp.h>
7864 +#include <linux/spinlock.h>
7865 +#include <linux/netfilter_ipv6/ip6_tables.h>
7866 +#include <linux/netfilter_ipv6/ip6t_fuzzy.h>
7867 +
7868 +/*
7869 + Packet Acceptance Rate - LOW and Packet Acceptance Rate - HIGH
7870 + Expressed in percentage
7871 +*/
7872 +
7873 +#define PAR_LOW                1/100
7874 +#define PAR_HIGH       1
7875 +
7876 +static spinlock_t fuzzy_lock = SPIN_LOCK_UNLOCKED;
7877 +
7878 +MODULE_AUTHOR("Hime Aguiar e Oliveira Junior <hime@engineer.com>");
7879 +MODULE_DESCRIPTION("IP tables Fuzzy Logic Controller match module");
7880 +MODULE_LICENSE("GPL");
7881 +
7882 +static  u_int8_t mf_high(u_int32_t tx,u_int32_t mini,u_int32_t maxi)
7883 +{
7884 +       if (tx >= maxi) return 100;
7885 +
7886 +       if (tx <= mini) return 0;
7887 +
7888 +       return ((100 * (tx-mini)) / (maxi-mini));
7889 +}
7890 +
7891 +static u_int8_t mf_low(u_int32_t tx,u_int32_t mini,u_int32_t maxi)
7892 +{
7893 +       if (tx <= mini) return 100;
7894 +
7895 +       if (tx >= maxi) return 0;
7896 +
7897 +       return ((100 * (maxi - tx)) / (maxi - mini));
7898 +
7899 +}
7900 +
7901 +static int
7902 +ip6t_fuzzy_match(const struct sk_buff *pskb,
7903 +              const struct net_device *in,
7904 +              const struct net_device *out,
7905 +              const void *matchinfo,
7906 +              int offset,
7907 +              const void *hdr,
7908 +              u_int16_t datalen,
7909 +              int *hotdrop)
7910 +{
7911 +       /* From userspace */
7912 +
7913 +       struct ip6t_fuzzy_info *info = (struct ip6t_fuzzy_info *) matchinfo;
7914 +
7915 +       u_int8_t random_number;
7916 +       unsigned long amount;
7917 +       u_int8_t howhigh, howlow;
7918 +
7919 +
7920 +       spin_lock_bh(&fuzzy_lock); /* Rise the lock */
7921 +
7922 +       info->bytes_total += pskb->len;
7923 +       info->packets_total++;
7924 +
7925 +       info->present_time = jiffies;
7926 +
7927 +       if (info->present_time >= info->previous_time)
7928 +               amount = info->present_time - info->previous_time;
7929 +       else {
7930 +               /* There was a transition : I choose to re-sample
7931 +                  and keep the old acceptance rate...
7932 +               */
7933 +
7934 +               amount = 0;
7935 +               info->previous_time = info->present_time;
7936 +               info->bytes_total = info->packets_total = 0;
7937 +            };
7938 +
7939 +       if ( amount > HZ/10) {/* More than 100 ms elapsed ... */
7940 +
7941 +               info->mean_rate = (u_int32_t) ((HZ * info->packets_total) \
7942 +                                       / amount);
7943 +
7944 +               info->previous_time = info->present_time;
7945 +               info->bytes_total = info->packets_total = 0;
7946 +
7947 +               howhigh = mf_high(info->mean_rate,info->minimum_rate,info->maximum_rate);
7948 +               howlow  = mf_low(info->mean_rate,info->minimum_rate,info->maximum_rate);
7949 +
7950 +               info->acceptance_rate = (u_int8_t) \
7951 +                               (howhigh * PAR_LOW + PAR_HIGH * howlow);
7952 +
7953 +       /* In fact, the above defuzzification would require a denominator
7954 +        * proportional to (howhigh+howlow) but, in this particular case,
7955 +        * that expression is constant.
7956 +        * An imediate consequence is that it is not necessary to call
7957 +        * both mf_high and mf_low - but to keep things understandable,
7958 +        * I did so.
7959 +        */
7960 +
7961 +       }
7962 +
7963 +       spin_unlock_bh(&fuzzy_lock); /* Release the lock */
7964 +
7965 +
7966 +       if (info->acceptance_rate < 100)
7967 +       {
7968 +               get_random_bytes((void *)(&random_number), 1);
7969 +
7970 +               /*  If within the acceptance , it can pass => don't match */
7971 +               if (random_number <= (255 * info->acceptance_rate) / 100)
7972 +                       return 0;
7973 +               else
7974 +                       return 1; /* It can't pass (It matches) */
7975 +       };
7976 +
7977 +       return 0; /* acceptance_rate == 100 % => Everything passes ... */
7978 +
7979 +}
7980 +
7981 +static int
7982 +ip6t_fuzzy_checkentry(const char *tablename,
7983 +                  const struct ip6t_ip6 *ip,
7984 +                  void *matchinfo,
7985 +                  unsigned int matchsize,
7986 +                  unsigned int hook_mask)
7987 +{
7988 +
7989 +       const struct ip6t_fuzzy_info *info = matchinfo;
7990 +
7991 +       if (matchsize != IP6T_ALIGN(sizeof(struct ip6t_fuzzy_info))) {
7992 +               printk("ip6t_fuzzy: matchsize %u != %u\n", matchsize,
7993 +                      IP6T_ALIGN(sizeof(struct ip6t_fuzzy_info)));
7994 +               return 0;
7995 +       }
7996 +
7997 +       if ((info->minimum_rate < MINFUZZYRATE) || (info->maximum_rate > MAXFUZZYRATE)
7998 +        || (info->minimum_rate >= info->maximum_rate)) {
7999 +               printk("ip6t_fuzzy: BAD limits , please verify !!!\n");
8000 +               return 0;
8001 +       }
8002 +
8003 +       return 1;
8004 +}
8005 +
8006 +static struct ip6t_match ip6t_fuzzy_reg = {
8007 +       {NULL, NULL},
8008 +       "fuzzy",
8009 +       ip6t_fuzzy_match,
8010 +       ip6t_fuzzy_checkentry,
8011 +       NULL,
8012 +       THIS_MODULE };
8013 +
8014 +static int __init init(void)
8015 +{
8016 +       if (ip6t_register_match(&ip6t_fuzzy_reg))
8017 +               return -EINVAL;
8018 +
8019 +       return 0;
8020 +}
8021 +
8022 +static void __exit fini(void)
8023 +{
8024 +       ip6t_unregister_match(&ip6t_fuzzy_reg);
8025 +}
8026 +
8027 +module_init(init);
8028 +module_exit(fini);
8029 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
8030 --- linux-2.6.6-rc1.org/net/ipv6/netfilter/ip6t_nth.c   1970-01-01 01:00:00.000000000 +0100
8031 +++ linux-2.6.6-rc1/net/ipv6/netfilter/ip6t_nth.c       2004-04-19 10:08:34.000000000 +0200
8032 @@ -0,0 +1,173 @@
8033 +/*
8034 +  This is a module which is used for match support for every Nth packet
8035 +  This file is distributed under the terms of the GNU General Public
8036 +  License (GPL). Copies of the GPL can be obtained from:
8037 +     ftp://prep.ai.mit.edu/pub/gnu/GPL
8038 +
8039 +  2001-07-18 Fabrice MARIE <fabrice@netfilter.org> : initial implementation.
8040 +  2001-09-20 Richard Wagner (rwagner@cloudnet.com)
8041 +        * added support for multiple counters
8042 +        * added support for matching on individual packets
8043 +          in the counter cycle
8044 +  2003-04-30 Maciej Soltysiak <solt@dns.toxicfilms.tv> : IPv6 Port
8045 +
8046 +*/
8047 +
8048 +#include <linux/module.h>
8049 +#include <linux/skbuff.h>
8050 +#include <linux/ip.h>
8051 +#include <net/tcp.h>
8052 +#include <linux/spinlock.h>
8053 +#include <linux/netfilter_ipv6/ip6_tables.h>
8054 +#include <linux/netfilter_ipv6/ip6t_nth.h>
8055 +
8056 +MODULE_LICENSE("GPL");
8057 +
8058 +/*
8059 + * State information.
8060 + */
8061 +struct state {
8062 +       spinlock_t lock;
8063 +       u_int16_t number;
8064 +};
8065 +
8066 +static struct state states[IP6T_NTH_NUM_COUNTERS];
8067 +
8068 +static int
8069 +ip6t_nth_match(const struct sk_buff *pskb,
8070 +             const struct net_device *in,
8071 +             const struct net_device *out,
8072 +             const void *matchinfo,
8073 +             int offset,
8074 +             const void *hdr,
8075 +             u_int16_t datalen,
8076 +             int *hotdrop)
8077 +{
8078 +       /* Parameters from userspace */
8079 +       const struct ip6t_nth_info *info = matchinfo;
8080 +        unsigned counter = info->counter;
8081 +               if((counter < 0) || (counter >= IP6T_NTH_NUM_COUNTERS)) 
8082 +       {
8083 +                       printk(KERN_WARNING "nth: invalid counter %u. counter between 0 and %u\n", counter, IP6T_NTH_NUM_COUNTERS-1);
8084 +               return 0;
8085 +        };
8086 +
8087 +        spin_lock(&states[counter].lock);
8088 +
8089 +        /* Are we matching every nth packet?*/
8090 +        if (info->packet == 0xFF)
8091 +        {
8092 +               /* We're matching every nth packet and only every nth packet*/
8093 +               /* Do we match or invert match? */
8094 +               if (info->not == 0)
8095 +               {
8096 +                       if (states[counter].number == 0)
8097 +                       {
8098 +                               ++states[counter].number;
8099 +                               goto match;
8100 +                       }
8101 +                       if (states[counter].number >= info->every)
8102 +                               states[counter].number = 0; /* reset the counter */
8103 +                       else
8104 +                               ++states[counter].number;
8105 +                       goto dontmatch;
8106 +               }
8107 +               else
8108 +               {
8109 +                       if (states[counter].number == 0)
8110 +                       {
8111 +                               ++states[counter].number;
8112 +                               goto dontmatch;
8113 +                       }
8114 +                       if (states[counter].number >= info->every)
8115 +                               states[counter].number = 0;
8116 +                       else
8117 +                               ++states[counter].number;
8118 +                       goto match;
8119 +               }
8120 +        }
8121 +        else
8122 +        {
8123 +               /* We're using the --packet, so there must be a rule for every value */
8124 +               if (states[counter].number == info->packet)
8125 +               {
8126 +                       /* only increment the counter when a match happens */
8127 +                       if (states[counter].number >= info->every)
8128 +                               states[counter].number = 0; /* reset the counter */
8129 +                       else
8130 +                               ++states[counter].number;
8131 +                       goto match;
8132 +               }
8133 +               else
8134 +                       goto dontmatch;
8135 +       }
8136 +
8137 + dontmatch:
8138 +       /* don't match */
8139 +       spin_unlock(&states[counter].lock);
8140 +       return 0;
8141 +
8142 + match:
8143 +       spin_unlock(&states[counter].lock);
8144 +       return 1;
8145 +}
8146 +
8147 +static int
8148 +ip6t_nth_checkentry(const char *tablename,
8149 +                  const struct ip6t_ip6 *e,
8150 +                  void *matchinfo,
8151 +                  unsigned int matchsize,
8152 +                  unsigned int hook_mask)
8153 +{
8154 +       /* Parameters from userspace */
8155 +       const struct ip6t_nth_info *info = matchinfo;
8156 +        unsigned counter = info->counter;
8157 +        if((counter < 0) || (counter >= IP6T_NTH_NUM_COUNTERS)) 
8158 +       {
8159 +               printk(KERN_WARNING "nth: invalid counter %u. counter between 0 and %u\n", counter, IP6T_NTH_NUM_COUNTERS-1);
8160 +                       return 0;
8161 +               };
8162 +
8163 +       if (matchsize != IP6T_ALIGN(sizeof(struct ip6t_nth_info))) {
8164 +               printk("nth: matchsize %u != %u\n", matchsize,
8165 +                      IP6T_ALIGN(sizeof(struct ip6t_nth_info)));
8166 +               return 0;
8167 +       }
8168 +
8169 +       states[counter].number = info->startat;
8170 +
8171 +       return 1;
8172 +}
8173 +
8174 +static struct ip6t_match ip6t_nth_reg = { 
8175 +       {NULL, NULL},
8176 +       "nth",
8177 +       ip6t_nth_match,
8178 +       ip6t_nth_checkentry,
8179 +       NULL,
8180 +       THIS_MODULE };
8181 +
8182 +static int __init init(void)
8183 +{
8184 +       unsigned counter;
8185 +        memset(&states, 0, sizeof(states));
8186 +       if (ip6t_register_match(&ip6t_nth_reg))
8187 +               return -EINVAL;
8188 +
8189 +        for(counter = 0; counter < IP6T_NTH_NUM_COUNTERS; counter++) 
8190 +       {
8191 +               spin_lock_init(&(states[counter].lock));
8192 +        };
8193 +
8194 +       printk("ip6t_nth match loaded\n");
8195 +       return 0;
8196 +}
8197 +
8198 +static void __exit fini(void)
8199 +{
8200 +       ip6t_unregister_match(&ip6t_nth_reg);
8201 +       printk("ip6t_nth match unloaded\n");
8202 +}
8203 +
8204 +module_init(init);
8205 +module_exit(fini);
8206 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
8207 --- linux-2.6.6-rc1.org/net/ipv6/netfilter/ip6t_random.c        1970-01-01 01:00:00.000000000 +0100
8208 +++ linux-2.6.6-rc1/net/ipv6/netfilter/ip6t_random.c    2004-04-19 10:08:38.000000000 +0200
8209 @@ -0,0 +1,97 @@
8210 +/*
8211 +  This is a module which is used for a "random" match support.
8212 +  This file is distributed under the terms of the GNU General Public
8213 +  License (GPL). Copies of the GPL can be obtained from:
8214 +     ftp://prep.ai.mit.edu/pub/gnu/GPL
8215 +
8216 +  2001-10-14 Fabrice MARIE <fabrice@netfilter.org> : initial implementation.
8217 +  2003-04-30 Maciej Soltysiak <solt@dns.toxicfilms.tv> : IPv6 Port
8218 +*/
8219 +
8220 +#include <linux/module.h>
8221 +#include <linux/skbuff.h>
8222 +#include <linux/ip.h>
8223 +#include <linux/random.h>
8224 +#include <net/tcp.h>
8225 +#include <linux/spinlock.h>
8226 +#include <linux/netfilter_ipv6/ip6_tables.h>
8227 +#include <linux/netfilter_ipv6/ip6t_random.h>
8228 +
8229 +MODULE_LICENSE("GPL");
8230 +
8231 +static int
8232 +ip6t_rand_match(const struct sk_buff *pskb,
8233 +              const struct net_device *in,
8234 +              const struct net_device *out,
8235 +              const void *matchinfo,
8236 +              int offset,
8237 +              const void *hdr,
8238 +              u_int16_t datalen,
8239 +              int *hotdrop)
8240 +{
8241 +       /* Parameters from userspace */
8242 +       const struct ip6t_rand_info *info = matchinfo;
8243 +       u_int8_t random_number;
8244 +
8245 +       /* get 1 random number from the kernel random number generation routine */
8246 +       get_random_bytes((void *)(&random_number), 1);
8247 +
8248 +       /* Do we match ? */
8249 +       if (random_number <= info->average)
8250 +               return 1;
8251 +       else
8252 +               return 0;
8253 +}
8254 +
8255 +static int
8256 +ip6t_rand_checkentry(const char *tablename,
8257 +                  const struct ip6t_ip6 *e,
8258 +                  void *matchinfo,
8259 +                  unsigned int matchsize,
8260 +                  unsigned int hook_mask)
8261 +{
8262 +       /* Parameters from userspace */
8263 +       const struct ip6t_rand_info *info = matchinfo;
8264 +
8265 +       if (matchsize != IP6T_ALIGN(sizeof(struct ip6t_rand_info))) {
8266 +               printk("ip6t_random: matchsize %u != %u\n", matchsize,
8267 +                      IP6T_ALIGN(sizeof(struct ip6t_rand_info)));
8268 +               return 0;
8269 +       }
8270 +
8271 +       /* must be  1 <= average % <= 99 */
8272 +       /* 1  x 2.55 = 2   */
8273 +       /* 99 x 2.55 = 252 */
8274 +       if ((info->average < 2) || (info->average > 252)) {
8275 +               printk("ip6t_random:  invalid average %u\n", info->average);
8276 +               return 0;
8277 +       }
8278 +
8279 +       return 1;
8280 +}
8281 +
8282 +static struct ip6t_match ip6t_rand_reg = { 
8283 +       {NULL, NULL},
8284 +       "random",
8285 +       ip6t_rand_match,
8286 +       ip6t_rand_checkentry,
8287 +       NULL,
8288 +       THIS_MODULE };
8289 +
8290 +static int __init init(void)
8291 +{
8292 +       if (ip6t_register_match(&ip6t_rand_reg))
8293 +               return -EINVAL;
8294 +
8295 +       printk("ip6t_random match loaded\n");
8296 +       return 0;
8297 +}
8298 +
8299 +static void __exit fini(void)
8300 +{
8301 +       ip6t_unregister_match(&ip6t_rand_reg);
8302 +       printk("ip6t_random match unloaded\n");
8303 +}
8304 +
8305 +module_init(init);
8306 +module_exit(fini);
8307 diff -Nur linux-2.6.6-rc1.org/net/ipv6/sit.c linux-2.6.6-rc1/net/ipv6/sit.c
8308 --- linux-2.6.6-rc1.org/net/ipv6/sit.c  2004-04-15 03:35:37.000000000 +0200
8309 +++ linux-2.6.6-rc1/net/ipv6/sit.c      2004-04-19 10:08:24.000000000 +0200
8310 @@ -388,13 +388,7 @@
8311                 skb->dev = tunnel->dev;
8312                 dst_release(skb->dst);
8313                 skb->dst = NULL;
8314 -#ifdef CONFIG_NETFILTER
8315 -               nf_conntrack_put(skb->nfct);
8316 -               skb->nfct = NULL;
8317 -#ifdef CONFIG_NETFILTER_DEBUG
8318 -               skb->nf_debug = 0;
8319 -#endif
8320 -#endif
8321 +               nf_reset(skb);
8322                 ipip6_ecn_decapsulate(iph, skb);
8323                 netif_rx(skb);
8324                 read_unlock(&ipip6_lock);
8325 @@ -580,13 +574,7 @@
8326         if ((iph->ttl = tiph->ttl) == 0)
8327                 iph->ttl        =       iph6->hop_limit;
8328  
8329 -#ifdef CONFIG_NETFILTER
8330 -       nf_conntrack_put(skb->nfct);
8331 -       skb->nfct = NULL;
8332 -#ifdef CONFIG_NETFILTER_DEBUG
8333 -       skb->nf_debug = 0;
8334 -#endif
8335 -#endif
8336 +       nf_reset(skb);
8337  
8338         IPTUNNEL_XMIT();
8339         tunnel->recursion--;
This page took 0.755131 seconds and 3 git commands to generate.