]> git.pld-linux.org Git - packages/kernel.git/blob - 2.6.6-rc1-patch-o-matic-ng-base-20040419.patch
- minor fix. it builds but linking needs fix.
[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,334 @@
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 +EXPORT_SYMBOL(ip_pool_match);
2728 +
2729 +static int pool_change(ip_pool_t index, u_int32_t addr, int isdel)
2730 +{
2731 +       struct ip_pool *pool;
2732 +       int res = -1;
2733 +
2734 +       pool = lookup(index);
2735 +       if (    !pool || !pool->members
2736 +            || addr < pool->first_ip || addr > pool->last_ip)
2737 +               return -1;
2738 +       read_lock_bh(&pool->lock);
2739 +       if (pool->members && addr >= pool->first_ip && addr <= pool->last_ip) {
2740 +               addr -= pool->first_ip;
2741 +               res = isdel
2742 +                       ? (0 != test_and_clear_bit(addr, pool->members))
2743 +                       : (0 != test_and_set_bit(addr, pool->members));
2744 +       }
2745 +       read_unlock_bh(&pool->lock);
2746 +       return res;
2747 +}
2748 +
2749 +int ip_pool_mod(ip_pool_t index, u_int32_t addr, int isdel)
2750 +{
2751 +       int res = pool_change(index,addr,isdel);
2752 +
2753 +       if (!isdel) res = !res;
2754 +       return res;
2755 +}
2756 +EXPORT_SYMBOL(ip_pool_mod);
2757 +
2758 +static inline int bitmap_bytes(u_int32_t a, u_int32_t b)
2759 +{
2760 +       return 4*((((b-a+8)/8)+3)/4);
2761 +}
2762 +
2763 +static inline int poolbytes(ip_pool_t index)
2764 +{
2765 +       struct ip_pool *pool = lookup(index);
2766 +
2767 +       return pool ? bitmap_bytes(pool->first_ip, pool->last_ip) : 0;
2768 +}
2769 +
2770 +static int setpool(
2771 +       struct sock *sk,
2772 +       int optval,
2773 +       void *user,
2774 +       unsigned int len
2775 +) {
2776 +       struct ip_pool_request req;
2777 +
2778 +       DP("ip_pool:setpool: optval=%d, user=%p, len=%d\n", optval, user, len);
2779 +       if (!capable(CAP_NET_ADMIN))
2780 +               return -EPERM;
2781 +       if (optval != SO_IP_POOL)
2782 +               return -EBADF;
2783 +       if (len != sizeof(req))
2784 +               return -EINVAL;
2785 +       if (copy_from_user(&req, user, sizeof(req)) != 0)
2786 +               return -EFAULT;
2787 +       printk("obsolete op - upgrade your ippool(8) utility.\n");
2788 +       return -EINVAL;
2789 +}
2790 +
2791 +static int getpool(
2792 +       struct sock *sk,
2793 +       int optval,
2794 +       void *user,
2795 +       int *len
2796 +) {
2797 +       struct ip_pool_request req;
2798 +       struct ip_pool *pool;
2799 +       ip_pool_t i;
2800 +       int newbytes;
2801 +       void *newmembers;
2802 +       int res;
2803 +
2804 +       DP("ip_pool:getpool: optval=%d, user=%p\n", optval, user);
2805 +       if (!capable(CAP_NET_ADMIN))
2806 +               return -EINVAL;
2807 +       if (optval != SO_IP_POOL)
2808 +               return -EINVAL;
2809 +       if (*len != sizeof(req)) {
2810 +               return -EFAULT;
2811 +       }
2812 +       if (copy_from_user(&req, user, sizeof(req)) != 0)
2813 +               return -EFAULT;
2814 +       DP("ip_pool:getpool op=%d, index=%d\n", req.op, req.index);
2815 +       if (req.op < IP_POOL_BAD001) {
2816 +               printk("obsolete op - upgrade your ippool(8) utility.\n");
2817 +               return -EFAULT;
2818 +       }
2819 +       switch(req.op) {
2820 +       case IP_POOL_HIGH_NR:
2821 +               DP("ip_pool HIGH_NR\n");
2822 +               req.index = IP_POOL_NONE;
2823 +               for (i=0; i<nr_pool; i++)
2824 +                       if (POOL[i].members)
2825 +                               req.index = i;
2826 +               return copy_to_user(user, &req, sizeof(req));
2827 +       case IP_POOL_LOOKUP:
2828 +               DP("ip_pool LOOKUP\n");
2829 +               pool = lookup(req.index);
2830 +               if (!pool)
2831 +                       return -EINVAL;
2832 +               if (!pool->members)
2833 +                       return -EBADF;
2834 +               req.addr = htonl(pool->first_ip);
2835 +               req.addr2 = htonl(pool->last_ip);
2836 +               return copy_to_user(user, &req, sizeof(req));
2837 +       case IP_POOL_USAGE:
2838 +               DP("ip_pool USE\n");
2839 +               pool = lookup(req.index);
2840 +               if (!pool)
2841 +                       return -EINVAL;
2842 +               if (!pool->members)
2843 +                       return -EBADF;
2844 +               req.addr = pool->nr_use;
2845 +               req.addr2 = pool->nr_match;
2846 +               return copy_to_user(user, &req, sizeof(req));
2847 +       case IP_POOL_TEST_ADDR:
2848 +               DP("ip_pool TEST 0x%08x\n", req.addr);
2849 +               pool = lookup(req.index);
2850 +               if (!pool)
2851 +                       return -EINVAL;
2852 +               res = 0;
2853 +               read_lock_bh(&pool->lock);
2854 +               if (!pool->members) {
2855 +                       DP("ip_pool TEST_ADDR no members in pool\n");
2856 +                       res = -EBADF;
2857 +                       goto unlock_and_return_res;
2858 +               }
2859 +               req.addr = ntohl(req.addr);
2860 +               if (req.addr < pool->first_ip) {
2861 +                       DP("ip_pool TEST_ADDR address < pool bounds\n");
2862 +                       res = -ERANGE;
2863 +                       goto unlock_and_return_res;
2864 +               }
2865 +               if (req.addr > pool->last_ip) {
2866 +                       DP("ip_pool TEST_ADDR address > pool bounds\n");
2867 +                       res = -ERANGE;
2868 +                       goto unlock_and_return_res;
2869 +               }
2870 +               req.addr = (0 != test_bit((req.addr - pool->first_ip),
2871 +                                       pool->members));
2872 +               read_unlock_bh(&pool->lock);
2873 +               return copy_to_user(user, &req, sizeof(req));
2874 +       case IP_POOL_FLUSH:
2875 +               DP("ip_pool FLUSH not yet implemented.\n");
2876 +               return -EBUSY;
2877 +       case IP_POOL_DESTROY:
2878 +               DP("ip_pool DESTROY not yet implemented.\n");
2879 +               return -EBUSY;
2880 +       case IP_POOL_INIT:
2881 +               DP("ip_pool INIT 0x%08x-0x%08x\n", req.addr, req.addr2);
2882 +               pool = lookup(req.index);
2883 +               if (!pool)
2884 +                       return -EINVAL;
2885 +               req.addr = ntohl(req.addr);
2886 +               req.addr2 = ntohl(req.addr2);
2887 +               if (req.addr > req.addr2) {
2888 +                       DP("ip_pool INIT bad ip range\n");
2889 +                       return -EINVAL;
2890 +               }
2891 +               newbytes = bitmap_bytes(req.addr, req.addr2);
2892 +               newmembers = kmalloc(newbytes, GFP_KERNEL);
2893 +               if (!newmembers) {
2894 +                       DP("ip_pool INIT out of mem for %d bytes\n", newbytes);
2895 +                       return -ENOMEM;
2896 +               }
2897 +               memset(newmembers, 0, newbytes);
2898 +               write_lock_bh(&pool->lock);
2899 +               if (pool->members) {
2900 +                       DP("ip_pool INIT pool %d exists\n", req.index);
2901 +                       kfree(newmembers);
2902 +                       res = -EBUSY;
2903 +                       goto unlock_and_return_res;
2904 +               }
2905 +               pool->first_ip = req.addr;
2906 +               pool->last_ip = req.addr2;
2907 +               pool->nr_use = 0;
2908 +               pool->nr_match = 0;
2909 +               pool->members = newmembers;
2910 +               write_unlock_bh(&pool->lock);
2911 +               return 0;
2912 +       case IP_POOL_ADD_ADDR:
2913 +               DP("ip_pool ADD_ADDR 0x%08x\n", req.addr);
2914 +               req.addr = pool_change(req.index, ntohl(req.addr), 0);
2915 +               return copy_to_user(user, &req, sizeof(req));
2916 +       case IP_POOL_DEL_ADDR:
2917 +               DP("ip_pool DEL_ADDR 0x%08x\n", req.addr);
2918 +               req.addr = pool_change(req.index, ntohl(req.addr), 1);
2919 +               return copy_to_user(user, &req, sizeof(req));
2920 +       default:
2921 +               DP("ip_pool:getpool bad op %d\n", req.op);
2922 +               return -EINVAL;
2923 +       }
2924 +       return -EINVAL;
2925 +
2926 +unlock_and_return_res:
2927 +       if (pool)
2928 +               read_unlock_bh(&pool->lock);
2929 +       return res;
2930 +}
2931 +
2932 +static struct nf_sockopt_ops so_pool
2933 += { { NULL, NULL }, PF_INET,
2934 +    SO_IP_POOL, SO_IP_POOL+1, &setpool,
2935 +    SO_IP_POOL, SO_IP_POOL+1, &getpool,
2936 +    0, NULL };
2937 +
2938 +MODULE_PARM(nr_pool, "i");
2939 +
2940 +static int __init init(void)
2941 +{
2942 +       ip_pool_t i;
2943 +       int res;
2944 +
2945 +       if (nr_pool < 1) {
2946 +               printk("ip_pool module init: bad nr_pool %d\n", nr_pool);
2947 +               return -EINVAL;
2948 +       }
2949 +       POOL = kmalloc(nr_pool * sizeof(*POOL), GFP_KERNEL);
2950 +       if (!POOL) {
2951 +               printk("ip_pool module init: out of memory for nr_pool %d\n",
2952 +                       nr_pool);
2953 +               return -ENOMEM;
2954 +       }
2955 +       for (i=0; i<nr_pool; i++) {
2956 +               POOL[i].first_ip = 0;
2957 +               POOL[i].last_ip = 0;
2958 +               POOL[i].members = 0;
2959 +               POOL[i].nr_use = 0;
2960 +               POOL[i].nr_match = 0;
2961 +               POOL[i].lock = RW_LOCK_UNLOCKED;
2962 +       }
2963 +       res = nf_register_sockopt(&so_pool);
2964 +       DP("ip_pool:init %d pools, result %d\n", nr_pool, res);
2965 +       if (res != 0) {
2966 +               kfree(POOL);
2967 +               POOL = 0;
2968 +       }
2969 +       return res;
2970 +}
2971 +
2972 +static void __exit fini(void)
2973 +{
2974 +       ip_pool_t i;
2975 +
2976 +       DP("ip_pool:fini BYEBYE\n");
2977 +       nf_unregister_sockopt(&so_pool);
2978 +       for (i=0; i<nr_pool; i++) {
2979 +               if (POOL[i].members) {
2980 +                       kfree(POOL[i].members);
2981 +                       POOL[i].members = 0;
2982 +               }
2983 +       }
2984 +       kfree(POOL);
2985 +       POOL = 0;
2986 +       DP("ip_pool:fini these are the famous last words\n");
2987 +       return;
2988 +}
2989 +
2990 +module_init(init);
2991 +module_exit(fini);
2992 diff -Nur linux-2.6.6-rc1.org/net/ipv4/netfilter/ip_tables.c linux-2.6.6-rc1/net/ipv4/netfilter/ip_tables.c
2993 --- linux-2.6.6-rc1.org/net/ipv4/netfilter/ip_tables.c  2004-04-15 03:34:03.000000000 +0200
2994 +++ linux-2.6.6-rc1/net/ipv4/netfilter/ip_tables.c      2004-04-19 10:08:25.000000000 +0200
2995 @@ -1716,9 +1716,9 @@
2996  };
2997  
2998  #ifdef CONFIG_PROC_FS
2999 -static inline int print_name(const char *i,
3000 -                            off_t start_offset, char *buffer, int length,
3001 -                            off_t *pos, unsigned int *count)
3002 +static int print_name(const char *i,
3003 +                      off_t start_offset, char *buffer, int length,
3004 +                      off_t *pos, unsigned int *count)
3005  {
3006         if ((*count)++ >= start_offset) {
3007                 unsigned int namelen;
3008 @@ -1752,6 +1752,15 @@
3009         return pos;
3010  }
3011  
3012 +static inline int print_target(const struct ipt_target *t,
3013 +                               off_t start_offset, char *buffer, int length,
3014 +                               off_t *pos, unsigned int *count)
3015 +{
3016 +       if (t != &ipt_standard_target && t != &ipt_error_target)
3017 +               return 0;
3018 +       return print_name((char *)t, start_offset, buffer, length, pos, count);
3019 +}
3020 +
3021  static int ipt_get_targets(char *buffer, char **start, off_t offset, int length)
3022  {
3023         off_t pos = 0;
3024 @@ -1760,7 +1769,7 @@
3025         if (down_interruptible(&ipt_mutex) != 0)
3026                 return 0;
3027  
3028 -       LIST_FIND(&ipt_target, print_name, void *,
3029 +       LIST_FIND(&ipt_target, print_target, struct ipt_target *,
3030                   offset, buffer, length, &pos, &count);
3031         
3032         up(&ipt_mutex);
3033 diff -Nur linux-2.6.6-rc1.org/net/ipv4/netfilter/ipt_IPV4OPTSSTRIP.c linux-2.6.6-rc1/net/ipv4/netfilter/ipt_IPV4OPTSSTRIP.c
3034 --- linux-2.6.6-rc1.org/net/ipv4/netfilter/ipt_IPV4OPTSSTRIP.c  1970-01-01 01:00:00.000000000 +0100
3035 +++ linux-2.6.6-rc1/net/ipv4/netfilter/ipt_IPV4OPTSSTRIP.c      2004-04-19 10:08:26.000000000 +0200
3036 @@ -0,0 +1,89 @@
3037 +/**
3038 + * Strip all IP options in the IP packet header.
3039 + *
3040 + * (C) 2001 by Fabrice MARIE <fabrice@netfilter.org>
3041 + * This software is distributed under GNU GPL v2, 1991
3042 + */
3043 +
3044 +#include <linux/module.h>
3045 +#include <linux/skbuff.h>
3046 +#include <linux/ip.h>
3047 +#include <net/checksum.h>
3048 +
3049 +#include <linux/netfilter_ipv4/ip_tables.h>
3050 +
3051 +MODULE_AUTHOR("Fabrice MARIE <fabrice@netfilter.org>");
3052 +MODULE_DESCRIPTION("Strip all options in IPv4 packets");
3053 +MODULE_LICENSE("GPL");
3054 +
3055 +static unsigned int
3056 +target(struct sk_buff **pskb,
3057 +       const struct net_device *in,
3058 +       const struct net_device *out,
3059 +       unsigned int hooknum,
3060 +       const void *targinfo,
3061 +       void *userinfo)
3062 +{
3063 +       struct iphdr *iph;
3064 +       struct sk_buff *skb;
3065 +       struct ip_options *opt;
3066 +       unsigned char *optiph;
3067 +       int l;
3068 +       
3069 +       if (!skb_ip_make_writable(pskb, (*pskb)->len))
3070 +               return NF_DROP;
3071
3072 +       skb = (*pskb);
3073 +       iph = (*pskb)->nh.iph;
3074 +       optiph = skb->nh.raw;
3075 +       l = ((struct ip_options *)(&(IPCB(skb)->opt)))->optlen;
3076 +
3077 +       /* if no options in packet then nothing to clear. */
3078 +       if (iph->ihl * 4 == sizeof(struct iphdr))
3079 +               return IPT_CONTINUE;
3080 +
3081 +       /* else clear all options */
3082 +       memset(&(IPCB(skb)->opt), 0, sizeof(struct ip_options));
3083 +       memset(optiph+sizeof(struct iphdr), IPOPT_NOOP, l);
3084 +       opt = &(IPCB(skb)->opt);
3085 +       opt->is_data = 0;
3086 +       opt->optlen = l;
3087 +
3088 +       skb->nfcache |= NFC_ALTERED;
3089 +
3090 +        return IPT_CONTINUE;
3091 +}
3092 +
3093 +static int
3094 +checkentry(const char *tablename,
3095 +          const struct ipt_entry *e,
3096 +           void *targinfo,
3097 +           unsigned int targinfosize,
3098 +           unsigned int hook_mask)
3099 +{
3100 +       if (strcmp(tablename, "mangle")) {
3101 +               printk(KERN_WARNING "IPV4OPTSSTRIP: can only be called from \"mangle\" table, not \"%s\"\n", tablename);
3102 +               return 0;
3103 +       }
3104 +       /* nothing else to check because no parameters */
3105 +       return 1;
3106 +}
3107 +
3108 +static struct ipt_target ipt_ipv4optsstrip_reg = { 
3109 +       .name = "IPV4OPTSSTRIP",
3110 +       .target = target,
3111 +       .checkentry = checkentry,
3112 +       .me = THIS_MODULE };
3113 +
3114 +static int __init init(void)
3115 +{
3116 +       return ipt_register_target(&ipt_ipv4optsstrip_reg);
3117 +}
3118 +
3119 +static void __exit fini(void)
3120 +{
3121 +       ipt_unregister_target(&ipt_ipv4optsstrip_reg);
3122 +}
3123 +
3124 +module_init(init);
3125 +module_exit(fini);
3126 diff -Nur linux-2.6.6-rc1.org/net/ipv4/netfilter/ipt_POOL.c linux-2.6.6-rc1/net/ipv4/netfilter/ipt_POOL.c
3127 --- linux-2.6.6-rc1.org/net/ipv4/netfilter/ipt_POOL.c   1970-01-01 01:00:00.000000000 +0100
3128 +++ linux-2.6.6-rc1/net/ipv4/netfilter/ipt_POOL.c       2004-04-19 10:08:36.000000000 +0200
3129 @@ -0,0 +1,116 @@
3130 +/* ipt_POOL.c - netfilter target to manipulate IP pools
3131 + *
3132 + * This target can be used almost everywhere. It acts on some specified
3133 + * IP pool, adding or deleting some IP address in the pool. The address
3134 + * can be either the source (--addsrc, --delsrc), or destination (--add/deldst)
3135 + * of the packet under inspection.
3136 + *
3137 + * The target normally returns IPT_CONTINUE.
3138 + */
3139 +
3140 +#include <linux/types.h>
3141 +#include <linux/ip.h>
3142 +#include <linux/timer.h>
3143 +#include <linux/module.h>
3144 +#include <linux/netfilter.h>
3145 +#include <linux/netdevice.h>
3146 +#include <linux/if.h>
3147 +#include <linux/inetdevice.h>
3148 +#include <net/protocol.h>
3149 +#include <net/checksum.h>
3150 +#include <linux/netfilter_ipv4.h>
3151 +#include <linux/netfilter_ipv4/ip_nat_rule.h>
3152 +#include <linux/netfilter_ipv4/ipt_pool.h>
3153 +
3154 +#if 0
3155 +#define DEBUGP printk
3156 +#else
3157 +#define DEBUGP(format, args...)
3158 +#endif
3159 +
3160 +/*** NOTE NOTE NOTE NOTE ***
3161 +**
3162 +** By sheer luck, I get away with using the "struct ipt_pool_info", as defined
3163 +** in <linux/netfilter_ipv4/ipt_pool.h>, both as the match and target info.
3164 +** Here, in the target implementation, ipt_pool_info.src, if not IP_POOL_NONE,
3165 +** is modified for the source IP address of the packet under inspection.
3166 +** The same way, the ipt_pool_info.dst pool is modified for the destination.
3167 +**
3168 +** The address is added to the pool normally. However, if IPT_POOL_DEL_dir
3169 +** flag is set in ipt_pool_info.flags, the address is deleted from the pool.
3170 +**
3171 +** If a modification was done to the pool, we possibly return ACCEPT or DROP,
3172 +** if the right IPT_POOL_MOD_dir_ACCEPT or _MOD_dir_DROP flags are set.
3173 +** The IPT_POOL_INV_MOD_dir flag inverts the sense of the check (i.e. the
3174 +** ACCEPT and DROP flags are evaluated when the pool was not modified.)
3175 +*/
3176 +
3177 +static int
3178 +do_check(const char *tablename,
3179 +              const struct ipt_entry *e,
3180 +              void *targinfo,
3181 +              unsigned int targinfosize,
3182 +              unsigned int hook_mask)
3183 +{
3184 +       const struct ipt_pool_info *ipi = targinfo;
3185 +
3186 +       if (targinfosize != IPT_ALIGN(sizeof(*ipi))) {
3187 +               DEBUGP("POOL_check: size %u.\n", targinfosize);
3188 +               return 0;
3189 +       }
3190 +       DEBUGP("ipt_POOL:do_check(%d,%d,%d)\n",ipi->src,ipi->dst,ipi->flags);
3191 +       return 1;
3192 +}
3193 +
3194 +static unsigned int
3195 +do_target(struct sk_buff **pskb,
3196 +               unsigned int hooknum,
3197 +               const struct net_device *in,
3198 +               const struct net_device *out,
3199 +               const void *targinfo,
3200 +               void *userinfo)
3201 +{
3202 +       const struct ipt_pool_info *ipi = targinfo;
3203 +       int modified;
3204 +       unsigned int verdict = IPT_CONTINUE;
3205 +
3206 +       if (ipi->src != IP_POOL_NONE) {
3207 +               modified = ip_pool_mod(ipi->src, ntohl((*pskb)->nh.iph->saddr),
3208 +                                       ipi->flags & IPT_POOL_DEL_SRC);
3209 +               if (!!modified ^ !!(ipi->flags & IPT_POOL_INV_MOD_SRC)) {
3210 +                       if (ipi->flags & IPT_POOL_MOD_SRC_ACCEPT)
3211 +                               verdict = NF_ACCEPT;
3212 +                       else if (ipi->flags & IPT_POOL_MOD_SRC_DROP)
3213 +                               verdict = NF_DROP;
3214 +               }
3215 +       }
3216 +       if (verdict == IPT_CONTINUE && ipi->dst != IP_POOL_NONE) {
3217 +               modified = ip_pool_mod(ipi->dst, ntohl((*pskb)->nh.iph->daddr),
3218 +                                       ipi->flags & IPT_POOL_DEL_DST);
3219 +               if (!!modified ^ !!(ipi->flags & IPT_POOL_INV_MOD_DST)) {
3220 +                       if (ipi->flags & IPT_POOL_MOD_DST_ACCEPT)
3221 +                               verdict = NF_ACCEPT;
3222 +                       else if (ipi->flags & IPT_POOL_MOD_DST_DROP)
3223 +                               verdict = NF_DROP;
3224 +               }
3225 +       }
3226 +       return verdict;
3227 +}
3228 +
3229 +static struct ipt_target pool_reg
3230 += { { NULL, NULL }, "POOL", do_target, do_check, NULL, THIS_MODULE };
3231 +
3232 +static int __init init(void)
3233 +{
3234 +       DEBUGP("init ipt_POOL\n");
3235 +       return ipt_register_target(&pool_reg);
3236 +}
3237 +
3238 +static void __exit fini(void)
3239 +{
3240 +       DEBUGP("fini ipt_POOL\n");
3241 +       ipt_unregister_target(&pool_reg);
3242 +}
3243 +
3244 +module_init(init);
3245 +module_exit(fini);
3246 diff -Nur linux-2.6.6-rc1.org/net/ipv4/netfilter/ipt_TTL.c linux-2.6.6-rc1/net/ipv4/netfilter/ipt_TTL.c
3247 --- linux-2.6.6-rc1.org/net/ipv4/netfilter/ipt_TTL.c    1970-01-01 01:00:00.000000000 +0100
3248 +++ linux-2.6.6-rc1/net/ipv4/netfilter/ipt_TTL.c        2004-04-19 10:08:28.000000000 +0200
3249 @@ -0,0 +1,120 @@
3250 +/* TTL modification target for IP tables
3251 + * (C) 2000 by Harald Welte <laforge@gnumonks.org>
3252 + *
3253 + * Version: $Revision$
3254 + *
3255 + * This software is distributed under the terms of GNU GPL
3256 + */
3257 +
3258 +#include <linux/module.h>
3259 +#include <linux/skbuff.h>
3260 +#include <linux/ip.h>
3261 +#include <net/checksum.h>
3262 +
3263 +#include <linux/netfilter_ipv4/ip_tables.h>
3264 +#include <linux/netfilter_ipv4/ipt_TTL.h>
3265 +
3266 +MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
3267 +MODULE_DESCRIPTION("IP tables TTL modification module");
3268 +MODULE_LICENSE("GPL");
3269 +
3270 +static unsigned int 
3271 +ipt_ttl_target(struct sk_buff **pskb, const struct net_device *in, 
3272 +               const struct net_device *out, unsigned int hooknum, 
3273 +               const void *targinfo, void *userinfo)
3274 +{
3275 +       struct iphdr *iph;
3276 +       const struct ipt_TTL_info *info = targinfo;
3277 +       u_int16_t diffs[2];
3278 +       int new_ttl;
3279 +
3280 +       if (!skb_ip_make_writable(pskb, (*pskb)->len))
3281 +               return NF_DROP;
3282 +
3283 +       iph = (*pskb)->nh.iph;
3284 +                        
3285 +       switch (info->mode) {
3286 +               case IPT_TTL_SET:
3287 +                       new_ttl = info->ttl;
3288 +                       break;
3289 +               case IPT_TTL_INC:
3290 +                       new_ttl = iph->ttl + info->ttl;
3291 +                       if (new_ttl > 255)
3292 +                               new_ttl = 255;
3293 +                       break;
3294 +               case IPT_TTL_DEC:
3295 +                       new_ttl = iph->ttl + info->ttl;
3296 +                       if (new_ttl < 0)
3297 +                               new_ttl = 0;
3298 +                       break;
3299 +               default:
3300 +                       new_ttl = iph->ttl;
3301 +                       break;
3302 +       }
3303 +
3304 +       if (new_ttl != iph->ttl) {
3305 +               diffs[0] = htons(((unsigned)iph->ttl) << 8) ^ 0xFFFF;
3306 +               iph->ttl = new_ttl;
3307 +               diffs[1] = htons(((unsigned)iph->ttl) << 8);
3308 +               iph->check = csum_fold(csum_partial((char *)diffs,
3309 +                                                   sizeof(diffs),
3310 +                                                   iph->check^0xFFFF));
3311 +                                                                                               (*pskb)->nfcache |= NFC_ALTERED;
3312 +       }
3313 +
3314 +       return IPT_CONTINUE;
3315 +}
3316 +
3317 +static int ipt_ttl_checkentry(const char *tablename,
3318 +               const struct ipt_entry *e,
3319 +               void *targinfo,
3320 +               unsigned int targinfosize,
3321 +               unsigned int hook_mask)
3322 +{
3323 +       struct ipt_TTL_info *info = targinfo;
3324 +
3325 +       if (targinfosize != IPT_ALIGN(sizeof(struct ipt_TTL_info))) {
3326 +               printk(KERN_WARNING "TTL: targinfosize %u != %Zu\n",
3327 +                               targinfosize,
3328 +                               IPT_ALIGN(sizeof(struct ipt_TTL_info)));
3329 +               return 0;       
3330 +       }       
3331 +
3332 +       if (strcmp(tablename, "mangle")) {
3333 +               printk(KERN_WARNING "TTL: can only be called from \"mangle\" table, not \"%s\"\n", tablename);
3334 +               return 0;
3335 +       }
3336 +
3337 +       if (info->mode > IPT_TTL_MAXMODE) {
3338 +               printk(KERN_WARNING "TTL: invalid or unknown Mode %u\n", 
3339 +                       info->mode);
3340 +               return 0;
3341 +       }
3342 +
3343 +       if ((info->mode != IPT_TTL_SET) && (info->ttl == 0)) {
3344 +               printk(KERN_WARNING "TTL: increment/decrement doesn't make sense with value 0\n");
3345 +               return 0;
3346 +       }
3347 +       
3348 +       return 1;
3349 +}
3350 +
3351 +static struct ipt_target ipt_TTL = { 
3352 +       .name = "TTL",
3353 +       .target = ipt_ttl_target, 
3354 +       .checkentry = ipt_ttl_checkentry, 
3355 +       .me = THIS_MODULE 
3356 +};
3357 +
3358 +static int __init init(void)
3359 +{
3360 +       return ipt_register_target(&ipt_TTL);
3361 +}
3362 +
3363 +static void __exit fini(void)
3364 +{
3365 +       ipt_unregister_target(&ipt_TTL);
3366 +}
3367 +
3368 +module_init(init);
3369 +module_exit(fini);
3370 diff -Nur linux-2.6.6-rc1.org/net/ipv4/netfilter/ipt_connlimit.c linux-2.6.6-rc1/net/ipv4/netfilter/ipt_connlimit.c
3371 --- linux-2.6.6-rc1.org/net/ipv4/netfilter/ipt_connlimit.c      1970-01-01 01:00:00.000000000 +0100
3372 +++ linux-2.6.6-rc1/net/ipv4/netfilter/ipt_connlimit.c  2004-04-19 10:08:29.000000000 +0200
3373 @@ -0,0 +1,230 @@
3374 +/*
3375 + * netfilter module to limit the number of parallel tcp
3376 + * connections per IP address.
3377 + *   (c) 2000 Gerd Knorr <kraxel@bytesex.org>
3378 + *   Nov 2002: Martin Bene <martin.bene@icomedias.com>:
3379 + *             only ignore TIME_WAIT or gone connections
3380 + *
3381 + * based on ...
3382 + *
3383 + * Kernel module to match connection tracking information.
3384 + * GPL (C) 1999  Rusty Russell (rusty@rustcorp.com.au).
3385 + */
3386 +#include <linux/module.h>
3387 +#include <linux/skbuff.h>
3388 +#include <linux/list.h>
3389 +#include <linux/netfilter_ipv4/ip_conntrack.h>
3390 +#include <linux/netfilter_ipv4/ip_conntrack_core.h>
3391 +#include <linux/netfilter_ipv4/ip_conntrack_tcp.h>
3392 +#include <linux/netfilter_ipv4/ip_tables.h>
3393 +#include <linux/netfilter_ipv4/ipt_connlimit.h>
3394 +
3395 +#define DEBUG 0
3396 +
3397 +MODULE_LICENSE("GPL");
3398 +
3399 +/* we'll save the tuples of all connections we care about */
3400 +struct ipt_connlimit_conn
3401 +{
3402 +        struct list_head list;
3403 +       struct ip_conntrack_tuple tuple;
3404 +};
3405 +
3406 +struct ipt_connlimit_data {
3407 +       spinlock_t lock;
3408 +       struct list_head iphash[256];
3409 +};
3410 +
3411 +static int ipt_iphash(u_int32_t addr)
3412 +{
3413 +       int hash;
3414 +
3415 +       hash  =  addr        & 0xff;
3416 +       hash ^= (addr >>  8) & 0xff;
3417 +       hash ^= (addr >> 16) & 0xff;
3418 +       hash ^= (addr >> 24) & 0xff;
3419 +       return hash;
3420 +}
3421 +
3422 +static int count_them(struct ipt_connlimit_data *data,
3423 +                     u_int32_t addr, u_int32_t mask,
3424 +                     struct ip_conntrack *ct)
3425 +{
3426 +#if DEBUG
3427 +       const static char *tcp[] = { "none", "established", "syn_sent", "syn_recv",
3428 +                                    "fin_wait", "time_wait", "close", "close_wait",
3429 +                                    "last_ack", "listen" };
3430 +#endif
3431 +       int addit = 1, matches = 0;
3432 +       struct ip_conntrack_tuple tuple;
3433 +       struct ip_conntrack_tuple_hash *found;
3434 +       struct ipt_connlimit_conn *conn;
3435 +       struct list_head *hash,*lh;
3436 +
3437 +       spin_lock(&data->lock);
3438 +       tuple = ct->tuplehash[0].tuple;
3439 +       hash = &data->iphash[ipt_iphash(addr & mask)];
3440 +
3441 +       /* check the saved connections */
3442 +       for (lh = hash->next; lh != hash; lh = lh->next) {
3443 +               conn = list_entry(lh,struct ipt_connlimit_conn,list);
3444 +               found = ip_conntrack_find_get(&conn->tuple,ct);
3445 +               if (0 == memcmp(&conn->tuple,&tuple,sizeof(tuple)) &&
3446 +                   found != NULL &&
3447 +                   found->ctrack->proto.tcp.state != TCP_CONNTRACK_TIME_WAIT) {
3448 +                       /* Just to be sure we have it only once in the list.
3449 +                          We should'nt see tuples twice unless someone hooks this
3450 +                          into a table without "-p tcp --syn" */
3451 +                       addit = 0;
3452 +               }
3453 +#if DEBUG
3454 +               printk("ipt_connlimit [%d]: src=%u.%u.%u.%u:%d dst=%u.%u.%u.%u:%d %s\n",
3455 +                      ipt_iphash(addr & mask),
3456 +                      NIPQUAD(conn->tuple.src.ip), ntohs(conn->tuple.src.u.tcp.port),
3457 +                      NIPQUAD(conn->tuple.dst.ip), ntohs(conn->tuple.dst.u.tcp.port),
3458 +                      (NULL != found) ? tcp[found->ctrack->proto.tcp.state] : "gone");
3459 +#endif
3460 +               if (NULL == found) {
3461 +                       /* this one is gone */
3462 +                       lh = lh->prev;
3463 +                       list_del(lh->next);
3464 +                       kfree(conn);
3465 +                       continue;
3466 +               }
3467 +               if (found->ctrack->proto.tcp.state == TCP_CONNTRACK_TIME_WAIT) {
3468 +                       /* we don't care about connections which are
3469 +                          closed already -> ditch it */
3470 +                       lh = lh->prev;
3471 +                       list_del(lh->next);
3472 +                       kfree(conn);
3473 +                       nf_conntrack_put(&found->ctrack->infos[0]);
3474 +                       continue;
3475 +               }
3476 +               if ((addr & mask) == (conn->tuple.src.ip & mask)) {
3477 +                       /* same source IP address -> be counted! */
3478 +                       matches++;
3479 +               }
3480 +               nf_conntrack_put(&found->ctrack->infos[0]);
3481 +       }
3482 +       if (addit) {
3483 +               /* save the new connection in our list */
3484 +#if DEBUG
3485 +               printk("ipt_connlimit [%d]: src=%u.%u.%u.%u:%d dst=%u.%u.%u.%u:%d new\n",
3486 +                      ipt_iphash(addr & mask),
3487 +                      NIPQUAD(tuple.src.ip), ntohs(tuple.src.u.tcp.port),
3488 +                      NIPQUAD(tuple.dst.ip), ntohs(tuple.dst.u.tcp.port));
3489 +#endif
3490 +               conn = kmalloc(sizeof(*conn),GFP_ATOMIC);
3491 +               if (NULL == conn)
3492 +                       return -1;
3493 +               memset(conn,0,sizeof(*conn));
3494 +               INIT_LIST_HEAD(&conn->list);
3495 +               conn->tuple = tuple;
3496 +               list_add(&conn->list,hash);
3497 +               matches++;
3498 +       }
3499 +       spin_unlock(&data->lock);
3500 +       return matches;
3501 +}
3502 +
3503 +static int
3504 +match(const struct sk_buff *skb,
3505 +      const struct net_device *in,
3506 +      const struct net_device *out,
3507 +      const void *matchinfo,
3508 +      int offset,
3509 +      int *hotdrop)
3510 +{
3511 +       const struct ipt_connlimit_info *info = matchinfo;
3512 +       int connections, match;
3513 +       struct ip_conntrack *ct;
3514 +       enum ip_conntrack_info ctinfo;
3515 +
3516 +       ct = ip_conntrack_get((struct sk_buff *)skb, &ctinfo);
3517 +       if (NULL == ct) {
3518 +               printk("ipt_connlimit: Oops: invalid ct state ?\n");
3519 +               *hotdrop = 1;
3520 +               return 0;
3521 +       }
3522 +       connections = count_them(info->data,skb->nh.iph->saddr,info->mask,ct);
3523 +       if (-1 == connections) {
3524 +               printk("ipt_connlimit: Hmm, kmalloc failed :-(\n");
3525 +               *hotdrop = 1; /* let's free some memory :-) */
3526 +               return 0;
3527 +       }
3528 +        match = (info->inverse) ? (connections <= info->limit) : (connections > info->limit);
3529 +#if DEBUG
3530 +       printk("ipt_connlimit: src=%u.%u.%u.%u mask=%u.%u.%u.%u "
3531 +              "connections=%d limit=%d match=%s\n",
3532 +              NIPQUAD(skb->nh.iph->saddr), NIPQUAD(info->mask),
3533 +              connections, info->limit, match ? "yes" : "no");
3534 +#endif
3535 +
3536 +       return match;
3537 +}
3538 +
3539 +static int check(const char *tablename,
3540 +                const struct ipt_ip *ip,
3541 +                void *matchinfo,
3542 +                unsigned int matchsize,
3543 +                unsigned int hook_mask)
3544 +{
3545 +       struct ipt_connlimit_info *info = matchinfo;
3546 +       int i;
3547 +
3548 +       /* verify size */
3549 +       if (matchsize != IPT_ALIGN(sizeof(struct ipt_connlimit_info)))
3550 +               return 0;
3551 +
3552 +       /* refuse anything but tcp */
3553 +       if (ip->proto != IPPROTO_TCP)
3554 +               return 0;
3555 +
3556 +       /* init private data */
3557 +       info->data = kmalloc(sizeof(struct ipt_connlimit_data),GFP_KERNEL);
3558 +       spin_lock_init(&(info->data->lock));
3559 +       for (i = 0; i < 256; i++)
3560 +               INIT_LIST_HEAD(&(info->data->iphash[i]));
3561 +       
3562 +       return 1;
3563 +}
3564 +
3565 +static void destroy(void *matchinfo, unsigned int matchinfosize)
3566 +{
3567 +       struct ipt_connlimit_info *info = matchinfo;
3568 +       struct ipt_connlimit_conn *conn;
3569 +       struct list_head *hash;
3570 +       int i;
3571 +
3572 +       /* cleanup */
3573 +       for (i = 0; i < 256; i++) {
3574 +               hash = &(info->data->iphash[i]);
3575 +               while (hash != hash->next) {
3576 +                       conn = list_entry(hash->next,struct ipt_connlimit_conn,list);
3577 +                       list_del(hash->next);
3578 +                       kfree(conn);
3579 +               }
3580 +       }
3581 +       kfree(info->data);
3582 +}
3583 +
3584 +static struct ipt_match connlimit_match = { 
3585 +       .name = "connlimit",
3586 +       .match = &match,
3587 +       .checkentry = &check,
3588 +       .destroy = &destroy,
3589 +       .me = THIS_MODULE
3590 +};
3591 +
3592 +static int __init init(void)
3593 +{
3594 +       return ipt_register_match(&connlimit_match);
3595 +}
3596 +
3597 +static void __exit fini(void)
3598 +{
3599 +       ipt_unregister_match(&connlimit_match);
3600 +}
3601 +
3602 +module_init(init);
3603 +module_exit(fini);
3604 diff -Nur linux-2.6.6-rc1.org/net/ipv4/netfilter/ipt_dstlimit.c linux-2.6.6-rc1/net/ipv4/netfilter/ipt_dstlimit.c
3605 --- linux-2.6.6-rc1.org/net/ipv4/netfilter/ipt_dstlimit.c       1970-01-01 01:00:00.000000000 +0100
3606 +++ linux-2.6.6-rc1/net/ipv4/netfilter/ipt_dstlimit.c   2004-04-19 10:08:30.000000000 +0200
3607 @@ -0,0 +1,690 @@
3608 +/* iptables match extension to limit the number of packets per second
3609 + * seperately for each destination.
3610 + *
3611 + * (C) 2003 by Harald Welte <laforge@netfilter.org>
3612 + *
3613 + * $Id$
3614 + *
3615 + * Development of this code was funded by Astaro AG, http://www.astaro.com/
3616 + *
3617 + * based on ipt_limit.c by:
3618 + * Jérôme de Vivie     <devivie@info.enserb.u-bordeaux.fr>
3619 + * Hervé Eychenne      <eychenne@info.enserb.u-bordeaux.fr>
3620 + * Rusty Russell       <rusty@rustcorp.com.au>
3621 + *
3622 + * The general idea is to create a hash table for every dstip and have a
3623 + * seperate limit counter per tuple.  This way you can do something like 'limit
3624 + * the number of syn packets for each of my internal addresses.
3625 + *
3626 + * Ideally this would just be implemented as a general 'hash' match, which would
3627 + * allow us to attach any iptables target to it's hash buckets.  But this is
3628 + * not possible in the current iptables architecture.  As always, pkttables for
3629 + * 2.7.x will help ;)
3630 + */
3631 +#include <linux/module.h>
3632 +#include <linux/skbuff.h>
3633 +#include <linux/spinlock.h>
3634 +#include <linux/random.h>
3635 +#include <linux/jhash.h>
3636 +#include <linux/slab.h>
3637 +#include <linux/vmalloc.h>
3638 +#include <linux/tcp.h>
3639 +#include <linux/udp.h>
3640 +#include <linux/proc_fs.h>
3641 +#include <linux/seq_file.h>
3642 +
3643 +#define ASSERT_READ_LOCK(x) 
3644 +#define ASSERT_WRITE_LOCK(x) 
3645 +#include <linux/netfilter_ipv4/lockhelp.h>
3646 +#include <linux/netfilter_ipv4/listhelp.h>
3647 +
3648 +#include <linux/netfilter_ipv4/ip_tables.h>
3649 +#include <linux/netfilter_ipv4/ipt_dstlimit.h>
3650 +
3651 +/* FIXME: this is just for IP_NF_ASSERRT */
3652 +#include <linux/netfilter_ipv4/ip_conntrack.h>
3653 +
3654 +#define MS2JIFFIES(x) ((x*HZ)/1000)
3655 +
3656 +MODULE_LICENSE("GPL");
3657 +MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
3658 +MODULE_DESCRIPTION("iptables match for limiting per destination");
3659 +
3660 +/* need to declare this at the top */
3661 +static struct proc_dir_entry *dstlimit_procdir;
3662 +static struct file_operations dl_file_ops;
3663 +
3664 +/* hash table crap */
3665 +
3666 +struct dsthash_dst {
3667 +       u_int32_t src_ip;
3668 +       u_int32_t dst_ip;
3669 +       u_int16_t port;
3670 +};
3671 +
3672 +struct dsthash_ent {
3673 +       /* static / read-only parts in the beginning */
3674 +       struct list_head list;
3675 +       struct dsthash_dst dst;
3676 +
3677 +       /* modified structure members in the end */
3678 +       unsigned long expires;          /* precalculated expiry time */
3679 +       struct {
3680 +               unsigned long prev;     /* last modification */
3681 +               u_int32_t credit;
3682 +               u_int32_t credit_cap, cost;
3683 +       } rateinfo;
3684 +};
3685 +
3686 +struct ipt_dstlimit_htable {
3687 +       struct list_head list;          /* global list of all htables */
3688 +       atomic_t use;
3689 +
3690 +       struct dstlimit_cfg cfg;        /* config */
3691 +
3692 +       /* used internally */
3693 +       spinlock_t lock;                /* lock for list_head */
3694 +       u_int32_t rnd;                  /* random seed for hash */
3695 +       struct timer_list timer;        /* timer for gc */
3696 +       atomic_t count;                 /* number entries in table */
3697 +
3698 +       /* seq_file stuff */
3699 +       struct proc_dir_entry *pde;
3700 +
3701 +       struct list_head hash[0];       /* hashtable itself */
3702 +};
3703 +
3704 +DECLARE_RWLOCK(dstlimit_lock);         /* protects htables list */
3705 +static LIST_HEAD(dstlimit_htables);
3706 +static kmem_cache_t *dstlimit_cachep;
3707 +
3708 +static inline int dst_cmp(const struct dsthash_ent *ent, struct dsthash_dst *b)
3709 +{
3710 +       return (ent->dst.dst_ip == b->dst_ip 
3711 +               && ent->dst.port == b->port
3712 +               && ent->dst.src_ip == b->src_ip);
3713 +}
3714 +
3715 +static inline u_int32_t
3716 +hash_dst(const struct ipt_dstlimit_htable *ht, const struct dsthash_dst *dst)
3717 +{
3718 +       return (jhash_3words(dst->dst_ip, dst->port, 
3719 +                            dst->src_ip, ht->rnd) % ht->cfg.size);
3720 +}
3721 +
3722 +static inline struct dsthash_ent *
3723 +__dsthash_find(const struct ipt_dstlimit_htable *ht, struct dsthash_dst *dst)
3724 +{
3725 +       struct dsthash_ent *ent;
3726 +       u_int32_t hash = hash_dst(ht, dst);
3727 +       MUST_BE_LOCKED(&ht->lock);
3728 +       ent = LIST_FIND(&ht->hash[hash], dst_cmp, struct dsthash_ent *, dst);
3729 +       return ent;
3730 +}
3731 +
3732 +/* allocate dsthash_ent, initialize dst, put in htable and lock it */
3733 +static struct dsthash_ent *
3734 +__dsthash_alloc_init(struct ipt_dstlimit_htable *ht, struct dsthash_dst *dst)
3735 +{
3736 +       struct dsthash_ent *ent;
3737 +
3738 +       /* initialize hash with random val at the time we allocate
3739 +        * the first hashtable entry */
3740 +       if (!ht->rnd)
3741 +               get_random_bytes(&ht->rnd, 4);
3742 +
3743 +       if (ht->cfg.max &&
3744 +           atomic_read(&ht->count) >= ht->cfg.max) {
3745 +               /* FIXME: do something. question is what.. */
3746 +               if (net_ratelimit())
3747 +                       printk(KERN_WARNING 
3748 +                               "ipt_dstlimit: max count of %u reached\n", 
3749 +                               ht->cfg.max);
3750 +               return NULL;
3751 +       }
3752 +
3753 +       ent = kmem_cache_alloc(dstlimit_cachep, GFP_ATOMIC);
3754 +       if (!ent) {
3755 +               if (net_ratelimit())
3756 +                       printk(KERN_ERR 
3757 +                               "ipt_dstlimit: can't allocate dsthash_ent\n");
3758 +               return NULL;
3759 +       }
3760 +
3761 +       atomic_inc(&ht->count);
3762 +
3763 +       ent->dst.dst_ip = dst->dst_ip;
3764 +       ent->dst.port = dst->port;
3765 +       ent->dst.src_ip = dst->src_ip;
3766 +
3767 +       list_add(&ent->list, &ht->hash[hash_dst(ht, dst)]);
3768 +
3769 +       return ent;
3770 +}
3771 +
3772 +static inline void 
3773 +__dsthash_free(struct ipt_dstlimit_htable *ht, struct dsthash_ent *ent)
3774 +{
3775 +       MUST_BE_LOCKED(&ht->lock);
3776 +
3777 +       list_del(&ent->list);
3778 +       kmem_cache_free(dstlimit_cachep, ent);
3779 +       atomic_dec(&ht->count);
3780 +}
3781 +static void htable_gc(unsigned long htlong);
3782 +
3783 +static int htable_create(struct ipt_dstlimit_info *minfo)
3784 +{
3785 +       int i;
3786 +       unsigned int size;
3787 +       struct ipt_dstlimit_htable *hinfo;
3788 +
3789 +       if (minfo->cfg.size)
3790 +               size = minfo->cfg.size;
3791 +       else {
3792 +               size = (((num_physpages << PAGE_SHIFT) / 16384)
3793 +                        / sizeof(struct list_head));
3794 +               if (num_physpages > (1024 * 1024 * 1024 / PAGE_SIZE))
3795 +                       size = 8192;
3796 +               if (size < 16)
3797 +                       size = 16;
3798 +       }
3799 +       /* FIXME: don't use vmalloc() here or anywhere else -HW */
3800 +       hinfo = vmalloc(sizeof(struct ipt_dstlimit_htable)
3801 +                       + (sizeof(struct list_head) * size));
3802 +       if (!hinfo) {
3803 +               printk(KERN_ERR "ipt_dstlimit: Unable to create hashtable\n");
3804 +               return -1;
3805 +       }
3806 +       minfo->hinfo = hinfo;
3807 +
3808 +       /* copy match config into hashtable config */
3809 +       memcpy(&hinfo->cfg, &minfo->cfg, sizeof(hinfo->cfg));
3810 +       hinfo->cfg.size = size;
3811 +       if (!hinfo->cfg.max)
3812 +               hinfo->cfg.max = 8 * hinfo->cfg.size;
3813 +       else if (hinfo->cfg.max < hinfo->cfg.size)
3814 +               hinfo->cfg.max = hinfo->cfg.size;
3815 +
3816 +       for (i = 0; i < hinfo->cfg.size; i++)
3817 +               INIT_LIST_HEAD(&hinfo->hash[i]);
3818 +
3819 +       atomic_set(&hinfo->count, 0);
3820 +       atomic_set(&hinfo->use, 1);
3821 +       hinfo->rnd = 0;
3822 +       hinfo->lock = SPIN_LOCK_UNLOCKED;
3823 +       hinfo->pde = create_proc_entry(minfo->name, 0, dstlimit_procdir);
3824 +       if (!hinfo->pde) {
3825 +               vfree(hinfo);
3826 +               return -1;
3827 +       }
3828 +       hinfo->pde->proc_fops = &dl_file_ops;
3829 +       hinfo->pde->data = hinfo;
3830 +
3831 +       init_timer(&hinfo->timer);
3832 +       hinfo->timer.expires = jiffies + MS2JIFFIES(hinfo->cfg.gc_interval);
3833 +       hinfo->timer.data = (unsigned long )hinfo;
3834 +       hinfo->timer.function = htable_gc;
3835 +       add_timer(&hinfo->timer);
3836 +
3837 +       WRITE_LOCK(&dstlimit_lock);
3838 +       list_add(&hinfo->list, &dstlimit_htables);
3839 +       WRITE_UNLOCK(&dstlimit_lock);
3840 +
3841 +       return 0;
3842 +}
3843 +
3844 +static int select_all(struct ipt_dstlimit_htable *ht, struct dsthash_ent *he)
3845 +{
3846 +       return 1;
3847 +}
3848 +
3849 +static int select_gc(struct ipt_dstlimit_htable *ht, struct dsthash_ent *he)
3850 +{
3851 +       return (jiffies >= he->expires);
3852 +}
3853 +
3854 +static void htable_selective_cleanup(struct ipt_dstlimit_htable *ht,
3855 +                               int (*select)(struct ipt_dstlimit_htable *ht, 
3856 +                                             struct dsthash_ent *he))
3857 +{
3858 +       int i;
3859 +
3860 +       IP_NF_ASSERT(ht->cfg.size && ht->cfg.max);
3861 +
3862 +       /* lock hash table and iterate over it */
3863 +       LOCK_BH(&ht->lock);
3864 +       for (i = 0; i < ht->cfg.size; i++) {
3865 +               struct dsthash_ent *dh, *n;
3866 +               list_for_each_entry_safe(dh, n, &ht->hash[i], list) {
3867 +                       if ((*select)(ht, dh))
3868 +                               __dsthash_free(ht, dh);
3869 +               }
3870 +       }
3871 +       UNLOCK_BH(&ht->lock);
3872 +}
3873 +
3874 +/* hash table garbage collector, run by timer */
3875 +static void htable_gc(unsigned long htlong)
3876 +{
3877 +       struct ipt_dstlimit_htable *ht = (struct ipt_dstlimit_htable *)htlong;
3878 +
3879 +       htable_selective_cleanup(ht, select_gc);
3880 +
3881 +       /* re-add the timer accordingly */
3882 +       ht->timer.expires = jiffies + MS2JIFFIES(ht->cfg.gc_interval);
3883 +       add_timer(&ht->timer);
3884 +}
3885 +
3886 +static void htable_destroy(struct ipt_dstlimit_htable *hinfo)
3887 +{
3888 +       /* remove timer, if it is pending */
3889 +       if (timer_pending(&hinfo->timer))
3890 +               del_timer(&hinfo->timer);
3891 +
3892 +       /* remove proc entry */
3893 +       remove_proc_entry(hinfo->pde->name, dstlimit_procdir);
3894 +
3895 +       htable_selective_cleanup(hinfo, select_all);
3896 +       vfree(hinfo);
3897 +}
3898 +
3899 +static struct ipt_dstlimit_htable *htable_find_get(char *name)
3900 +{
3901 +       struct ipt_dstlimit_htable *hinfo;
3902 +
3903 +       READ_LOCK(&dstlimit_lock);
3904 +       list_for_each_entry(hinfo, &dstlimit_htables, list) {
3905 +               if (!strcmp(name, hinfo->pde->name)) {
3906 +                       atomic_inc(&hinfo->use);
3907 +                       READ_UNLOCK(&dstlimit_lock);
3908 +                       return hinfo;
3909 +               }
3910 +       }
3911 +       READ_UNLOCK(&dstlimit_lock);
3912 +
3913 +       return NULL;
3914 +}
3915 +
3916 +static void htable_put(struct ipt_dstlimit_htable *hinfo)
3917 +{
3918 +       if (atomic_dec_and_test(&hinfo->use)) {
3919 +               WRITE_LOCK(&dstlimit_lock);
3920 +               list_del(&hinfo->list);
3921 +               WRITE_UNLOCK(&dstlimit_lock);
3922 +               htable_destroy(hinfo);
3923 +       }
3924 +}
3925 +
3926 +
3927 +/* The algorithm used is the Simple Token Bucket Filter (TBF)
3928 + * see net/sched/sch_tbf.c in the linux source tree
3929 + */
3930 +
3931 +/* Rusty: This is my (non-mathematically-inclined) understanding of
3932 +   this algorithm.  The `average rate' in jiffies becomes your initial
3933 +   amount of credit `credit' and the most credit you can ever have
3934 +   `credit_cap'.  The `peak rate' becomes the cost of passing the
3935 +   test, `cost'.
3936 +
3937 +   `prev' tracks the last packet hit: you gain one credit per jiffy.
3938 +   If you get credit balance more than this, the extra credit is
3939 +   discarded.  Every time the match passes, you lose `cost' credits;
3940 +   if you don't have that many, the test fails.
3941 +
3942 +   See Alexey's formal explanation in net/sched/sch_tbf.c.
3943 +
3944 +   To get the maximum range, we multiply by this factor (ie. you get N
3945 +   credits per jiffy).  We want to allow a rate as low as 1 per day
3946 +   (slowest userspace tool allows), which means
3947 +   CREDITS_PER_JIFFY*HZ*60*60*24 < 2^32 ie.
3948 +*/
3949 +#define MAX_CPJ (0xFFFFFFFF / (HZ*60*60*24))
3950 +
3951 +/* Repeated shift and or gives us all 1s, final shift and add 1 gives
3952 + * us the power of 2 below the theoretical max, so GCC simply does a
3953 + * shift. */
3954 +#define _POW2_BELOW2(x) ((x)|((x)>>1))
3955 +#define _POW2_BELOW4(x) (_POW2_BELOW2(x)|_POW2_BELOW2((x)>>2))
3956 +#define _POW2_BELOW8(x) (_POW2_BELOW4(x)|_POW2_BELOW4((x)>>4))
3957 +#define _POW2_BELOW16(x) (_POW2_BELOW8(x)|_POW2_BELOW8((x)>>8))
3958 +#define _POW2_BELOW32(x) (_POW2_BELOW16(x)|_POW2_BELOW16((x)>>16))
3959 +#define POW2_BELOW32(x) ((_POW2_BELOW32(x)>>1) + 1)
3960 +
3961 +#define CREDITS_PER_JIFFY POW2_BELOW32(MAX_CPJ)
3962 +
3963 +/* Precision saver. */
3964 +static inline u_int32_t
3965 +user2credits(u_int32_t user)
3966 +{
3967 +       /* If multiplying would overflow... */
3968 +       if (user > 0xFFFFFFFF / (HZ*CREDITS_PER_JIFFY))
3969 +               /* Divide first. */
3970 +               return (user / IPT_DSTLIMIT_SCALE) * HZ * CREDITS_PER_JIFFY;
3971 +
3972 +       return (user * HZ * CREDITS_PER_JIFFY) / IPT_DSTLIMIT_SCALE;
3973 +}
3974 +
3975 +static inline void rateinfo_recalc(struct dsthash_ent *dh, unsigned long now)
3976 +{
3977 +       dh->rateinfo.credit += (now - xchg(&dh->rateinfo.prev, now)) 
3978 +                                       * CREDITS_PER_JIFFY;
3979 +       if (dh->rateinfo.credit > dh->rateinfo.credit_cap)
3980 +               dh->rateinfo.credit = dh->rateinfo.credit_cap;
3981 +}
3982 +
3983 +static int
3984 +dstlimit_match(const struct sk_buff *skb,
3985 +               const struct net_device *in,
3986 +               const struct net_device *out,
3987 +               const void *matchinfo,
3988 +               int offset,
3989 +               int *hotdrop)
3990 +{
3991 +       struct ipt_dstlimit_info *r = 
3992 +               ((struct ipt_dstlimit_info *)matchinfo)->u.master;
3993 +       struct ipt_dstlimit_htable *hinfo = r->hinfo;
3994 +       unsigned long now = jiffies;
3995 +       struct dsthash_ent *dh;
3996 +       struct dsthash_dst dst;
3997 +
3998 +       memset(&dst, 0, sizeof(dst));
3999 +
4000 +       /* dest ip is always in hash */
4001 +       dst.dst_ip = skb->nh.iph->daddr;
4002 +
4003 +       /* source ip only if respective hashmode, otherwise set to
4004 +        * zero */
4005 +       if (hinfo->cfg.mode & IPT_DSTLIMIT_HASH_SIP)
4006 +               dst.src_ip = skb->nh.iph->saddr;
4007 +
4008 +       /* dest port only if respective mode */
4009 +       if (hinfo->cfg.mode & IPT_DSTLIMIT_HASH_DPT) {
4010 +               u16 ports[2];
4011 +
4012 +               /* Must not be a fragment. */
4013 +               if (offset)
4014 +                       return 0;
4015 +
4016 +               /* Must be big enough to read ports (both UDP and TCP have
4017 +                  them at the start). */
4018 +               if (skb_copy_bits(skb, skb->nh.iph->ihl*4, ports, sizeof(ports)) < 0) {
4019 +                       /* We've been asked to examine this packet, and we
4020 +                          can't.  Hence, no choice but to drop. */
4021 +                       *hotdrop = 1;
4022 +                       return 0;
4023 +               }
4024 +
4025 +               switch (skb->nh.iph->protocol) {
4026 +                       struct tcphdr *th;
4027 +                       struct udphdr *uh;
4028 +               case IPPROTO_TCP:
4029 +                       th = (void *)skb->nh.iph+skb->nh.iph->ihl*4;
4030 +                       dst.port = th->dest;
4031 +                       break;
4032 +               case IPPROTO_UDP:
4033 +                       uh = (void *)skb->nh.iph+skb->nh.iph->ihl*4;
4034 +                       dst.port = uh->dest;
4035 +                       break;
4036 +               default:
4037 +                       break;
4038 +               }
4039 +       } 
4040 +
4041 +       LOCK_BH(&hinfo->lock);
4042 +       dh = __dsthash_find(hinfo, &dst);
4043 +       if (!dh) {
4044 +               dh = __dsthash_alloc_init(hinfo, &dst);
4045 +
4046 +               if (!dh) {
4047 +                       /* enomem... don't match == DROP */
4048 +                       if (net_ratelimit())
4049 +                               printk(KERN_ERR "%s: ENOMEM\n", __FUNCTION__);
4050 +                       UNLOCK_BH(&hinfo->lock);
4051 +                       return 0;
4052 +               }
4053 +
4054 +               dh->expires = jiffies + MS2JIFFIES(hinfo->cfg.expire);
4055 +
4056 +               dh->rateinfo.prev = jiffies;
4057 +               dh->rateinfo.credit = user2credits(hinfo->cfg.avg * 
4058 +                                                       hinfo->cfg.burst);
4059 +               dh->rateinfo.credit_cap = user2credits(hinfo->cfg.avg * 
4060 +                                                       hinfo->cfg.burst);
4061 +               dh->rateinfo.cost = user2credits(hinfo->cfg.avg);
4062 +
4063 +               UNLOCK_BH(&hinfo->lock);
4064 +               return 1;
4065 +       }
4066 +
4067 +       /* update expiration timeout */
4068 +       dh->expires = now + MS2JIFFIES(hinfo->cfg.expire);
4069 +
4070 +       rateinfo_recalc(dh, now);
4071 +       if (dh->rateinfo.credit >= dh->rateinfo.cost) {
4072 +               /* We're underlimit. */
4073 +               dh->rateinfo.credit -= dh->rateinfo.cost;
4074 +               UNLOCK_BH(&hinfo->lock);
4075 +               return 1;
4076 +       }
4077 +
4078 +               UNLOCK_BH(&hinfo->lock);
4079 +
4080 +       /* default case: we're overlimit, thus don't match */
4081 +       return 0;
4082 +}
4083 +
4084 +static int
4085 +dstlimit_checkentry(const char *tablename,
4086 +                    const struct ipt_ip *ip,
4087 +                    void *matchinfo,
4088 +                    unsigned int matchsize,
4089 +                    unsigned int hook_mask)
4090 +{
4091 +       struct ipt_dstlimit_info *r = matchinfo;
4092 +
4093 +       if (matchsize != IPT_ALIGN(sizeof(struct ipt_dstlimit_info)))
4094 +               return 0;
4095 +
4096 +       /* Check for overflow. */
4097 +       if (r->cfg.burst == 0
4098 +           || user2credits(r->cfg.avg * r->cfg.burst) < 
4099 +                                       user2credits(r->cfg.avg)) {
4100 +               printk(KERN_ERR "ipt_dstlimit: Overflow, try lower: %u/%u\n",
4101 +                      r->cfg.avg, r->cfg.burst);
4102 +               return 0;
4103 +       }
4104 +
4105 +       if (r->cfg.mode == 0 
4106 +           || r->cfg.mode > (IPT_DSTLIMIT_HASH_DPT
4107 +                         |IPT_DSTLIMIT_HASH_DIP
4108 +                         |IPT_DSTLIMIT_HASH_SIP))
4109 +               return 0;
4110 +
4111 +       if (!r->cfg.gc_interval)
4112 +               return 0;
4113 +       
4114 +       if (!r->cfg.expire)
4115 +               return 0;
4116 +
4117 +       r->hinfo = htable_find_get(r->name);
4118 +       if (!r->hinfo && (htable_create(r) != 0)) {
4119 +               return 0;
4120 +       }
4121 +
4122 +       /* Ugly hack: For SMP, we only want to use one set */
4123 +       r->u.master = r;
4124 +
4125 +       return 1;
4126 +}
4127 +
4128 +static void
4129 +dstlimit_destroy(void *matchinfo, unsigned int matchsize)
4130 +{
4131 +       struct ipt_dstlimit_info *r = (struct ipt_dstlimit_info *) matchinfo;
4132 +
4133 +       htable_put(r->hinfo);
4134 +}
4135 +
4136 +static struct ipt_match ipt_dstlimit = { 
4137 +       .list = { .prev = NULL, .next = NULL }, 
4138 +       .name = "dstlimit", 
4139 +       .match = dstlimit_match, 
4140 +       .checkentry = dstlimit_checkentry, 
4141 +       .destroy = dstlimit_destroy,
4142 +       .me = THIS_MODULE 
4143 +};
4144 +
4145 +/* PROC stuff */
4146 +
4147 +static void *dl_seq_start(struct seq_file *s, loff_t *pos)
4148 +{
4149 +       struct proc_dir_entry *pde = s->private;
4150 +       struct ipt_dstlimit_htable *htable = pde->data;
4151 +       unsigned int *bucket;
4152 +
4153 +       LOCK_BH(&htable->lock);
4154 +       if (*pos >= htable->cfg.size)
4155 +               return NULL;
4156 +
4157 +       bucket = kmalloc(sizeof(unsigned int), GFP_KERNEL);
4158 +       if (!bucket)
4159 +               return ERR_PTR(-ENOMEM);
4160 +
4161 +       *bucket = *pos;
4162 +       return bucket;
4163 +}
4164 +
4165 +static void *dl_seq_next(struct seq_file *s, void *v, loff_t *pos)
4166 +{
4167 +       struct proc_dir_entry *pde = s->private;
4168 +       struct ipt_dstlimit_htable *htable = pde->data;
4169 +       unsigned int *bucket = (unsigned int *)v;
4170 +
4171 +       *pos = ++(*bucket);
4172 +       if (*pos >= htable->cfg.size) {
4173 +               kfree(v);
4174 +               return NULL;
4175 +       }
4176 +       return bucket;
4177 +}
4178 +
4179 +static void dl_seq_stop(struct seq_file *s, void *v)
4180 +{
4181 +       struct proc_dir_entry *pde = s->private;
4182 +       struct ipt_dstlimit_htable *htable = pde->data;
4183 +       unsigned int *bucket = (unsigned int *)v;
4184 +
4185 +       kfree(bucket);
4186 +
4187 +       UNLOCK_BH(&htable->lock);
4188 +}
4189 +
4190 +static inline int dl_seq_real_show(struct dsthash_ent *ent, struct seq_file *s)
4191 +{
4192 +       /* recalculate to show accurate numbers */
4193 +       rateinfo_recalc(ent, jiffies);
4194 +
4195 +       return seq_printf(s, "%ld %u.%u.%u.%u->%u.%u.%u.%u:%u %u %u %u\n",
4196 +                       (ent->expires - jiffies)/HZ,
4197 +                       NIPQUAD(ent->dst.src_ip),
4198 +                       NIPQUAD(ent->dst.dst_ip), ntohs(ent->dst.port),
4199 +                       ent->rateinfo.credit, ent->rateinfo.credit_cap,
4200 +                       ent->rateinfo.cost);
4201 +}
4202 +
4203 +static int dl_seq_show(struct seq_file *s, void *v)
4204 +{
4205 +       struct proc_dir_entry *pde = s->private;
4206 +       struct ipt_dstlimit_htable *htable = pde->data;
4207 +       unsigned int *bucket = (unsigned int *)v;
4208 +
4209 +       if (LIST_FIND_W(&htable->hash[*bucket], dl_seq_real_show,
4210 +                     struct dsthash_ent *, s)) {
4211 +               /* buffer was filled and unable to print that tuple */
4212 +               return 1;
4213 +       }
4214 +       return 0;
4215 +}
4216 +
4217 +static struct seq_operations dl_seq_ops = {
4218 +       .start = dl_seq_start,
4219 +       .next  = dl_seq_next,
4220 +       .stop  = dl_seq_stop,
4221 +       .show  = dl_seq_show
4222 +};
4223 +
4224 +static int dl_proc_open(struct inode *inode, struct file *file)
4225 +{
4226 +       int ret = seq_open(file, &dl_seq_ops);
4227 +
4228 +       if (!ret) {
4229 +               struct seq_file *sf = file->private_data;
4230 +               sf->private = PDE(inode);
4231 +       }
4232 +       return ret;
4233 +}
4234 +
4235 +static struct file_operations dl_file_ops = {
4236 +       .owner   = THIS_MODULE,
4237 +       .open    = dl_proc_open,
4238 +       .read    = seq_read,
4239 +       .llseek  = seq_lseek,
4240 +       .release = seq_release
4241 +};
4242 +
4243 +static int init_or_fini(int fini)
4244 +{
4245 +       int ret = 0;
4246 +
4247 +       if (fini)
4248 +               goto cleanup;
4249 +
4250 +       if (ipt_register_match(&ipt_dstlimit)) {
4251 +               ret = -EINVAL;
4252 +               goto cleanup_nothing;
4253 +       }
4254 +
4255 +       /* FIXME: do we really want HWCACHE_ALIGN since our objects are
4256 +        * quite small ? */
4257 +       dstlimit_cachep = kmem_cache_create("ipt_dstlimit",
4258 +                                           sizeof(struct dsthash_ent), 0,
4259 +                                           SLAB_HWCACHE_ALIGN, NULL, NULL);
4260 +       if (!dstlimit_cachep) {
4261 +               printk(KERN_ERR "Unable to create ipt_dstlimit slab cache\n");
4262 +               ret = -ENOMEM;
4263 +               goto cleanup_unreg_match;
4264 +       }
4265 +
4266 +       dstlimit_procdir = proc_mkdir("ipt_dstlimit", proc_net);
4267 +       if (!dstlimit_procdir) {
4268 +               printk(KERN_ERR "Unable to create proc dir entry\n");
4269 +               ret = -ENOMEM;
4270 +               goto cleanup_free_slab;
4271 +       }
4272 +
4273 +       return ret;
4274 +
4275 +cleanup:
4276 +       remove_proc_entry("ipt_dstlimit", proc_net);
4277 +cleanup_free_slab:
4278 +       kmem_cache_destroy(dstlimit_cachep);
4279 +cleanup_unreg_match:
4280 +       ipt_unregister_match(&ipt_dstlimit);
4281 +cleanup_nothing:
4282 +       return ret;
4283 +       
4284 +}
4285 +
4286 +static int __init init(void)
4287 +{
4288 +       return init_or_fini(0);
4289 +}
4290 +
4291 +static void __exit fini(void)
4292 +{
4293 +       init_or_fini(1);
4294 +}
4295 +
4296 +module_init(init);
4297 +module_exit(fini);
4298 diff -Nur linux-2.6.6-rc1.org/net/ipv4/netfilter/ipt_fuzzy.c linux-2.6.6-rc1/net/ipv4/netfilter/ipt_fuzzy.c
4299 --- linux-2.6.6-rc1.org/net/ipv4/netfilter/ipt_fuzzy.c  1970-01-01 01:00:00.000000000 +0100
4300 +++ linux-2.6.6-rc1/net/ipv4/netfilter/ipt_fuzzy.c      2004-04-19 10:08:31.000000000 +0200
4301 @@ -0,0 +1,185 @@
4302 +/*
4303 + *  This module implements a simple TSK FLC 
4304 + * (Takagi-Sugeno-Kang Fuzzy Logic Controller) that aims
4305 + * to limit , in an adaptive and flexible way , the packet rate crossing 
4306 + * a given stream . It serves as an initial and very simple (but effective)
4307 + * example of how Fuzzy Logic techniques can be applied to defeat DoS attacks.
4308 + *  As a matter of fact , Fuzzy Logic can help us to insert any "behavior"  
4309 + * into our code in a precise , adaptive and efficient manner. 
4310 + *  The goal is very similar to that of "limit" match , but using techniques of
4311 + * Fuzzy Control , that allow us to shape the transfer functions precisely ,
4312 + * avoiding over and undershoots - and stuff like that .
4313 + *
4314 + *
4315 + * 2002-08-10  Hime Aguiar e Oliveira Jr. <hime@engineer.com> : Initial version.
4316 + * 2002-08-17  : Changed to eliminate floating point operations .
4317 + * 2002-08-23  : Coding style changes .
4318 +*/
4319 +
4320 +#include <linux/module.h>
4321 +#include <linux/skbuff.h>
4322 +#include <linux/ip.h>
4323 +#include <linux/random.h>
4324 +#include <net/tcp.h>
4325 +#include <linux/spinlock.h>
4326 +#include <linux/netfilter_ipv4/ip_tables.h>
4327 +#include <linux/netfilter_ipv4/ipt_fuzzy.h>
4328 +
4329 +/*
4330 + Packet Acceptance Rate - LOW and Packet Acceptance Rate - HIGH
4331 + Expressed in percentage
4332 +*/
4333 +
4334 +#define PAR_LOW                1/100
4335 +#define PAR_HIGH       1
4336 +
4337 +static spinlock_t fuzzy_lock = SPIN_LOCK_UNLOCKED ;
4338 +
4339 +MODULE_AUTHOR("Hime Aguiar e Oliveira Junior <hime@engineer.com>");
4340 +MODULE_DESCRIPTION("IP tables Fuzzy Logic Controller match module");
4341 +MODULE_LICENSE("GPL");
4342 +
4343 +static  u_int8_t mf_high(u_int32_t tx,u_int32_t mini,u_int32_t maxi)
4344 +{
4345 +       if (tx >= maxi)
4346 +               return 100;
4347 +
4348 +       if (tx <= mini)
4349 +               return 0;
4350 +
4351 +       return ( (100*(tx-mini)) / (maxi-mini) );
4352 +}
4353 +
4354 +static u_int8_t mf_low(u_int32_t tx,u_int32_t mini,u_int32_t maxi)
4355 +{
4356 +       if (tx <= mini)
4357 +               return 100;
4358 +
4359 +       if (tx >= maxi)
4360 +               return 0;
4361 +
4362 +       return ( (100*( maxi - tx ))  / ( maxi - mini ) );
4363 +}
4364 +
4365 +static int
4366 +ipt_fuzzy_match(const struct sk_buff *pskb,
4367 +              const struct net_device *in,
4368 +              const struct net_device *out,
4369 +              const void *matchinfo,
4370 +              int offset,
4371 +              int *hotdrop)
4372 +{
4373 +       /* From userspace */
4374 +       
4375 +       struct ipt_fuzzy_info *info = (struct ipt_fuzzy_info *) matchinfo;
4376 +
4377 +       u_int8_t random_number;
4378 +       unsigned long amount;
4379 +       u_int8_t howhigh, howlow;
4380 +       
4381 +
4382 +       spin_lock_bh(&fuzzy_lock); /* Rise the lock */
4383 +
4384 +       info->bytes_total += pskb->len;
4385 +       info->packets_total++;
4386 +
4387 +       info->present_time = jiffies;
4388 +       
4389 +       if (info->present_time >= info->previous_time)
4390 +               amount = info->present_time - info->previous_time;
4391 +       else { 
4392 +               /* There was a transition : I choose to re-sample 
4393 +                  and keep the old acceptance rate...
4394 +               */
4395 +
4396 +               amount = 0;
4397 +               info->previous_time = info->present_time;
4398 +               info->bytes_total = info->packets_total = 0;
4399 +       };
4400 +       
4401 +       if (amount > HZ/10) /* More than 100 ms elapsed ... */
4402 +       {
4403 +
4404 +               info->mean_rate = (u_int32_t) ((HZ*info->packets_total)  \
4405 +                                       / amount );
4406 +
4407 +               info->previous_time = info->present_time;
4408 +               info->bytes_total = info->packets_total = 0;
4409 +
4410 +               howhigh = mf_high(info->mean_rate,info->minimum_rate,info->maximum_rate);
4411 +               howlow  = mf_low(info->mean_rate,info->minimum_rate,info->maximum_rate);
4412 +
4413 +               info->acceptance_rate = (u_int8_t) \
4414 +                          (howhigh*PAR_LOW + PAR_HIGH*howlow);
4415 +
4416 +               /* In fact , the above defuzzification would require a denominator
4417 +                  proportional to (howhigh+howlow) but , in this particular case ,
4418 +                  that expression is constant .
4419 +                  An imediate consequence is that it isn't necessary to call 
4420 +                  both mf_high and mf_low - but to keep things understandable ,
4421 +                  I did so .  */ 
4422 +
4423 +       }
4424 +       
4425 +       spin_unlock_bh(&fuzzy_lock); /* Release the lock */
4426 +
4427 +
4428 +       if ( info->acceptance_rate < 100 )
4429 +       {                
4430 +               get_random_bytes((void *)(&random_number), 1);
4431 +
4432 +               /*  If within the acceptance , it can pass => don't match */
4433 +               if (random_number <= (255 * info->acceptance_rate) / 100)
4434 +                       return 0;
4435 +               else
4436 +                       return 1; /* It can't pass ( It matches ) */
4437 +       } ;
4438 +
4439 +       return 0; /* acceptance_rate == 100 % => Everything passes ... */
4440 +       
4441 +}
4442 +
4443 +static int
4444 +ipt_fuzzy_checkentry(const char *tablename,
4445 +                  const struct ipt_ip *e,
4446 +                  void *matchinfo,
4447 +                  unsigned int matchsize,
4448 +                  unsigned int hook_mask)
4449 +{
4450 +       
4451 +       const struct ipt_fuzzy_info *info = matchinfo;
4452 +
4453 +       if (matchsize != IPT_ALIGN(sizeof(struct ipt_fuzzy_info))) {
4454 +               printk("ipt_fuzzy: matchsize %u != %u\n", matchsize,
4455 +                      IPT_ALIGN(sizeof(struct ipt_fuzzy_info)));
4456 +               return 0;
4457 +       }
4458 +
4459 +       if ((info->minimum_rate < MINFUZZYRATE ) || (info->maximum_rate > MAXFUZZYRATE)
4460 +           || (info->minimum_rate >= info->maximum_rate )) {
4461 +               printk("ipt_fuzzy: BAD limits , please verify !!!\n");
4462 +               return 0;
4463 +       }
4464 +
4465 +       return 1;
4466 +}
4467 +
4468 +static struct ipt_match ipt_fuzzy_reg = { 
4469 +       .name = "fuzzy",
4470 +       .match = ipt_fuzzy_match,
4471 +       .checkentry = ipt_fuzzy_checkentry,
4472 +       .me = THIS_MODULE
4473 +};
4474 +
4475 +static int __init init(void)
4476 +{
4477 +       return ipt_register_match(&ipt_fuzzy_reg);
4478 +}
4479 +
4480 +static void __exit fini(void)
4481 +{
4482 +       ipt_unregister_match(&ipt_fuzzy_reg);
4483 +}
4484 +
4485 +module_init(init);
4486 +module_exit(fini);
4487 diff -Nur linux-2.6.6-rc1.org/net/ipv4/netfilter/ipt_helper.c linux-2.6.6-rc1/net/ipv4/netfilter/ipt_helper.c
4488 --- linux-2.6.6-rc1.org/net/ipv4/netfilter/ipt_helper.c 2004-04-15 03:35:20.000000000 +0200
4489 +++ linux-2.6.6-rc1/net/ipv4/netfilter/ipt_helper.c     2004-04-19 10:08:23.000000000 +0200
4490 @@ -41,17 +41,17 @@
4491         struct ip_conntrack_expect *exp;
4492         struct ip_conntrack *ct;
4493         enum ip_conntrack_info ctinfo;
4494 -       int ret = 0;
4495 +       int ret = info->invert;
4496         
4497         ct = ip_conntrack_get((struct sk_buff *)skb, &ctinfo);
4498         if (!ct) {
4499                 DEBUGP("ipt_helper: Eek! invalid conntrack?\n");
4500 -               return 0;
4501 +               return ret;
4502         }
4503  
4504         if (!ct->master) {
4505                 DEBUGP("ipt_helper: conntrack %p has no master\n", ct);
4506 -               return 0;
4507 +               return ret;
4508         }
4509  
4510         exp = ct->master;
4511 @@ -71,8 +71,8 @@
4512         DEBUGP("master's name = %s , info->name = %s\n", 
4513                 exp->expectant->helper->name, info->name);
4514  
4515 -       ret = !strncmp(exp->expectant->helper->name, info->name, 
4516 -                      strlen(exp->expectant->helper->name)) ^ info->invert;
4517 +       ret ^= !strncmp(exp->expectant->helper->name, info->name, 
4518 +                       strlen(exp->expectant->helper->name));
4519  out_unlock:
4520         READ_UNLOCK(&ip_conntrack_lock);
4521         return ret;
4522 @@ -108,7 +108,6 @@
4523  
4524  static int __init init(void)
4525  {
4526 -       need_ip_conntrack();
4527         return ipt_register_match(&helper_match);
4528  }
4529  
4530 diff -Nur linux-2.6.6-rc1.org/net/ipv4/netfilter/ipt_ipv4options.c linux-2.6.6-rc1/net/ipv4/netfilter/ipt_ipv4options.c
4531 --- linux-2.6.6-rc1.org/net/ipv4/netfilter/ipt_ipv4options.c    1970-01-01 01:00:00.000000000 +0100
4532 +++ linux-2.6.6-rc1/net/ipv4/netfilter/ipt_ipv4options.c        2004-04-19 10:08:32.000000000 +0200
4533 @@ -0,0 +1,172 @@
4534 +/*
4535 +  This is a module which is used to match ipv4 options.
4536 +  This file is distributed under the terms of the GNU General Public
4537 +  License (GPL). Copies of the GPL can be obtained from:
4538 +  ftp://prep.ai.mit.edu/pub/gnu/GPL
4539 +
4540 +  11-mars-2001 Fabrice MARIE <fabrice@netfilter.org> : initial development.
4541 +  12-july-2001 Fabrice MARIE <fabrice@netfilter.org> : added router-alert otions matching. Fixed a bug with no-srr
4542 +  12-august-2001 Imran Patel <ipatel@crosswinds.net> : optimization of the match.
4543 +  18-november-2001 Fabrice MARIE <fabrice@netfilter.org> : added [!] 'any' option match.
4544 +  19-february-2004 Harald Welte <laforge@netfilter.org> : merge with 2.6.x
4545 +*/
4546 +
4547 +#include <linux/module.h>
4548 +#include <linux/skbuff.h>
4549 +#include <net/ip.h>
4550 +
4551 +#include <linux/netfilter_ipv4/ip_tables.h>
4552 +#include <linux/netfilter_ipv4/ipt_ipv4options.h>
4553 +
4554 +MODULE_LICENSE("GPL");
4555 +MODULE_AUTHOR("Fabrice Marie <fabrice@netfilter.org>");
4556 +
4557 +static int
4558 +match(const struct sk_buff *skb,
4559 +      const struct net_device *in,
4560 +      const struct net_device *out,
4561 +      const void *matchinfo,
4562 +      int offset,
4563 +      int *hotdrop)
4564 +{
4565 +       const struct ipt_ipv4options_info *info = matchinfo;   /* match info for rule */
4566 +       const struct iphdr *iph = skb->nh.iph;
4567 +       const struct ip_options *opt;
4568 +
4569 +       if (iph->ihl * 4 == sizeof(struct iphdr)) {
4570 +               /* No options, so we match only the "DONTs" and the "IGNOREs" */
4571 +
4572 +               if (((info->options & IPT_IPV4OPTION_MATCH_ANY_OPT) == IPT_IPV4OPTION_MATCH_ANY_OPT) ||
4573 +                   ((info->options & IPT_IPV4OPTION_MATCH_SSRR) == IPT_IPV4OPTION_MATCH_SSRR) ||
4574 +                   ((info->options & IPT_IPV4OPTION_MATCH_LSRR) == IPT_IPV4OPTION_MATCH_LSRR) ||
4575 +                   ((info->options & IPT_IPV4OPTION_MATCH_RR) == IPT_IPV4OPTION_MATCH_RR) ||
4576 +                   ((info->options & IPT_IPV4OPTION_MATCH_TIMESTAMP) == IPT_IPV4OPTION_MATCH_TIMESTAMP) ||
4577 +                    ((info->options & IPT_IPV4OPTION_MATCH_ROUTER_ALERT) == IPT_IPV4OPTION_MATCH_ROUTER_ALERT))
4578 +                       return 0;
4579 +               return 1;
4580 +       }
4581 +       else {
4582 +               if ((info->options & IPT_IPV4OPTION_MATCH_ANY_OPT) == IPT_IPV4OPTION_MATCH_ANY_OPT)
4583 +                       /* there are options, and we don't need to care which one */
4584 +                       return 1;
4585 +               else {
4586 +                       if ((info->options & IPT_IPV4OPTION_DONT_MATCH_ANY_OPT) == IPT_IPV4OPTION_DONT_MATCH_ANY_OPT)
4587 +                               /* there are options but we don't want any ! */
4588 +                               return 0;
4589 +               }
4590 +       }
4591 +
4592 +       opt = &(IPCB(skb)->opt);
4593 +
4594 +       /* source routing */
4595 +       if ((info->options & IPT_IPV4OPTION_MATCH_SSRR) == IPT_IPV4OPTION_MATCH_SSRR) {
4596 +               if (!((opt->srr) & (opt->is_strictroute)))
4597 +                       return 0;
4598 +       }
4599 +       else if ((info->options & IPT_IPV4OPTION_MATCH_LSRR) == IPT_IPV4OPTION_MATCH_LSRR) {
4600 +               if (!((opt->srr) & (!opt->is_strictroute)))
4601 +                       return 0;
4602 +       }
4603 +       else if ((info->options & IPT_IPV4OPTION_DONT_MATCH_SRR) == IPT_IPV4OPTION_DONT_MATCH_SRR) {
4604 +               if (opt->srr)
4605 +                       return 0;
4606 +       }
4607 +       /* record route */
4608 +       if ((info->options & IPT_IPV4OPTION_MATCH_RR) == IPT_IPV4OPTION_MATCH_RR) {
4609 +               if (!opt->rr)
4610 +                       return 0;
4611 +       }
4612 +       else if ((info->options & IPT_IPV4OPTION_DONT_MATCH_RR) == IPT_IPV4OPTION_DONT_MATCH_RR) {
4613 +               if (opt->rr)
4614 +                       return 0;
4615 +       }
4616 +       /* timestamp */
4617 +       if ((info->options & IPT_IPV4OPTION_MATCH_TIMESTAMP) == IPT_IPV4OPTION_MATCH_TIMESTAMP) {
4618 +               if (!opt->ts)
4619 +                       return 0;
4620 +       }
4621 +       else if ((info->options & IPT_IPV4OPTION_DONT_MATCH_TIMESTAMP) == IPT_IPV4OPTION_DONT_MATCH_TIMESTAMP) {
4622 +               if (opt->ts)
4623 +                       return 0;
4624 +       }
4625 +       /* router-alert option  */
4626 +       if ((info->options & IPT_IPV4OPTION_MATCH_ROUTER_ALERT) == IPT_IPV4OPTION_MATCH_ROUTER_ALERT) {
4627 +               if (!opt->router_alert)
4628 +                       return 0;
4629 +       }
4630 +       else if ((info->options & IPT_IPV4OPTION_DONT_MATCH_ROUTER_ALERT) == IPT_IPV4OPTION_DONT_MATCH_ROUTER_ALERT) {
4631 +               if (opt->router_alert)
4632 +                       return 0;
4633 +       }
4634 +
4635 +       /* we match ! */
4636 +       return 1;
4637 +}
4638 +
4639 +static int
4640 +checkentry(const char *tablename,
4641 +          const struct ipt_ip *ip,
4642 +          void *matchinfo,
4643 +          unsigned int matchsize,
4644 +          unsigned int hook_mask)
4645 +{
4646 +       const struct ipt_ipv4options_info *info = matchinfo;   /* match info for rule */
4647 +       /* Check the size */
4648 +       if (matchsize != IPT_ALIGN(sizeof(struct ipt_ipv4options_info)))
4649 +               return 0;
4650 +       /* Now check the coherence of the data ... */
4651 +       if (((info->options & IPT_IPV4OPTION_MATCH_ANY_OPT) == IPT_IPV4OPTION_MATCH_ANY_OPT) &&
4652 +           (((info->options & IPT_IPV4OPTION_DONT_MATCH_SRR) == IPT_IPV4OPTION_DONT_MATCH_SRR) ||
4653 +            ((info->options & IPT_IPV4OPTION_DONT_MATCH_RR) == IPT_IPV4OPTION_DONT_MATCH_RR) ||
4654 +            ((info->options & IPT_IPV4OPTION_DONT_MATCH_TIMESTAMP) == IPT_IPV4OPTION_DONT_MATCH_TIMESTAMP) ||
4655 +            ((info->options & IPT_IPV4OPTION_DONT_MATCH_ROUTER_ALERT) == IPT_IPV4OPTION_DONT_MATCH_ROUTER_ALERT) ||
4656 +            ((info->options & IPT_IPV4OPTION_DONT_MATCH_ANY_OPT) == IPT_IPV4OPTION_DONT_MATCH_ANY_OPT)))
4657 +               return 0; /* opposites */
4658 +       if (((info->options & IPT_IPV4OPTION_DONT_MATCH_ANY_OPT) == IPT_IPV4OPTION_DONT_MATCH_ANY_OPT) &&
4659 +           (((info->options & IPT_IPV4OPTION_MATCH_LSRR) == IPT_IPV4OPTION_MATCH_LSRR) ||
4660 +            ((info->options & IPT_IPV4OPTION_MATCH_SSRR) == IPT_IPV4OPTION_MATCH_SSRR) ||
4661 +            ((info->options & IPT_IPV4OPTION_MATCH_RR) == IPT_IPV4OPTION_MATCH_RR) ||
4662 +            ((info->options & IPT_IPV4OPTION_MATCH_TIMESTAMP) == IPT_IPV4OPTION_MATCH_TIMESTAMP) ||
4663 +            ((info->options & IPT_IPV4OPTION_MATCH_ROUTER_ALERT) == IPT_IPV4OPTION_MATCH_ROUTER_ALERT) ||
4664 +            ((info->options & IPT_IPV4OPTION_MATCH_ANY_OPT) == IPT_IPV4OPTION_MATCH_ANY_OPT)))
4665 +               return 0; /* opposites */
4666 +       if (((info->options & IPT_IPV4OPTION_MATCH_SSRR) == IPT_IPV4OPTION_MATCH_SSRR) &&
4667 +           ((info->options & IPT_IPV4OPTION_MATCH_LSRR) == IPT_IPV4OPTION_MATCH_LSRR))
4668 +               return 0; /* cannot match in the same time loose and strict source routing */
4669 +       if ((((info->options & IPT_IPV4OPTION_MATCH_SSRR) == IPT_IPV4OPTION_MATCH_SSRR) ||
4670 +            ((info->options & IPT_IPV4OPTION_MATCH_LSRR) == IPT_IPV4OPTION_MATCH_LSRR)) &&
4671 +           ((info->options & IPT_IPV4OPTION_DONT_MATCH_SRR) == IPT_IPV4OPTION_DONT_MATCH_SRR))
4672 +               return 0; /* opposites */
4673 +       if (((info->options & IPT_IPV4OPTION_MATCH_RR) == IPT_IPV4OPTION_MATCH_RR) &&
4674 +           ((info->options & IPT_IPV4OPTION_DONT_MATCH_RR) == IPT_IPV4OPTION_DONT_MATCH_RR))
4675 +               return 0; /* opposites */
4676 +       if (((info->options & IPT_IPV4OPTION_MATCH_TIMESTAMP) == IPT_IPV4OPTION_MATCH_TIMESTAMP) &&
4677 +           ((info->options & IPT_IPV4OPTION_DONT_MATCH_TIMESTAMP) == IPT_IPV4OPTION_DONT_MATCH_TIMESTAMP))
4678 +               return 0; /* opposites */
4679 +       if (((info->options & IPT_IPV4OPTION_MATCH_ROUTER_ALERT) == IPT_IPV4OPTION_MATCH_ROUTER_ALERT) &&
4680 +           ((info->options & IPT_IPV4OPTION_DONT_MATCH_ROUTER_ALERT) == IPT_IPV4OPTION_DONT_MATCH_ROUTER_ALERT))
4681 +               return 0; /* opposites */
4682 +
4683 +       /* everything looks ok. */
4684 +       return 1;
4685 +}
4686 +
4687 +static struct ipt_match ipv4options_match = { 
4688 +       .name = "ipv4options",
4689 +       .match = match,
4690 +       .checkentry = checkentry,
4691 +       .me = THIS_MODULE
4692 +};
4693 +
4694 +static int __init init(void)
4695 +{
4696 +       return ipt_register_match(&ipv4options_match);
4697 +}
4698 +
4699 +static void __exit fini(void)
4700 +{
4701 +       ipt_unregister_match(&ipv4options_match);
4702 +}
4703 +
4704 +module_init(init);
4705 +module_exit(fini);
4706 diff -Nur linux-2.6.6-rc1.org/net/ipv4/netfilter/ipt_mport.c linux-2.6.6-rc1/net/ipv4/netfilter/ipt_mport.c
4707 --- linux-2.6.6-rc1.org/net/ipv4/netfilter/ipt_mport.c  1970-01-01 01:00:00.000000000 +0100
4708 +++ linux-2.6.6-rc1/net/ipv4/netfilter/ipt_mport.c      2004-04-19 10:08:33.000000000 +0200
4709 @@ -0,0 +1,116 @@
4710 +/* Kernel module to match one of a list of TCP/UDP ports: ports are in
4711 +   the same place so we can treat them as equal. */
4712 +#include <linux/module.h>
4713 +#include <linux/types.h>
4714 +#include <linux/udp.h>
4715 +#include <linux/skbuff.h>
4716 +
4717 +#include <linux/netfilter_ipv4/ipt_mport.h>
4718 +#include <linux/netfilter_ipv4/ip_tables.h>
4719 +
4720 +MODULE_LICENSE("GPL");
4721 +
4722 +#if 0
4723 +#define duprintf(format, args...) printk(format , ## args)
4724 +#else
4725 +#define duprintf(format, args...)
4726 +#endif
4727 +
4728 +/* Returns 1 if the port is matched by the test, 0 otherwise. */
4729 +static inline int
4730 +ports_match(const struct ipt_mport *minfo, u_int16_t src, u_int16_t dst)
4731 +{
4732 +       unsigned int i;
4733 +        unsigned int m;
4734 +        u_int16_t pflags = minfo->pflags;
4735 +       for (i=0, m=1; i<IPT_MULTI_PORTS; i++, m<<=1) {
4736 +                u_int16_t s, e;
4737 +
4738 +                if (pflags & m
4739 +                    && minfo->ports[i] == 65535)
4740 +                        return 0;
4741 +
4742 +                s = minfo->ports[i];
4743 +
4744 +                if (pflags & m) {
4745 +                        e = minfo->ports[++i];
4746 +                        m <<= 1;
4747 +                } else
4748 +                        e = s;
4749 +
4750 +                if (minfo->flags & IPT_MPORT_SOURCE
4751 +                    && src >= s && src <= e)
4752 +                        return 1;
4753 +
4754 +               if (minfo->flags & IPT_MPORT_DESTINATION
4755 +                   && dst >= s && dst <= e)
4756 +                       return 1;
4757 +       }
4758 +
4759 +       return 0;
4760 +}
4761 +
4762 +static int
4763 +match(const struct sk_buff *skb,
4764 +      const struct net_device *in,
4765 +      const struct net_device *out,
4766 +      const void *matchinfo,
4767 +      int offset,
4768 +      int *hotdrop)
4769 +{
4770 +       u16 ports[2];
4771 +       const struct ipt_mport *minfo = matchinfo;
4772 +
4773 +       if (offset)
4774 +               return 0;
4775 +
4776 +       /* Must be big enough to read ports (both UDP and TCP have
4777 +           them at the start). */
4778 +       if (skb_copy_bits(skb, skb->nh.iph->ihl*4, ports, sizeof(ports)) < 0) {
4779 +               /* We've been asked to examine this packet, and we
4780 +                  can't.  Hence, no choice but to drop. */
4781 +                       duprintf("ipt_multiport:"
4782 +                                " Dropping evil offset=0 tinygram.\n");
4783 +                       *hotdrop = 1;
4784 +                       return 0;
4785 +       }
4786 +
4787 +       return ports_match(minfo, ntohs(ports[0]), ntohs(ports[1]));
4788 +}
4789 +
4790 +/* Called when user tries to insert an entry of this type. */
4791 +static int
4792 +checkentry(const char *tablename,
4793 +          const struct ipt_ip *ip,
4794 +          void *matchinfo,
4795 +          unsigned int matchsize,
4796 +          unsigned int hook_mask)
4797 +{
4798 +       if (matchsize != IPT_ALIGN(sizeof(struct ipt_mport)))
4799 +               return 0;
4800 +
4801 +       /* Must specify proto == TCP/UDP, no unknown flags or bad count */
4802 +       return (ip->proto == IPPROTO_TCP || ip->proto == IPPROTO_UDP)
4803 +               && !(ip->invflags & IPT_INV_PROTO)
4804 +               && matchsize == IPT_ALIGN(sizeof(struct ipt_mport));
4805 +}
4806 +
4807 +static struct ipt_match mport_match = { 
4808 +       .name = "mport",
4809 +       .match = &match,
4810 +       .checkentry = &checkentry,
4811 +       .me = THIS_MODULE
4812 +};
4813 +
4814 +static int __init init(void)
4815 +{
4816 +       return ipt_register_match(&mport_match);
4817 +}
4818 +
4819 +static void __exit fini(void)
4820 +{
4821 +       ipt_unregister_match(&mport_match);
4822 +}
4823 +
4824 +module_init(init);
4825 +module_exit(fini);
4826 diff -Nur linux-2.6.6-rc1.org/net/ipv4/netfilter/ipt_nth.c linux-2.6.6-rc1/net/ipv4/netfilter/ipt_nth.c
4827 --- linux-2.6.6-rc1.org/net/ipv4/netfilter/ipt_nth.c    1970-01-01 01:00:00.000000000 +0100
4828 +++ linux-2.6.6-rc1/net/ipv4/netfilter/ipt_nth.c        2004-04-19 10:08:34.000000000 +0200
4829 @@ -0,0 +1,166 @@
4830 +/*
4831 +  This is a module which is used for match support for every Nth packet
4832 +  This file is distributed under the terms of the GNU General Public
4833 +  License (GPL). Copies of the GPL can be obtained from:
4834 +     ftp://prep.ai.mit.edu/pub/gnu/GPL
4835 +
4836 +  2001-07-18 Fabrice MARIE <fabrice@netfilter.org> : initial implementation.
4837 +  2001-09-20 Richard Wagner (rwagner@cloudnet.com)
4838 +        * added support for multiple counters
4839 +        * added support for matching on individual packets
4840 +          in the counter cycle
4841 +  2004-02-19 Harald Welte <laforge@netfilter.org>
4842 +       * port to 2.6.x
4843 +
4844 +*/
4845 +
4846 +#include <linux/module.h>
4847 +#include <linux/skbuff.h>
4848 +#include <linux/ip.h>
4849 +#include <net/tcp.h>
4850 +#include <linux/spinlock.h>
4851 +#include <linux/netfilter_ipv4/ip_tables.h>
4852 +#include <linux/netfilter_ipv4/ipt_nth.h>
4853 +
4854 +MODULE_LICENSE("GPL");
4855 +MODULE_AUTHOR("Fabrice Marie <fabrice@netfilter.org>");
4856 +
4857 +/*
4858 + * State information.
4859 + */
4860 +struct state {
4861 +       spinlock_t lock;
4862 +       u_int16_t number;
4863 +};
4864 +
4865 +static struct state states[IPT_NTH_NUM_COUNTERS];
4866 +
4867 +static int
4868 +ipt_nth_match(const struct sk_buff *pskb,
4869 +             const struct net_device *in,
4870 +             const struct net_device *out,
4871 +             const void *matchinfo,
4872 +             int offset,
4873 +             int *hotdrop)
4874 +{
4875 +       /* Parameters from userspace */
4876 +       const struct ipt_nth_info *info = matchinfo;
4877 +        unsigned counter = info->counter;
4878 +               if((counter < 0) || (counter >= IPT_NTH_NUM_COUNTERS)) 
4879 +       {
4880 +                       printk(KERN_WARNING "nth: invalid counter %u. counter between 0 and %u\n", counter, IPT_NTH_NUM_COUNTERS-1);
4881 +               return 0;
4882 +        };
4883 +
4884 +        spin_lock(&states[counter].lock);
4885 +
4886 +        /* Are we matching every nth packet?*/
4887 +        if (info->packet == 0xFF)
4888 +        {
4889 +               /* We're matching every nth packet and only every nth packet*/
4890 +               /* Do we match or invert match? */
4891 +               if (info->not == 0)
4892 +               {
4893 +                       if (states[counter].number == 0)
4894 +                       {
4895 +                               ++states[counter].number;
4896 +                               goto match;
4897 +                       }
4898 +                       if (states[counter].number >= info->every)
4899 +                               states[counter].number = 0; /* reset the counter */
4900 +                       else
4901 +                               ++states[counter].number;
4902 +                       goto dontmatch;
4903 +               }
4904 +               else
4905 +               {
4906 +                       if (states[counter].number == 0)
4907 +                       {
4908 +                               ++states[counter].number;
4909 +                               goto dontmatch;
4910 +                       }
4911 +                       if (states[counter].number >= info->every)
4912 +                               states[counter].number = 0;
4913 +                       else
4914 +                               ++states[counter].number;
4915 +                       goto match;
4916 +               }
4917 +        }
4918 +        else
4919 +        {
4920 +               /* We're using the --packet, so there must be a rule for every value */
4921 +               if (states[counter].number == info->packet)
4922 +               {
4923 +                       /* only increment the counter when a match happens */
4924 +                       if (states[counter].number >= info->every)
4925 +                               states[counter].number = 0; /* reset the counter */
4926 +                       else
4927 +                               ++states[counter].number;
4928 +                       goto match;
4929 +               }
4930 +               else
4931 +                       goto dontmatch;
4932 +       }
4933 +
4934 + dontmatch:
4935 +       /* don't match */
4936 +       spin_unlock(&states[counter].lock);
4937 +       return 0;
4938 +
4939 + match:
4940 +       spin_unlock(&states[counter].lock);
4941 +       return 1;
4942 +}
4943 +
4944 +static int
4945 +ipt_nth_checkentry(const char *tablename,
4946 +                  const struct ipt_ip *e,
4947 +                  void *matchinfo,
4948 +                  unsigned int matchsize,
4949 +                  unsigned int hook_mask)
4950 +{
4951 +       /* Parameters from userspace */
4952 +       const struct ipt_nth_info *info = matchinfo;
4953 +        unsigned counter = info->counter;
4954 +        if((counter < 0) || (counter >= IPT_NTH_NUM_COUNTERS)) 
4955 +       {
4956 +               printk(KERN_WARNING "nth: invalid counter %u. counter between 0 and %u\n", counter, IPT_NTH_NUM_COUNTERS-1);
4957 +                       return 0;
4958 +               };
4959 +
4960 +       if (matchsize != IPT_ALIGN(sizeof(struct ipt_nth_info))) {
4961 +               printk("nth: matchsize %u != %u\n", matchsize,
4962 +                      IPT_ALIGN(sizeof(struct ipt_nth_info)));
4963 +               return 0;
4964 +       }
4965 +
4966 +       states[counter].number = info->startat;
4967 +
4968 +       return 1;
4969 +}
4970 +
4971 +static struct ipt_match ipt_nth_reg = { 
4972 +       .name = "nth",
4973 +       .match = ipt_nth_match,
4974 +       .checkentry = ipt_nth_checkentry,
4975 +       .me = THIS_MODULE
4976 +};
4977 +
4978 +static int __init init(void)
4979 +{
4980 +       unsigned counter;
4981 +
4982 +       memset(&states, 0, sizeof(states));
4983 +        for (counter = 0; counter < IPT_NTH_NUM_COUNTERS; counter++) 
4984 +               spin_lock_init(&(states[counter].lock));
4985 +
4986 +       return ipt_register_match(&ipt_nth_reg);
4987 +}
4988 +
4989 +static void __exit fini(void)
4990 +{
4991 +       ipt_unregister_match(&ipt_nth_reg);
4992 +}
4993 +
4994 +module_init(init);
4995 +module_exit(fini);
4996 diff -Nur linux-2.6.6-rc1.org/net/ipv4/netfilter/ipt_osf.c linux-2.6.6-rc1/net/ipv4/netfilter/ipt_osf.c
4997 --- linux-2.6.6-rc1.org/net/ipv4/netfilter/ipt_osf.c    1970-01-01 01:00:00.000000000 +0100
4998 +++ linux-2.6.6-rc1/net/ipv4/netfilter/ipt_osf.c        2004-04-19 10:08:35.000000000 +0200
4999 @@ -0,0 +1,866 @@
5000 +/*
5001 + * ipt_osf.c
5002 + *
5003 + * Copyright (c) 2003 Evgeniy Polyakov <johnpol@2ka.mipt.ru>
5004 + *
5005 + *
5006 + * This program is free software; you can redistribute it and/or modify
5007 + * it under the terms of the GNU General Public License as published by
5008 + * the Free Software Foundation; either version 2 of the License, or
5009 + * (at your option) any later version.
5010 + *
5011 + * This program is distributed in the hope that it will be useful,
5012 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
5013 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
5014 + * GNU General Public License for more details.
5015 + *
5016 + * You should have received a copy of the GNU General Public License
5017 + * along with this program; if not, write to the Free Software
5018 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
5019 + */
5020 +
5021 +/*
5022 + * OS fingerprint matching module.
5023 + * It simply compares various parameters from SYN packet with
5024 + * some hardcoded ones.
5025 + *
5026 + * Original table was created by Michal Zalewski <lcamtuf@coredump.cx>
5027 + * for his p0f.
5028 + */
5029 +
5030 +#include <linux/config.h>
5031 +#include <linux/kernel.h>
5032 +#include <linux/types.h>
5033 +#include <linux/string.h>
5034 +#include <linux/smp.h>
5035 +#include <linux/module.h>
5036 +#include <linux/skbuff.h>
5037 +#include <linux/file.h>
5038 +#include <linux/ip.h>
5039 +#include <linux/proc_fs.h>
5040 +#include <linux/fs.h>
5041 +#include <linux/slab.h>
5042 +#include <linux/spinlock.h>
5043 +#include <linux/ctype.h>
5044 +#include <linux/list.h>
5045 +#include <linux/if.h>
5046 +#include <linux/tcp.h>
5047 +
5048 +#include <net/sock.h>
5049 +#include <net/ip.h>
5050 +
5051 +#include <linux/netfilter_ipv4/ip_tables.h>
5052 +
5053 +#include <linux/netfilter_ipv4/ipt_osf.h>
5054 +
5055 +#define OSF_DEBUG
5056 +
5057 +#ifdef OSF_DEBUG
5058 +#define log(x...)              printk(KERN_INFO "ipt_osf: " x)
5059 +#define loga(x...)             printk(x)
5060 +#else
5061 +#define log(x...)              do {} while(0)
5062 +#define loga(x...)             do {} while(0)
5063 +#endif
5064 +
5065 +#define FMATCH_WRONG           0
5066 +#define FMATCH_OK              1
5067 +#define FMATCH_OPT_WRONG       2
5068 +
5069 +#define OPTDEL                 ','
5070 +#define OSFPDEL                ':'
5071 +#define MAXOPTSTRLEN           128
5072 +#define OSFFLUSH               "FLUSH"
5073 +
5074 +static rwlock_t osf_lock = RW_LOCK_UNLOCKED;
5075 +static spinlock_t ipt_osf_netlink_lock = SPIN_LOCK_UNLOCKED;
5076 +static struct list_head        finger_list;    
5077 +static int match(const struct sk_buff *, const struct net_device *, const struct net_device *,
5078 +                     const void *, int, 
5079 +                     const void *, u_int16_t, 
5080 +                     int *);
5081 +static int checkentry(const char *, const struct ipt_ip *, void *,
5082 +                          unsigned int, unsigned int);
5083 +
5084 +static unsigned long seq, ipt_osf_groups = 1;
5085 +static struct sock *nts;
5086 +
5087 +static struct ipt_match osf_match = 
5088 +{ 
5089 +       { NULL, NULL }, 
5090 +       "osf", 
5091 +       &match, 
5092 +       &checkentry, 
5093 +       NULL, 
5094 +       THIS_MODULE 
5095 +};
5096 +
5097 +static void ipt_osf_nlsend(struct osf_finger *f, const struct sk_buff *sk)
5098 +{
5099 +       unsigned int size;
5100 +       struct sk_buff *skb;
5101 +       struct ipt_osf_nlmsg *data;
5102 +       struct nlmsghdr *nlh;
5103 +
5104 +       size = NLMSG_SPACE(sizeof(struct ipt_osf_nlmsg));
5105 +
5106 +       skb = alloc_skb(size, GFP_ATOMIC);
5107 +       if (!skb)
5108 +       {
5109 +               log("skb_alloc() failed.\n");
5110 +               return;
5111 +       }
5112 +       
5113 +       nlh = NLMSG_PUT(skb, 0, seq++, NLMSG_DONE, size - sizeof(*nlh));
5114 +       
5115 +       data = (struct ipt_osf_nlmsg *)NLMSG_DATA(nlh);
5116 +
5117 +       memcpy(&data->f, f, sizeof(struct osf_finger));
5118 +       memcpy(&data->ip, sk->nh.iph, sizeof(struct iphdr));
5119 +       memcpy(&data->tcp, (struct tcphdr *)((u_int32_t *)sk->nh.iph + sk->nh.iph->ihl), sizeof(struct tcphdr));
5120 +
5121 +       NETLINK_CB(skb).dst_groups = ipt_osf_groups;
5122 +       netlink_broadcast(nts, skb, 0, ipt_osf_groups, GFP_ATOMIC);
5123 +
5124 +nlmsg_failure:
5125 +       return;
5126 +}
5127 +
5128 +static inline int smart_dec(const struct sk_buff *skb, unsigned long flags, unsigned char f_ttl)
5129 +{
5130 +       struct iphdr *ip = skb->nh.iph;
5131 +
5132 +       if (flags & IPT_OSF_SMART)
5133 +       {
5134 +               struct in_device *in_dev = in_dev_get(skb->dev);
5135 +
5136 +               for_ifa(in_dev)
5137 +               {
5138 +                       if (inet_ifa_match(ip->saddr, ifa))
5139 +                       {
5140 +                               in_dev_put(in_dev);
5141 +                               return (ip->ttl == f_ttl);
5142 +                       }
5143 +               }
5144 +               endfor_ifa(in_dev);
5145 +               
5146 +               in_dev_put(in_dev);
5147 +               return (ip->ttl <= f_ttl);
5148 +       }
5149 +       else
5150 +               return (ip->ttl == f_ttl);
5151 +}
5152 +
5153 +static int
5154 +match(const struct sk_buff *skb, const struct net_device *in, const struct net_device *out,
5155 +      const void *matchinfo, int offset,
5156 +      const void *hdr, u_int16_t datalen,
5157 +      int *hotdrop)
5158 +{
5159 +       struct ipt_osf_info *info = (struct ipt_osf_info *)matchinfo;
5160 +       struct iphdr *ip = skb->nh.iph;
5161 +       struct tcphdr *tcp;
5162 +       int fmatch = FMATCH_WRONG, fcount = 0;
5163 +       unsigned long totlen, optsize = 0, window;
5164 +       unsigned char df, *optp = NULL, *_optp = NULL;
5165 +       char check_WSS = 0;
5166 +       struct list_head *ent;
5167 +       struct osf_finger *f;
5168 +
5169 +       if (!ip || !info)
5170 +               return 0;
5171 +                               
5172 +       tcp = (struct tcphdr *)((u_int32_t *)ip + ip->ihl);
5173 +
5174 +       if (!tcp->syn)
5175 +               return 0;
5176 +       
5177 +       totlen = ntohs(ip->tot_len);
5178 +       df = ((ntohs(ip->frag_off) & IP_DF)?1:0);
5179 +       window = ntohs(tcp->window);
5180 +       
5181 +       if (tcp->doff*4 > sizeof(struct tcphdr))
5182 +       {
5183 +               _optp = optp = (char *)(tcp+1);
5184 +               optsize = tcp->doff*4 - sizeof(struct tcphdr);
5185 +       }
5186 +
5187 +       
5188 +       /* Actually we can create hash/table of all genres and search
5189 +        * only in appropriate part, but here is initial variant,
5190 +        * so will use slow path.
5191 +        */
5192 +       read_lock(&osf_lock);
5193 +       list_for_each(ent, &finger_list)
5194 +       {
5195 +               f = list_entry(ent, struct osf_finger, flist);
5196 +       
5197 +               if (!(info->flags & IPT_OSF_LOG) && strcmp(info->genre, f->genre)) 
5198 +                       continue;
5199 +
5200 +               optp = _optp;
5201 +               fmatch = FMATCH_WRONG;
5202 +
5203 +               if (totlen == f->ss && df == f->df && 
5204 +                       smart_dec(skb, info->flags, f->ttl))
5205 +               {
5206 +                       unsigned long foptsize;
5207 +                       int optnum;
5208 +                       unsigned short mss = 0;
5209 +
5210 +                       check_WSS = 0;
5211 +
5212 +                       switch (f->wss.wc)
5213 +                       {
5214 +                               case 0:   check_WSS = 0; break;
5215 +                               case 'S': check_WSS = 1; break;
5216 +                               case 'T': check_WSS = 2; break;
5217 +                               case '%': check_WSS = 3; break;
5218 +                               default: log("Wrong fingerprint wss.wc=%d, %s - %s\n", 
5219 +                                                        f->wss.wc, f->genre, f->details);
5220 +                                        check_WSS = 4;
5221 +                                        break;
5222 +                       }
5223 +                       if (check_WSS == 4)
5224 +                               continue;
5225 +
5226 +                       /* Check options */
5227 +
5228 +                       foptsize = 0;
5229 +                       for (optnum=0; optnum<f->opt_num; ++optnum)
5230 +                               foptsize += f->opt[optnum].length;
5231 +
5232 +                               
5233 +                       if (foptsize > MAX_IPOPTLEN || optsize > MAX_IPOPTLEN || optsize != foptsize)
5234 +                               continue;
5235 +
5236 +                       if (!optp)
5237 +                       {
5238 +                               fmatch = FMATCH_OK;
5239 +                               loga("\tYEP : matching without options.\n");
5240 +                               if ((info->flags & IPT_OSF_LOG) && 
5241 +                                       info->loglevel == IPT_OSF_LOGLEVEL_FIRST)
5242 +                                       break;
5243 +                               else
5244 +                                       continue;
5245 +                       }
5246 +                       
5247 +
5248 +                       for (optnum=0; optnum<f->opt_num; ++optnum)
5249 +                       {
5250 +                               if (f->opt[optnum].kind == (*optp)) 
5251 +                               {
5252 +                                       unsigned char len = f->opt[optnum].length;
5253 +                                       unsigned char *optend = optp + len;
5254 +                                       int loop_cont = 0;
5255 +
5256 +                                       fmatch = FMATCH_OK;
5257 +
5258 +
5259 +                                       switch (*optp)
5260 +                                       {
5261 +                                               case OSFOPT_MSS:
5262 +                                                       mss = ntohs(*(unsigned short *)(optp+2));
5263 +                                                       break;
5264 +                                               case OSFOPT_TS:
5265 +                                                       loop_cont = 1;
5266 +                                                       break;
5267 +                                       }
5268 +                                       
5269 +                                       if (loop_cont)
5270 +                                       {
5271 +                                               optp = optend;
5272 +                                               continue;
5273 +                                       }
5274 +                                       
5275 +                                       if (len != 1)
5276 +                                       {
5277 +                                               /* Skip kind and length fields*/
5278 +                                               optp += 2; 
5279 +
5280 +                                               if (f->opt[optnum].wc.val != 0)
5281 +                                               {
5282 +                                                       unsigned long tmp = 0;
5283 +                                                       
5284 +                                                       /* Hmmm... It looks a bit ugly. :) */
5285 +                                                       memcpy(&tmp, optp, 
5286 +                                                               (len > sizeof(unsigned long)?
5287 +                                                                       sizeof(unsigned long):len));
5288 +                                                       /* 2 + 2: optlen(2 bytes) + 
5289 +                                                        *      kind(1 byte) + length(1 byte) */
5290 +                                                       if (len == 4) 
5291 +                                                               tmp = ntohs(tmp);
5292 +                                                       else
5293 +                                                               tmp = ntohl(tmp);
5294 +
5295 +                                                       if (f->opt[optnum].wc.wc == '%')
5296 +                                                       {
5297 +                                                               if ((tmp % f->opt[optnum].wc.val) != 0)
5298 +                                                                       fmatch = FMATCH_OPT_WRONG;
5299 +                                                       }
5300 +                                                       else if (tmp != f->opt[optnum].wc.val)
5301 +                                                               fmatch = FMATCH_OPT_WRONG;
5302 +                                               }
5303 +                                       }
5304 +
5305 +                                       optp = optend;
5306 +                               }
5307 +                               else
5308 +                                       fmatch = FMATCH_OPT_WRONG;
5309 +
5310 +                               if (fmatch != FMATCH_OK)
5311 +                                       break;
5312 +                       }
5313 +
5314 +                       if (fmatch != FMATCH_OPT_WRONG)
5315 +                       {
5316 +                               fmatch = FMATCH_WRONG;
5317 +
5318 +                               switch (check_WSS)
5319 +                               {
5320 +                                       case 0:
5321 +                                               if (f->wss.val == 0 || window == f->wss.val)
5322 +                                                       fmatch = FMATCH_OK;
5323 +                                               break;
5324 +                                       case 1: /* MSS */
5325 +/* Lurked in OpenBSD */
5326 +#define SMART_MSS      1460
5327 +                                               if (window == f->wss.val*mss || 
5328 +                                                       window == f->wss.val*SMART_MSS)
5329 +                                                       fmatch = FMATCH_OK;
5330 +                                               break;
5331 +                                       case 2: /* MTU */
5332 +                                               if (window == f->wss.val*(mss+40) ||
5333 +                                                       window == f->wss.val*(SMART_MSS+40))
5334 +                                                       fmatch = FMATCH_OK;
5335 +                                               break;
5336 +                                       case 3: /* MOD */
5337 +                                               if ((window % f->wss.val) == 0)
5338 +                                                       fmatch = FMATCH_OK;
5339 +                                               break;
5340 +                               }
5341 +                       }
5342 +                                       
5343 +
5344 +                       if (fmatch == FMATCH_OK)
5345 +                       {
5346 +                               fcount++;
5347 +                               log("%s [%s:%s:%s] : %u.%u.%u.%u:%u -> %u.%u.%u.%u:%u hops=%d\n", 
5348 +                                       f->genre, f->version,
5349 +                                       f->subtype, f->details,
5350 +                                       NIPQUAD(ip->saddr), ntohs(tcp->source),
5351 +                                       NIPQUAD(ip->daddr), ntohs(tcp->dest),
5352 +                                       f->ttl - ip->ttl);
5353 +                               if (info->flags & IPT_OSF_NETLINK)
5354 +                               {
5355 +                                       spin_lock_bh(&ipt_osf_netlink_lock);
5356 +                                       ipt_osf_nlsend(f, skb);
5357 +                                       spin_unlock_bh(&ipt_osf_netlink_lock);
5358 +                               }
5359 +                               if ((info->flags & IPT_OSF_LOG) && 
5360 +                                       info->loglevel == IPT_OSF_LOGLEVEL_FIRST)
5361 +                                       break;
5362 +                       }
5363 +               }
5364 +       }
5365 +       if (!fcount && (info->flags & (IPT_OSF_LOG | IPT_OSF_NETLINK)))
5366 +       {
5367 +               unsigned char opt[4 * 15 - sizeof(struct tcphdr)];
5368 +               unsigned int i, optsize;
5369 +               struct osf_finger fg;
5370 +
5371 +               memset(&fg, 0, sizeof(fg));
5372 +
5373 +               if ((info->flags & IPT_OSF_LOG))
5374 +                       log("Unknown: %lu:%d:%d:%lu:", window, ip->ttl, df, totlen);
5375 +               if (optp)
5376 +               {
5377 +                       optsize = tcp->doff * 4 - sizeof(struct tcphdr);
5378 +                       if (skb_copy_bits(skb, ip->ihl*4 + sizeof(struct tcphdr),
5379 +                                         opt, optsize) < 0)
5380 +                       {
5381 +                               if (info->flags & IPT_OSF_LOG)
5382 +                                       loga("TRUNCATED");
5383 +                               if (info->flags & IPT_OSF_NETLINK)
5384 +                                       strcpy(fg.details, "TRUNCATED");
5385 +                       }
5386 +                       else
5387 +                       {
5388 +                               for (i = 0; i < optsize; i++)
5389 +                               {
5390 +                                       if (info->flags & IPT_OSF_LOG)
5391 +                                               loga("%02X", opt[i]);
5392 +                               }
5393 +                               if (info->flags & IPT_OSF_NETLINK)
5394 +                                       memcpy(fg.details, opt, MAXDETLEN);
5395 +                       }
5396 +               }
5397 +               if ((info->flags & IPT_OSF_LOG))
5398 +                       loga(" %u.%u.%u.%u:%u -> %u.%u.%u.%u:%u\n", 
5399 +                               NIPQUAD(ip->saddr), ntohs(tcp->source),
5400 +                               NIPQUAD(ip->daddr), ntohs(tcp->dest));
5401 +               
5402 +               if (info->flags & IPT_OSF_NETLINK)
5403 +               {
5404 +                       fg.wss.val      = window;
5405 +                       fg.ttl          = ip->ttl;
5406 +                       fg.df           = df;
5407 +                       fg.ss           = totlen;
5408 +                       strncpy(fg.genre, "Unknown", MAXGENRELEN);
5409 +
5410 +                       spin_lock_bh(&ipt_osf_netlink_lock);
5411 +                       ipt_osf_nlsend(&fg, skb);
5412 +                       spin_unlock_bh(&ipt_osf_netlink_lock);
5413 +               }
5414 +       }
5415 +
5416 +       read_unlock(&osf_lock);
5417 +
5418 +       return (fmatch == FMATCH_OK)?1:0;
5419 +}
5420 +
5421 +static int
5422 +checkentry(const char *tablename,
5423 +           const struct ipt_ip *ip,
5424 +           void *matchinfo,
5425 +           unsigned int matchsize,
5426 +           unsigned int hook_mask)
5427 +{
5428 +       if (matchsize != IPT_ALIGN(sizeof(struct ipt_osf_info)))
5429 +               return 0;
5430 +       if (ip->proto != IPPROTO_TCP)
5431 +              return 0;
5432 +
5433 +       return 1;
5434 +}
5435 +
5436 +static char * osf_strchr(char *ptr, char c)
5437 +{
5438 +       char *tmp;
5439 +
5440 +       tmp = strchr(ptr, c);
5441 +
5442 +       while (tmp && tmp+1 && isspace(*(tmp+1)))
5443 +               tmp++;
5444 +
5445 +       return tmp;
5446 +}
5447 +
5448 +static struct osf_finger * finger_alloc(void)
5449 +{
5450 +       struct osf_finger *f;
5451 +
5452 +       f = kmalloc(sizeof(struct osf_finger), GFP_KERNEL);
5453 +       if (f)
5454 +               memset(f, 0, sizeof(struct osf_finger));
5455 +       
5456 +       return f;
5457 +}
5458 +
5459 +static void finger_free(struct osf_finger *f)
5460 +{
5461 +       memset(f, 0, sizeof(struct osf_finger));
5462 +       kfree(f);
5463 +}
5464 +
5465 +
5466 +static void osf_parse_opt(struct osf_opt *opt, int *optnum, char *obuf, int olen)
5467 +{
5468 +       int i, op;
5469 +       char *ptr, wc;
5470 +       unsigned long val;
5471 +
5472 +       ptr = &obuf[0];
5473 +       i = 0;
5474 +       while (ptr != NULL && i < olen)
5475 +       {
5476 +               val = 0;
5477 +               op = 0;
5478 +               wc = 0;
5479 +               switch (obuf[i])
5480 +               {
5481 +                       case 'N': 
5482 +                               op = OSFOPT_NOP;
5483 +                               ptr = osf_strchr(&obuf[i], OPTDEL);
5484 +                               if (ptr)
5485 +                               {
5486 +                                       *ptr = '\0';
5487 +                                       ptr++;
5488 +                                       i += (int)(ptr-&obuf[i]);
5489 +
5490 +                               }
5491 +                               else
5492 +                                       i++;
5493 +                               break;
5494 +                       case 'S': 
5495 +                               op = OSFOPT_SACKP;
5496 +                               ptr = osf_strchr(&obuf[i], OPTDEL);
5497 +                               if (ptr)
5498 +                               {
5499 +                                       *ptr = '\0';
5500 +                                       ptr++;
5501 +                                       i += (int)(ptr-&obuf[i]);
5502 +
5503 +                               }
5504 +                               else
5505 +                                       i++;
5506 +                               break;
5507 +                       case 'T': 
5508 +                               op = OSFOPT_TS;
5509 +                               ptr = osf_strchr(&obuf[i], OPTDEL);
5510 +                               if (ptr)
5511 +                               {
5512 +                                       *ptr = '\0';
5513 +                                       ptr++;
5514 +                                       i += (int)(ptr-&obuf[i]);
5515 +
5516 +                               }
5517 +                               else
5518 +                                       i++;
5519 +                               break;
5520 +                       case 'W': 
5521 +                               op = OSFOPT_WSO;
5522 +                               ptr = osf_strchr(&obuf[i], OPTDEL);
5523 +                               if (ptr)
5524 +                               {
5525 +                                       switch (obuf[i+1])
5526 +                                       {
5527 +                                               case '%':       wc = '%'; break;
5528 +                                               case 'S':       wc = 'S'; break;
5529 +                                               case 'T':       wc = 'T'; break;
5530 +                                               default:        wc = 0; break;
5531 +                                       }
5532 +                                       
5533 +                                       *ptr = '\0';
5534 +                                       ptr++;
5535 +                                       if (wc)
5536 +                                               val = simple_strtoul(&obuf[i+2], NULL, 10);
5537 +                                       else
5538 +                                               val = simple_strtoul(&obuf[i+1], NULL, 10);
5539 +                                       i += (int)(ptr-&obuf[i]);
5540 +
5541 +                               }
5542 +                               else
5543 +                                       i++;
5544 +                               break;
5545 +                       case 'M': 
5546 +                               op = OSFOPT_MSS;
5547 +                               ptr = osf_strchr(&obuf[i], OPTDEL);
5548 +                               if (ptr)
5549 +                               {
5550 +                                       if (obuf[i+1] == '%')
5551 +                                               wc = '%';
5552 +                                       *ptr = '\0';
5553 +                                       ptr++;
5554 +                                       if (wc)
5555 +                                               val = simple_strtoul(&obuf[i+2], NULL, 10);
5556 +                                       else
5557 +                                               val = simple_strtoul(&obuf[i+1], NULL, 10);
5558 +                                       i += (int)(ptr-&obuf[i]);
5559 +
5560 +                               }
5561 +                               else
5562 +                                       i++;
5563 +                               break;
5564 +                       case 'E': 
5565 +                               op = OSFOPT_EOL;
5566 +                               ptr = osf_strchr(&obuf[i], OPTDEL);
5567 +                               if (ptr)
5568 +                               {
5569 +                                       *ptr = '\0';
5570 +                                       ptr++;
5571 +                                       i += (int)(ptr-&obuf[i]);
5572 +
5573 +                               }
5574 +                               else
5575 +                                       i++;
5576 +                               break;
5577 +                       default:
5578 +                               ptr = osf_strchr(&obuf[i], OPTDEL);
5579 +                               if (ptr)
5580 +                               {
5581 +                                       ptr++;
5582 +                                       i += (int)(ptr-&obuf[i]);
5583 +
5584 +                               }
5585 +                               else
5586 +                                       i++;
5587 +                               break;
5588 +               }
5589 +
5590 +               opt[*optnum].kind       = IANA_opts[op].kind;
5591 +               opt[*optnum].length     = IANA_opts[op].length;
5592 +               opt[*optnum].wc.wc      = wc;
5593 +               opt[*optnum].wc.val     = val;
5594 +
5595 +               (*optnum)++;
5596 +       }
5597 +}
5598 +
5599 +static int osf_proc_read(char *buf, char **start, off_t off, int count, int *eof, void *data)
5600 +{
5601 +       struct list_head *ent;
5602 +       struct osf_finger *f = NULL;
5603 +       int i;
5604 +       
5605 +       *eof = 1;
5606 +       count = 0;
5607 +
5608 +       read_lock_bh(&osf_lock);
5609 +       list_for_each(ent, &finger_list)
5610 +       {
5611 +               f = list_entry(ent, struct osf_finger, flist);
5612 +
5613 +               log("%s [%s]", f->genre, f->details);
5614 +               
5615 +               count += sprintf(buf+count, "%s - %s[%s] : %s", 
5616 +                                       f->genre, f->version,
5617 +                                       f->subtype, f->details);
5618 +               
5619 +               if (f->opt_num)
5620 +               {
5621 +                       loga(" OPT: ");
5622 +                       //count += sprintf(buf+count, " OPT: ");
5623 +                       for (i=0; i<f->opt_num; ++i)
5624 +                       {
5625 +                               //count += sprintf(buf+count, "%d.%c%lu; ", 
5626 +                               //      f->opt[i].kind, (f->opt[i].wc.wc)?f->opt[i].wc.wc:' ', f->opt[i].wc.val);
5627 +                               loga("%d.%c%lu; ", 
5628 +                                       f->opt[i].kind, (f->opt[i].wc.wc)?f->opt[i].wc.wc:' ', f->opt[i].wc.val);
5629 +                       }
5630 +               }
5631 +               loga("\n");
5632 +               count += sprintf(buf+count, "\n");
5633 +       }
5634 +       read_unlock_bh(&osf_lock);
5635 +
5636 +       return count;
5637 +}
5638 +
5639 +static int osf_proc_write(struct file *file, const char *buffer, unsigned long count, void *data)
5640 +{
5641 +       int cnt;
5642 +       unsigned long i;
5643 +       char obuf[MAXOPTSTRLEN];
5644 +       struct osf_finger *finger;
5645 +       struct list_head *ent, *n;
5646 +
5647 +       char *pbeg, *pend;
5648 +
5649 +       if (count == strlen(OSFFLUSH) && !strncmp(buffer, OSFFLUSH, strlen(OSFFLUSH)))
5650 +       {
5651 +               int i = 0;
5652 +               write_lock_bh(&osf_lock);
5653 +               list_for_each_safe(ent, n, &finger_list)
5654 +               {
5655 +                       i++;
5656 +                       finger = list_entry(ent, struct osf_finger, flist);
5657 +                       list_del(&finger->flist);
5658 +                       finger_free(finger);
5659 +               }
5660 +               write_unlock_bh(&osf_lock);
5661 +       
5662 +               log("Flushed %d entries.\n", i);
5663 +               
5664 +               return count;
5665 +       }
5666 +
5667 +       
5668 +       cnt = 0;
5669 +       for (i=0; i<count && buffer[i] != '\0'; ++i)
5670 +               if (buffer[i] == ':')
5671 +                       cnt++;
5672 +
5673 +       if (cnt != 8 || i != count)
5674 +       {
5675 +               log("Wrong input line cnt=%d[8], len=%lu[%lu]\n", 
5676 +                       cnt, i, count);
5677 +               return count;
5678 +       }
5679 +
5680 +       memset(obuf, 0, sizeof(obuf));
5681 +       
5682 +       finger = finger_alloc();
5683 +       if (!finger)
5684 +       {
5685 +               log("Failed to allocate new fingerprint entry.\n");
5686 +               return -ENOMEM;
5687 +       }
5688 +
5689 +       pbeg = (char *)buffer;
5690 +       pend = osf_strchr(pbeg, OSFPDEL);
5691 +       if (pend)
5692 +       {
5693 +               *pend = '\0';
5694 +               if (pbeg[0] == 'S')
5695 +               {
5696 +                       finger->wss.wc = 'S';
5697 +                       if (pbeg[1] == '%')
5698 +                               finger->wss.val = simple_strtoul(pbeg+2, NULL, 10);
5699 +                       else if (pbeg[1] == '*')
5700 +                               finger->wss.val = 0;
5701 +                       else 
5702 +                               finger->wss.val = simple_strtoul(pbeg+1, NULL, 10);
5703 +               }
5704 +               else if (pbeg[0] == 'T')
5705 +               {
5706 +                       finger->wss.wc = 'T';
5707 +                       if (pbeg[1] == '%')
5708 +                               finger->wss.val = simple_strtoul(pbeg+2, NULL, 10);
5709 +                       else if (pbeg[1] == '*')
5710 +                               finger->wss.val = 0;
5711 +                       else 
5712 +                               finger->wss.val = simple_strtoul(pbeg+1, NULL, 10);
5713 +               }
5714 +               else if (pbeg[0] == '%')
5715 +               {
5716 +                       finger->wss.wc = '%';
5717 +                       finger->wss.val = simple_strtoul(pbeg+1, NULL, 10);
5718 +               }
5719 +               else if (isdigit(pbeg[0]))
5720 +               {
5721 +                       finger->wss.wc = 0;
5722 +                       finger->wss.val = simple_strtoul(pbeg, NULL, 10);
5723 +               }
5724 +
5725 +               pbeg = pend+1;
5726 +       }
5727 +       pend = osf_strchr(pbeg, OSFPDEL);
5728 +       if (pend)
5729 +       {
5730 +               *pend = '\0';
5731 +               finger->ttl = simple_strtoul(pbeg, NULL, 10);
5732 +               pbeg = pend+1;
5733 +       }
5734 +       pend = osf_strchr(pbeg, OSFPDEL);
5735 +       if (pend)
5736 +       {
5737 +               *pend = '\0';
5738 +               finger->df = simple_strtoul(pbeg, NULL, 10);
5739 +               pbeg = pend+1;
5740 +       }
5741 +       pend = osf_strchr(pbeg, OSFPDEL);
5742 +       if (pend)
5743 +       {
5744 +               *pend = '\0';
5745 +               finger->ss = simple_strtoul(pbeg, NULL, 10);
5746 +               pbeg = pend+1;
5747 +       }
5748 +
5749 +       pend = osf_strchr(pbeg, OSFPDEL);
5750 +       if (pend)
5751 +       {
5752 +               *pend = '\0';
5753 +               cnt = snprintf(obuf, sizeof(obuf), "%s", pbeg);
5754 +               pbeg = pend+1;
5755 +       }
5756 +
5757 +       pend = osf_strchr(pbeg, OSFPDEL);
5758 +       if (pend)
5759 +       {
5760 +               *pend = '\0';
5761 +               if (pbeg[0] == '@' || pbeg[0] == '*')
5762 +                       cnt = snprintf(finger->genre, sizeof(finger->genre), "%s", pbeg+1);
5763 +               else
5764 +                       cnt = snprintf(finger->genre, sizeof(finger->genre), "%s", pbeg);
5765 +               pbeg = pend+1;
5766 +       }
5767 +       
5768 +       pend = osf_strchr(pbeg, OSFPDEL);
5769 +       if (pend)
5770 +       {
5771 +               *pend = '\0';
5772 +               cnt = snprintf(finger->version, sizeof(finger->version), "%s", pbeg);
5773 +               pbeg = pend+1;
5774 +       }
5775 +       
5776 +       pend = osf_strchr(pbeg, OSFPDEL);
5777 +       if (pend)
5778 +       {
5779 +               *pend = '\0';
5780 +               cnt = snprintf(finger->subtype, sizeof(finger->subtype), "%s", pbeg);
5781 +               pbeg = pend+1;
5782 +       }
5783 +
5784 +       cnt = snprintf(finger->details, 
5785 +                       ((count - (pbeg - buffer)+1) > MAXDETLEN)?MAXDETLEN:(count - (pbeg - buffer)+1), 
5786 +                       "%s", pbeg);
5787 +       
5788 +       log("%s - %s[%s] : %s\n", 
5789 +               finger->genre, finger->version,
5790 +               finger->subtype, finger->details);
5791 +       
5792 +       osf_parse_opt(finger->opt, &finger->opt_num, obuf, sizeof(obuf));
5793 +       
5794 +
5795 +       write_lock_bh(&osf_lock);
5796 +       list_add_tail(&finger->flist, &finger_list);
5797 +       write_unlock_bh(&osf_lock);
5798 +
5799 +       return count;
5800 +}
5801 +
5802 +static int __init osf_init(void)
5803 +{
5804 +       int err;
5805 +       struct proc_dir_entry *p;
5806 +
5807 +       log("Startng OS fingerprint matching module.\n");
5808 +
5809 +       INIT_LIST_HEAD(&finger_list);
5810 +       
5811 +       err = ipt_register_match(&osf_match);
5812 +       if (err)
5813 +       {
5814 +               log("Failed to register OS fingerprint matching module.\n");
5815 +               return -ENXIO;
5816 +       }
5817 +
5818 +       p = create_proc_entry("sys/net/ipv4/osf", S_IFREG | 0644, NULL);
5819 +       if (!p)
5820 +       {
5821 +               ipt_unregister_match(&osf_match);
5822 +               return -ENXIO;
5823 +       }
5824 +
5825 +       p->write_proc = osf_proc_write;
5826 +       p->read_proc  = osf_proc_read;
5827 +       
5828 +       nts = netlink_kernel_create(NETLINK_NFLOG, NULL);
5829 +       if (!nts)
5830 +       {
5831 +               log("netlink_kernel_create() failed\n");
5832 +               remove_proc_entry("sys/net/ipv4/osf", NULL);
5833 +               ipt_unregister_match(&osf_match);
5834 +               return -ENOMEM;
5835 +       }
5836 +
5837 +       return 0;
5838 +}
5839 +
5840 +static void __exit osf_fini(void)
5841 +{
5842 +       struct list_head *ent, *n;
5843 +       struct osf_finger *f;
5844 +       
5845 +       remove_proc_entry("sys/net/ipv4/osf", NULL);
5846 +       ipt_unregister_match(&osf_match);
5847 +//     if (nts && nts->socket)
5848 +//             sock_release(nts->socket);
5849 +
5850 +       list_for_each_safe(ent, n, &finger_list)
5851 +       {
5852 +               f = list_entry(ent, struct osf_finger, flist);
5853 +               list_del(&f->flist);
5854 +               finger_free(f);
5855 +       }
5856 +       
5857 +       log("OS fingerprint matching module finished.\n");
5858 +}
5859 +
5860 +module_init(osf_init);
5861 +module_exit(osf_fini);
5862 +
5863 +MODULE_LICENSE("GPL");
5864 +MODULE_AUTHOR("Evgeniy Polyakov <johnpol@2ka.mipt.ru>");
5865 +MODULE_DESCRIPTION("Passive OS fingerprint matching.");
5866 diff -Nur linux-2.6.6-rc1.org/net/ipv4/netfilter/ipt_pool.c linux-2.6.6-rc1/net/ipv4/netfilter/ipt_pool.c
5867 --- linux-2.6.6-rc1.org/net/ipv4/netfilter/ipt_pool.c   1970-01-01 01:00:00.000000000 +0100
5868 +++ linux-2.6.6-rc1/net/ipv4/netfilter/ipt_pool.c       2004-04-19 10:08:36.000000000 +0200
5869 @@ -0,0 +1,71 @@
5870 +/* Kernel module to match an IP address pool. */
5871 +
5872 +#include <linux/module.h>
5873 +#include <linux/ip.h>
5874 +#include <linux/skbuff.h>
5875 +
5876 +#include <linux/netfilter_ipv4/ip_tables.h>
5877 +#include <linux/netfilter_ipv4/ip_pool.h>
5878 +#include <linux/netfilter_ipv4/ipt_pool.h>
5879 +
5880 +static inline int match_pool(
5881 +       ip_pool_t index,
5882 +       __u32 addr,
5883 +       int inv
5884 +) {
5885 +       if (ip_pool_match(index, ntohl(addr)))
5886 +               inv = !inv;
5887 +       return inv;
5888 +}
5889 +
5890 +static int match(
5891 +       const struct sk_buff *skb,
5892 +       const struct net_device *in,
5893 +       const struct net_device *out,
5894 +       const void *matchinfo,
5895 +       int offset,
5896 +       const void *hdr,
5897 +       u_int16_t datalen,
5898 +       int *hotdrop
5899 +) {
5900 +       const struct ipt_pool_info *info = matchinfo;
5901 +       const struct iphdr *iph = skb->nh.iph;
5902 +
5903 +       if (info->src != IP_POOL_NONE && !match_pool(info->src, iph->saddr,
5904 +                                               info->flags&IPT_POOL_INV_SRC))
5905 +               return 0;
5906 +
5907 +       if (info->dst != IP_POOL_NONE && !match_pool(info->dst, iph->daddr,
5908 +                                               info->flags&IPT_POOL_INV_DST))
5909 +               return 0;
5910 +
5911 +       return 1;
5912 +}
5913 +
5914 +static int checkentry(
5915 +       const char *tablename,
5916 +       const struct ipt_ip *ip,
5917 +       void *matchinfo,
5918 +       unsigned int matchsize,
5919 +       unsigned int hook_mask
5920 +) {
5921 +       if (matchsize != IPT_ALIGN(sizeof(struct ipt_pool_info)))
5922 +               return 0;
5923 +       return 1;
5924 +}
5925 +
5926 +static struct ipt_match pool_match
5927 += { { NULL, NULL }, "pool", &match, &checkentry, NULL, THIS_MODULE };
5928 +
5929 +static int __init init(void)
5930 +{
5931 +       return ipt_register_match(&pool_match);
5932 +}
5933 +
5934 +static void __exit fini(void)
5935 +{
5936 +       ipt_unregister_match(&pool_match);
5937 +}
5938 +
5939 +module_init(init);
5940 +module_exit(fini);
5941 diff -Nur linux-2.6.6-rc1.org/net/ipv4/netfilter/ipt_psd.c linux-2.6.6-rc1/net/ipv4/netfilter/ipt_psd.c
5942 --- linux-2.6.6-rc1.org/net/ipv4/netfilter/ipt_psd.c    1970-01-01 01:00:00.000000000 +0100
5943 +++ linux-2.6.6-rc1/net/ipv4/netfilter/ipt_psd.c        2004-04-19 10:08:37.000000000 +0200
5944 @@ -0,0 +1,361 @@
5945 +/*
5946 +  This is a module which is used for PSD (portscan detection)
5947 +  Derived from scanlogd v2.1 written by Solar Designer <solar@false.com>
5948 +  and LOG target module.
5949 +
5950 +  Copyright (C) 2000,2001 astaro AG
5951 +
5952 +  This file is distributed under the terms of the GNU General Public
5953 +  License (GPL). Copies of the GPL can be obtained from:
5954 +     ftp://prep.ai.mit.edu/pub/gnu/GPL
5955 +
5956 +  2000-05-04 Markus Hennig <hennig@astaro.de> : initial
5957 +  2000-08-18 Dennis Koslowski <koslowski@astaro.de> : first release
5958 +  2000-12-01 Dennis Koslowski <koslowski@astaro.de> : UDP scans detection added
5959 +  2001-01-02 Dennis Koslowski <koslowski@astaro.de> : output modified
5960 +  2001-02-04 Jan Rekorajski <baggins@pld.org.pl> : converted from target to match
5961 +*/
5962 +
5963 +#include <linux/module.h>
5964 +#include <linux/skbuff.h>
5965 +#include <linux/ip.h>
5966 +#include <net/tcp.h>
5967 +#include <linux/spinlock.h>
5968 +#include <linux/netfilter_ipv4/ip_tables.h>
5969 +#include <linux/netfilter_ipv4/ipt_psd.h>
5970 +
5971 +#if 0
5972 +#define DEBUGP printk
5973 +#else
5974 +#define DEBUGP(format, args...)
5975 +#endif
5976 +
5977 +MODULE_LICENSE("GPL");
5978 +MODULE_AUTHOR("Dennis Koslowski <koslowski@astaro.com>");
5979 +
5980 +#define HF_DADDR_CHANGING   0x01
5981 +#define HF_SPORT_CHANGING   0x02
5982 +#define HF_TOS_CHANGING            0x04
5983 +#define HF_TTL_CHANGING            0x08
5984 +            
5985 +/*
5986 + * Information we keep per each target port
5987 + */
5988 +struct port {
5989 +       u_int16_t number;      /* port number */ 
5990 +       u_int8_t proto;        /* protocol number */
5991 +       u_int8_t and_flags;    /* tcp ANDed flags */
5992 +       u_int8_t or_flags;     /* tcp ORed flags */
5993 +};
5994 +
5995 +/*
5996 + * Information we keep per each source address.
5997 + */
5998 +struct host {
5999 +       struct host *next;              /* Next entry with the same hash */
6000 +       clock_t timestamp;              /* Last update time */
6001 +       struct in_addr src_addr;        /* Source address */
6002 +       struct in_addr dest_addr;       /* Destination address */
6003 +       unsigned short src_port;        /* Source port */
6004 +       int count;                      /* Number of ports in the list */
6005 +       int weight;                     /* Total weight of ports in the list */
6006 +       struct port ports[SCAN_MAX_COUNT - 1];  /* List of ports */
6007 +       unsigned char tos;              /* TOS */
6008 +       unsigned char ttl;              /* TTL */
6009 +       unsigned char flags;            /* HF_ flags bitmask */
6010 +};
6011 +
6012 +/*
6013 + * State information.
6014 + */
6015 +static struct {
6016 +       spinlock_t lock;
6017 +       struct host list[LIST_SIZE];    /* List of source addresses */
6018 +       struct host *hash[HASH_SIZE];   /* Hash: pointers into the list */
6019 +       int index;                      /* Oldest entry to be replaced */
6020 +} state;
6021 +
6022 +/*
6023 + * Convert an IP address into a hash table index.
6024 + */
6025 +static inline int hashfunc(struct in_addr addr)
6026 +{
6027 +       unsigned int value;
6028 +       int hash;
6029 +
6030 +       value = addr.s_addr;
6031 +       hash = 0;
6032 +       do {
6033 +               hash ^= value;
6034 +       } while ((value >>= HASH_LOG));
6035 +
6036 +       return hash & (HASH_SIZE - 1);
6037 +}
6038 +
6039 +static int
6040 +ipt_psd_match(const struct sk_buff *pskb,
6041 +             const struct net_device *in,
6042 +             const struct net_device *out,
6043 +             const void *matchinfo,
6044 +             int offset,
6045 +             const void *hdr,
6046 +             u_int16_t datalen,
6047 +             int *hotdrop)
6048 +{
6049 +       struct iphdr *ip_hdr;
6050 +       struct tcphdr *tcp_hdr;
6051 +       struct in_addr addr;
6052 +       u_int16_t src_port,dest_port;
6053 +       u_int8_t tcp_flags, proto;
6054 +       clock_t now;
6055 +       struct host *curr, *last, **head;
6056 +       int hash, index, count;
6057 +
6058 +       /* Parameters from userspace */
6059 +       const struct ipt_psd_info *psdinfo = matchinfo;
6060 +
6061 +       /* IP header */
6062 +       ip_hdr = pskb->nh.iph;
6063 +
6064 +       /* Sanity check */
6065 +       if (ntohs(ip_hdr->frag_off) & IP_OFFSET) {
6066 +               DEBUGP("PSD: sanity check failed\n");
6067 +               return 0;
6068 +       }
6069 +
6070 +       /* TCP or UDP ? */
6071 +       proto = ip_hdr->protocol;
6072 +
6073 +       if (proto != IPPROTO_TCP && proto != IPPROTO_UDP) {
6074 +               DEBUGP("PSD: protocol not supported\n");
6075 +               return 0;
6076 +       }
6077 +
6078 +       /* Get the source address, source & destination ports, and TCP flags */
6079 +
6080 +       addr.s_addr = ip_hdr->saddr;
6081 +
6082 +       tcp_hdr = (struct tcphdr*)((u_int32_t *)ip_hdr + ip_hdr->ihl);
6083 +
6084 +       /* Yep, it´s dirty */
6085 +       src_port = tcp_hdr->source;
6086 +       dest_port = tcp_hdr->dest;
6087 +
6088 +       if (proto == IPPROTO_TCP) {
6089 +               tcp_flags = *((u_int8_t*)tcp_hdr + 13);
6090 +       }
6091 +       else {
6092 +               tcp_flags = 0x00;
6093 +       }
6094 +
6095 +       /* We're using IP address 0.0.0.0 for a special purpose here, so don't let
6096 +        * them spoof us. [DHCP needs this feature - HW] */
6097 +       if (!addr.s_addr) {
6098 +               DEBUGP("PSD: spoofed source address (0.0.0.0)\n");
6099 +               return 0;
6100 +       }
6101 +
6102 +       /* Use jiffies here not to depend on someone setting the time while we're
6103 +        * running; we need to be careful with possible return value overflows. */
6104 +       now = jiffies;
6105 +
6106 +       spin_lock(&state.lock);
6107 +
6108 +       /* Do we know this source address already? */
6109 +       count = 0;
6110 +       last = NULL;
6111 +       if ((curr = *(head = &state.hash[hash = hashfunc(addr)])))
6112 +               do {
6113 +                       if (curr->src_addr.s_addr == addr.s_addr) break;
6114 +                       count++;
6115 +                       if (curr->next) last = curr;
6116 +               } while ((curr = curr->next));
6117 +
6118 +       if (curr) {
6119 +
6120 +               /* We know this address, and the entry isn't too old. Update it. */
6121 +               if (now - curr->timestamp <= (psdinfo->delay_threshold*HZ)/100 &&
6122 +                   time_after_eq(now, curr->timestamp)) {
6123 +
6124 +                       /* Just update the appropriate list entry if we've seen this port already */
6125 +                       for (index = 0; index < curr->count; index++) {
6126 +                               if (curr->ports[index].number == dest_port) {
6127 +                                       curr->ports[index].proto = proto;
6128 +                                       curr->ports[index].and_flags &= tcp_flags;
6129 +                                       curr->ports[index].or_flags |= tcp_flags;
6130 +                                       goto out_no_match;
6131 +                               }
6132 +                       }
6133 +
6134 +                       /* TCP/ACK and/or TCP/RST to a new port? This could be an outgoing connection. */
6135 +                       if (proto == IPPROTO_TCP && (tcp_hdr->ack || tcp_hdr->rst))
6136 +                               goto out_no_match;
6137 +
6138 +                       /* Packet to a new port, and not TCP/ACK: update the timestamp */
6139 +                       curr->timestamp = now;
6140 +
6141 +                       /* Logged this scan already? Then drop the packet. */
6142 +                       if (curr->weight >= psdinfo->weight_threshold)
6143 +                               goto out_match;
6144 +
6145 +                       /* Specify if destination address, source port, TOS or TTL are not fixed */
6146 +                       if (curr->dest_addr.s_addr != ip_hdr->daddr)
6147 +                               curr->flags |= HF_DADDR_CHANGING;
6148 +                       if (curr->src_port != src_port)
6149 +                               curr->flags |= HF_SPORT_CHANGING;
6150 +                       if (curr->tos != ip_hdr->tos)
6151 +                               curr->flags |= HF_TOS_CHANGING;
6152 +                       if (curr->ttl != ip_hdr->ttl)
6153 +                               curr->flags |= HF_TTL_CHANGING;
6154 +
6155 +                       /* Update the total weight */
6156 +                       curr->weight += (ntohs(dest_port) < 1024) ?
6157 +                               psdinfo->lo_ports_weight : psdinfo->hi_ports_weight;
6158 +
6159 +                       /* Got enough destination ports to decide that this is a scan? */
6160 +                       /* Then log it and drop the packet. */
6161 +                       if (curr->weight >= psdinfo->weight_threshold)
6162 +                               goto out_match;
6163 +
6164 +                       /* Remember the new port */
6165 +                       if (curr->count < SCAN_MAX_COUNT) {
6166 +                               curr->ports[curr->count].number = dest_port;
6167 +                               curr->ports[curr->count].proto = proto;
6168 +                               curr->ports[curr->count].and_flags = tcp_flags;
6169 +                               curr->ports[curr->count].or_flags = tcp_flags;
6170 +                               curr->count++;
6171 +                       }
6172 +
6173 +                       goto out_no_match;
6174 +               }
6175 +
6176 +               /* We know this address, but the entry is outdated. Mark it unused, and
6177 +                * remove from the hash table. We'll allocate a new entry instead since
6178 +                * this one might get re-used too soon. */
6179 +               curr->src_addr.s_addr = 0;
6180 +               if (last)
6181 +                       last->next = last->next->next;
6182 +               else if (*head)
6183 +                       *head = (*head)->next;
6184 +               last = NULL;
6185 +       }
6186 +
6187 +       /* We don't need an ACK from a new source address */
6188 +       if (proto == IPPROTO_TCP && tcp_hdr->ack)
6189 +               goto out_no_match;
6190 +
6191 +       /* Got too many source addresses with the same hash value? Then remove the
6192 +        * oldest one from the hash table, so that they can't take too much of our
6193 +        * CPU time even with carefully chosen spoofed IP addresses. */
6194 +       if (count >= HASH_MAX && last) last->next = NULL;
6195 +
6196 +       /* We're going to re-use the oldest list entry, so remove it from the hash
6197 +        * table first (if it is really already in use, and isn't removed from the
6198 +        * hash table already because of the HASH_MAX check above). */
6199 +
6200 +       /* First, find it */
6201 +       if (state.list[state.index].src_addr.s_addr)
6202 +               head = &state.hash[hashfunc(state.list[state.index].src_addr)];
6203 +       else
6204 +               head = &last;
6205 +       last = NULL;
6206 +       if ((curr = *head))
6207 +       do {
6208 +               if (curr == &state.list[state.index]) break;
6209 +               last = curr;
6210 +       } while ((curr = curr->next));
6211 +
6212 +       /* Then, remove it */
6213 +       if (curr) {
6214 +               if (last)
6215 +                       last->next = last->next->next;
6216 +               else if (*head)
6217 +                       *head = (*head)->next;
6218 +       }
6219 +
6220 +       /* Get our list entry */
6221 +       curr = &state.list[state.index++];
6222 +       if (state.index >= LIST_SIZE) state.index = 0;
6223 +
6224 +       /* Link it into the hash table */
6225 +       head = &state.hash[hash];
6226 +       curr->next = *head;
6227 +       *head = curr;
6228 +
6229 +       /* And fill in the fields */
6230 +       curr->timestamp = now;
6231 +       curr->src_addr = addr;
6232 +       curr->dest_addr.s_addr = ip_hdr->daddr;
6233 +       curr->src_port = src_port;
6234 +       curr->count = 1;
6235 +       curr->weight = (ntohs(dest_port) < 1024) ?
6236 +               psdinfo->lo_ports_weight : psdinfo->hi_ports_weight;
6237 +       curr->ports[0].number = dest_port;
6238 +       curr->ports[0].proto = proto;
6239 +       curr->ports[0].and_flags = tcp_flags;
6240 +       curr->ports[0].or_flags = tcp_flags;
6241 +       curr->tos = ip_hdr->tos;
6242 +       curr->ttl = ip_hdr->ttl;
6243 +
6244 +out_no_match:
6245 +       spin_unlock(&state.lock);
6246 +       return 0;
6247 +
6248 +out_match:
6249 +       spin_unlock(&state.lock);
6250 +       return 1;
6251 +}
6252 +
6253 +static int ipt_psd_checkentry(const char *tablename,
6254 +                             const struct ipt_ip *e,
6255 +                             void *matchinfo,
6256 +                             unsigned int matchsize,
6257 +                             unsigned int hook_mask)
6258 +{
6259 +/*     const struct ipt_psd_info *psdinfo = targinfo;*/
6260 +
6261 +       /* we accept TCP only */
6262 +/*     if (e->ip.proto != IPPROTO_TCP) { */
6263 +/*             DEBUGP("PSD: specified protocol may be TCP only\n"); */
6264 +/*             return 0; */
6265 +/*     } */
6266 +
6267 +       if (matchsize != IPT_ALIGN(sizeof(struct ipt_psd_info))) {
6268 +               DEBUGP("PSD: matchsize %u != %u\n",
6269 +                      matchsize,
6270 +                      IPT_ALIGN(sizeof(struct ipt_psd_info)));
6271 +               return 0;
6272 +       }
6273 +
6274 +       return 1;
6275 +}
6276 +
6277 +static struct ipt_match ipt_psd_reg = { 
6278 +       {NULL, NULL},
6279 +       "psd",
6280 +       ipt_psd_match,
6281 +       ipt_psd_checkentry,
6282 +       NULL,
6283 +       THIS_MODULE };
6284 +
6285 +static int __init init(void)
6286 +{
6287 +       if (ipt_register_match(&ipt_psd_reg))
6288 +               return -EINVAL;
6289 +
6290 +       memset(&state, 0, sizeof(state));
6291 +
6292 +       spin_lock_init(&(state.lock));
6293 +
6294 +       printk("netfilter PSD loaded - (c) astaro AG\n");
6295 +       return 0;
6296 +}
6297 +
6298 +static void __exit fini(void)
6299 +{
6300 +       ipt_unregister_match(&ipt_psd_reg);
6301 +       printk("netfilter PSD unloaded - (c) astaro AG\n");
6302 +}
6303 +
6304 +module_init(init);
6305 +module_exit(fini);
6306 diff -Nur linux-2.6.6-rc1.org/net/ipv4/netfilter/ipt_quota.c linux-2.6.6-rc1/net/ipv4/netfilter/ipt_quota.c
6307 --- linux-2.6.6-rc1.org/net/ipv4/netfilter/ipt_quota.c  1970-01-01 01:00:00.000000000 +0100
6308 +++ linux-2.6.6-rc1/net/ipv4/netfilter/ipt_quota.c      2004-04-19 10:08:37.000000000 +0200
6309 @@ -0,0 +1,91 @@
6310 +/* 
6311 + * netfilter module to enforce network quotas
6312 + *
6313 + * Sam Johnston <samj@samj.net>
6314 + */
6315 +#include <linux/module.h>
6316 +#include <linux/skbuff.h>
6317 +#include <linux/spinlock.h>
6318 +#include <linux/interrupt.h>
6319 +
6320 +#include <linux/netfilter_ipv4/ip_tables.h>
6321 +#include <linux/netfilter_ipv4/ipt_quota.h>
6322 +
6323 +MODULE_LICENSE("GPL");
6324 +MODULE_AUTHOR("Sam Johnston <samj@samj.net>");
6325 +
6326 +static spinlock_t quota_lock = SPIN_LOCK_UNLOCKED;
6327 +
6328 +static int
6329 +match(const struct sk_buff *skb,
6330 +      const struct net_device *in,
6331 +      const struct net_device *out,
6332 +      const void *matchinfo,
6333 +      int offset, int *hotdrop)
6334 +{
6335 +        struct ipt_quota_info *q = (struct ipt_quota_info *) matchinfo;
6336 +       unsigned int datalen;
6337 +
6338 +       if (skb->len < sizeof(struct iphdr))
6339 +               return NF_ACCEPT;
6340 +       
6341 +       datalen = skb->len - skb->nh.iph->ihl*4;
6342 +
6343 +        spin_lock_bh(&quota_lock);
6344 +
6345 +        if (q->quota >= datalen) {
6346 +                /* we can afford this one */
6347 +                q->quota -= datalen;
6348 +                spin_unlock_bh(&quota_lock);
6349 +
6350 +#ifdef DEBUG_IPT_QUOTA
6351 +                printk("IPT Quota OK: %llu datlen %d \n", q->quota, datalen);
6352 +#endif
6353 +                return 1;
6354 +        }
6355 +
6356 +        /* so we do not allow even small packets from now on */
6357 +        q->quota = 0;
6358 +
6359 +#ifdef DEBUG_IPT_QUOTA
6360 +        printk("IPT Quota Failed: %llu datlen %d \n", q->quota, datalen);
6361 +#endif
6362 +
6363 +        spin_unlock_bh(&quota_lock);
6364 +        return 0;
6365 +}
6366 +
6367 +static int
6368 +checkentry(const char *tablename,
6369 +           const struct ipt_ip *ip,
6370 +           void *matchinfo, unsigned int matchsize, unsigned int hook_mask)
6371 +{
6372 +        /* TODO: spinlocks? sanity checks? */
6373 +        if (matchsize != IPT_ALIGN(sizeof (struct ipt_quota_info)))
6374 +                return 0;
6375 +
6376 +        return 1;
6377 +}
6378 +
6379 +static struct ipt_match quota_match = {
6380 +       .name = "quota",
6381 +       .match = match,
6382 +       .checkentry = checkentry,
6383 +       .me = THIS_MODULE
6384 +};
6385 +
6386 +static int __init
6387 +init(void)
6388 +{
6389 +        return ipt_register_match(&quota_match);
6390 +}
6391 +
6392 +static void __exit
6393 +fini(void)
6394 +{
6395 +        ipt_unregister_match(&quota_match);
6396 +}
6397 +
6398 +module_init(init);
6399 +module_exit(fini);
6400 +
6401 diff -Nur linux-2.6.6-rc1.org/net/ipv4/netfilter/ipt_random.c linux-2.6.6-rc1/net/ipv4/netfilter/ipt_random.c
6402 --- linux-2.6.6-rc1.org/net/ipv4/netfilter/ipt_random.c 1970-01-01 01:00:00.000000000 +0100
6403 +++ linux-2.6.6-rc1/net/ipv4/netfilter/ipt_random.c     2004-04-19 10:08:38.000000000 +0200
6404 @@ -0,0 +1,96 @@
6405 +/*
6406 +  This is a module which is used for a "random" match support.
6407 +  This file is distributed under the terms of the GNU General Public
6408 +  License (GPL). Copies of the GPL can be obtained from:
6409 +     ftp://prep.ai.mit.edu/pub/gnu/GPL
6410 +
6411 +  2001-10-14 Fabrice MARIE <fabrice@netfilter.org> : initial implementation.
6412 +*/
6413 +
6414 +#include <linux/module.h>
6415 +#include <linux/skbuff.h>
6416 +#include <linux/ip.h>
6417 +#include <linux/random.h>
6418 +#include <net/tcp.h>
6419 +#include <linux/spinlock.h>
6420 +#include <linux/netfilter_ipv4/ip_tables.h>
6421 +#include <linux/netfilter_ipv4/ipt_random.h>
6422 +
6423 +MODULE_LICENSE("GPL");
6424 +
6425 +static int
6426 +ipt_rand_match(const struct sk_buff *pskb,
6427 +              const struct net_device *in,
6428 +              const struct net_device *out,
6429 +              const void *matchinfo,
6430 +              int offset,
6431 +              const void *hdr,
6432 +              u_int16_t datalen,
6433 +              int *hotdrop)
6434 +{
6435 +       /* Parameters from userspace */
6436 +       const struct ipt_rand_info *info = matchinfo;
6437 +       u_int8_t random_number;
6438 +
6439 +       /* get 1 random number from the kernel random number generation routine */
6440 +       get_random_bytes((void *)(&random_number), 1);
6441 +
6442 +       /* Do we match ? */
6443 +       if (random_number <= info->average)
6444 +               return 1;
6445 +       else
6446 +               return 0;
6447 +}
6448 +
6449 +static int
6450 +ipt_rand_checkentry(const char *tablename,
6451 +                  const struct ipt_ip *e,
6452 +                  void *matchinfo,
6453 +                  unsigned int matchsize,
6454 +                  unsigned int hook_mask)
6455 +{
6456 +       /* Parameters from userspace */
6457 +       const struct ipt_rand_info *info = matchinfo;
6458 +
6459 +       if (matchsize != IPT_ALIGN(sizeof(struct ipt_rand_info))) {
6460 +               printk("ipt_random: matchsize %u != %u\n", matchsize,
6461 +                      IPT_ALIGN(sizeof(struct ipt_rand_info)));
6462 +               return 0;
6463 +       }
6464 +
6465 +       /* must be  1 <= average % <= 99 */
6466 +       /* 1  x 2.55 = 2   */
6467 +       /* 99 x 2.55 = 252 */
6468 +       if ((info->average < 2) || (info->average > 252)) {
6469 +               printk("ipt_random:  invalid average %u\n", info->average);
6470 +               return 0;
6471 +       }
6472 +
6473 +       return 1;
6474 +}
6475 +
6476 +static struct ipt_match ipt_rand_reg = { 
6477 +       {NULL, NULL},
6478 +       "random",
6479 +       ipt_rand_match,
6480 +       ipt_rand_checkentry,
6481 +       NULL,
6482 +       THIS_MODULE };
6483 +
6484 +static int __init init(void)
6485 +{
6486 +       if (ipt_register_match(&ipt_rand_reg))
6487 +               return -EINVAL;
6488 +
6489 +       printk("ipt_random match loaded\n");
6490 +       return 0;
6491 +}
6492 +
6493 +static void __exit fini(void)
6494 +{
6495 +       ipt_unregister_match(&ipt_rand_reg);
6496 +       printk("ipt_random match unloaded\n");
6497 +}
6498 +
6499 +module_init(init);
6500 +module_exit(fini);
6501 diff -Nur linux-2.6.6-rc1.org/net/ipv4/netfilter/ipt_realm.c linux-2.6.6-rc1/net/ipv4/netfilter/ipt_realm.c
6502 --- linux-2.6.6-rc1.org/net/ipv4/netfilter/ipt_realm.c  1970-01-01 01:00:00.000000000 +0100
6503 +++ linux-2.6.6-rc1/net/ipv4/netfilter/ipt_realm.c      2004-04-19 10:08:39.000000000 +0200
6504 @@ -0,0 +1,78 @@
6505 +/* IP tables module for matching the routing realm
6506 + *
6507 + * $Id$
6508 + *
6509 + * (C) 2003 by Sampsa Ranta <sampsa@netsonic.fi>
6510 + *
6511 + * This program is free software; you can redistribute it and/or modify
6512 + * it under the terms of the GNU General Public License version 2 as
6513 + * published by the Free Software Foundation.
6514 + */
6515 +
6516 +#include <linux/module.h>
6517 +#include <linux/skbuff.h>
6518 +#include <linux/netdevice.h>
6519 +#include <net/route.h>
6520 +
6521 +#include <linux/netfilter_ipv4/ipt_realm.h>
6522 +#include <linux/netfilter_ipv4/ip_tables.h>
6523 +
6524 +MODULE_AUTHOR("Sampsa Ranta <sampsa@netsonic.fi>");
6525 +MODULE_LICENSE("GPL");
6526 +
6527 +static int
6528 +match(const struct sk_buff *skb,
6529 +      const struct net_device *in,
6530 +      const struct net_device *out,
6531 +      const void *matchinfo,
6532 +      int offset,
6533 +      int *hotdrop)
6534 +{
6535 +       const struct ipt_realm_info *info = matchinfo;
6536 +       struct dst_entry *dst = skb->dst;
6537 +    
6538 +       if (!dst)
6539 +               return 0;
6540 +
6541 +       return (info->id == (dst->tclassid & info->mask)) ^ info->invert;
6542 +}
6543 +
6544 +static int check(const char *tablename,
6545 +                 const struct ipt_ip *ip,
6546 +                 void *matchinfo,
6547 +                 unsigned int matchsize,
6548 +                 unsigned int hook_mask)
6549 +{
6550 +       if (hook_mask
6551 +           & ~((1 << NF_IP_POST_ROUTING) | (1 << NF_IP_FORWARD) |
6552 +               (1 << NF_IP_LOCAL_OUT)| (1 << NF_IP_LOCAL_IN))) {
6553 +               printk("ipt_realm: only valid for POST_ROUTING, LOCAL_OUT, "
6554 +                      "LOCAL_IN or FORWARD.\n");
6555 +               return 0;
6556 +       }
6557 +
6558 +       if (matchsize != IPT_ALIGN(sizeof(struct ipt_realm_info)))
6559 +               return 0;
6560 +
6561 +       return 1;
6562 +}
6563 +
6564 +static struct ipt_match realm_match = {
6565 +       .name = "realm",
6566 +       .match = match, 
6567 +       .checkentry = check,
6568 +       .me = THIS_MODULE
6569 +};
6570 +
6571 +static int __init init(void)
6572 +{
6573 +       return ipt_register_match(&realm_match);
6574 +}
6575 +
6576 +static void __exit fini(void)
6577 +{
6578 +       ipt_unregister_match(&realm_match);
6579 +}
6580 +
6581 +module_init(init);
6582 +module_exit(fini);
6583 diff -Nur linux-2.6.6-rc1.org/net/ipv4/netfilter/ipt_sctp.c linux-2.6.6-rc1/net/ipv4/netfilter/ipt_sctp.c
6584 --- linux-2.6.6-rc1.org/net/ipv4/netfilter/ipt_sctp.c   1970-01-01 01:00:00.000000000 +0100
6585 +++ linux-2.6.6-rc1/net/ipv4/netfilter/ipt_sctp.c       2004-04-19 10:08:40.000000000 +0200
6586 @@ -0,0 +1,199 @@
6587 +#include <linux/module.h>
6588 +#include <linux/skbuff.h>
6589 +#include <net/ip.h>
6590 +#include <linux/sctp.h>
6591 +
6592 +#include <linux/netfilter_ipv4/ip_tables.h>
6593 +#include <linux/netfilter_ipv4/ipt_sctp.h>
6594 +
6595 +#if 0
6596 +#define duprintf(format, args...) printk(format , ## args)
6597 +#else
6598 +#define duprintf(format, args...)
6599 +#endif
6600 +
6601 +#define SCCHECK(cond, option, flag, invflag) (!((flag) & (option)) \
6602 +                                             || (!!((invflag) & (option)) ^ (cond)))
6603 +
6604 +static int
6605 +match_flags(const struct ipt_sctp_flag_info *flag_info,
6606 +           const int flag_count,
6607 +           u_int8_t chunktype,
6608 +           u_int8_t chunkflags)
6609 +{
6610 +       int i;
6611 +
6612 +       for (i = 0; i < flag_count; i++) {
6613 +               if (flag_info[i].chunktype == chunktype) {
6614 +                       return (chunkflags & flag_info[i].flag_mask) == flag_info[i].flag;
6615 +               }
6616 +       }
6617 +
6618 +       return 1;
6619 +}
6620 +
6621 +static int
6622 +match_packet(const struct sk_buff *skb,
6623 +            const u_int32_t *chunkmap,
6624 +            int chunk_match_type,
6625 +            const struct ipt_sctp_flag_info *flag_info,
6626 +            const int flag_count,
6627 +            int *hotdrop)
6628 +{
6629 +       int offset;
6630 +       u_int32_t chunkmapcopy[256 / sizeof (u_int32_t)];
6631 +       sctp_chunkhdr_t sch;
6632 +
6633 +       int i = 0;
6634 +
6635 +       if (chunk_match_type == SCTP_CHUNK_MATCH_ALL) {
6636 +               SCTP_CHUNKMAP_COPY(chunkmapcopy, chunkmap);
6637 +       }
6638 +
6639 +       offset = skb->nh.iph->ihl * 4 + sizeof (sctp_sctphdr_t);
6640 +       do {
6641 +               if (skb_copy_bits(skb, offset, &sch, sizeof(sch)) < 0) {
6642 +                       duprintf("Dropping invalid SCTP packet.\n");
6643 +                       *hotdrop = 1;
6644 +                       return 0;
6645 +               }
6646 +
6647 +               duprintf("Chunk num: %d\toffset: %d\ttype: %d\tlength: %d\tflags: %x\n", 
6648 +                               ++i, offset, sch.type, htons(sch.length), sch.flags);
6649 +
6650 +               offset += (htons(sch.length) + 3) & ~3;
6651 +
6652 +               duprintf("skb->len: %d\toffset: %d\n", skb->len, offset);
6653 +
6654 +               if (SCTP_CHUNKMAP_IS_SET(chunkmap, sch.type)) {
6655 +                       switch (chunk_match_type) {
6656 +                       case SCTP_CHUNK_MATCH_ANY:
6657 +                               if (match_flags(flag_info, flag_count, 
6658 +                                       sch.type, sch.flags)) {
6659 +                                       return 1;
6660 +                               }
6661 +                               break;
6662 +
6663 +                       case SCTP_CHUNK_MATCH_ALL:
6664 +                               if (match_flags(flag_info, flag_count, 
6665 +                                       sch.type, sch.flags)) {
6666 +                                       SCTP_CHUNKMAP_CLEAR(chunkmapcopy, sch.type);
6667 +                               }
6668 +                               break;
6669 +
6670 +                       case SCTP_CHUNK_MATCH_ONLY:
6671 +                               if (!match_flags(flag_info, flag_count, 
6672 +                                       sch.type, sch.flags)) {
6673 +                                       return 0;
6674 +                               }
6675 +                               break;
6676 +                       }
6677 +               } else {
6678 +                       switch (chunk_match_type) {
6679 +                       case SCTP_CHUNK_MATCH_ONLY:
6680 +                               return 0;
6681 +                       }
6682 +               }
6683 +       } while (offset < skb->len);
6684 +
6685 +       switch (chunk_match_type) {
6686 +       case SCTP_CHUNK_MATCH_ALL:
6687 +               return SCTP_CHUNKMAP_IS_CLEAR(chunkmap);
6688 +       case SCTP_CHUNK_MATCH_ANY:
6689 +               return 0;
6690 +       case SCTP_CHUNK_MATCH_ONLY:
6691 +               return 1;
6692 +       }
6693 +
6694 +       /* This will never be reached, but required to stop compiler whine */
6695 +       return 0;
6696 +}
6697 +
6698 +static int
6699 +match(const struct sk_buff *skb,
6700 +      const struct net_device *in,
6701 +      const struct net_device *out,
6702 +      const void *matchinfo,
6703 +      int offset,
6704 +      int *hotdrop)
6705 +{
6706 +       const struct ipt_sctp_info *info;
6707 +       sctp_sctphdr_t sh;
6708 +
6709 +       info = (const struct ipt_sctp_info *)matchinfo;
6710 +
6711 +       if (offset) {
6712 +               duprintf("Dropping non-first fragment.. FIXME\n");
6713 +               return 0;
6714 +       }
6715 +       
6716 +       if (skb_copy_bits(skb, skb->nh.iph->ihl*4, &sh, sizeof(sh)) < 0) {
6717 +               duprintf("Dropping evil TCP offset=0 tinygram.\n");
6718 +               *hotdrop = 1;
6719 +               return 0;
6720 +               }
6721 +       duprintf("spt: %d\tdpt: %d\n", ntohs(sh.source), ntohs(sh.dest));
6722 +
6723 +       return  SCCHECK(((ntohs(sh.source) >= info->spts[0]) 
6724 +                       && (ntohs(sh.source) <= info->spts[1])), 
6725 +                       IPT_SCTP_SRC_PORTS, info->flags, info->invflags)
6726 +               && SCCHECK(((ntohs(sh.dest) >= info->dpts[0]) 
6727 +                       && (ntohs(sh.dest) <= info->dpts[1])), 
6728 +                       IPT_SCTP_DEST_PORTS, info->flags, info->invflags)
6729 +               && SCCHECK(match_packet(skb, info->chunkmap, info->chunk_match_type,
6730 +                                       info->flag_info, info->flag_count, 
6731 +                                       hotdrop),
6732 +                          IPT_SCTP_CHUNK_TYPES, info->flags, info->invflags);
6733 +}
6734 +
6735 +static int
6736 +checkentry(const char *tablename,
6737 +          const struct ipt_ip *ip,
6738 +          void *matchinfo,
6739 +          unsigned int matchsize,
6740 +          unsigned int hook_mask)
6741 +{
6742 +       const struct ipt_sctp_info *info;
6743 +
6744 +       info = (const struct ipt_sctp_info *)matchinfo;
6745 +
6746 +       return ip->proto == IPPROTO_SCTP
6747 +               && !(ip->invflags & IPT_INV_PROTO)
6748 +               && matchsize == IPT_ALIGN(sizeof(struct ipt_sctp_info))
6749 +               && !(info->flags & ~IPT_SCTP_VALID_FLAGS)
6750 +               && !(info->invflags & ~IPT_SCTP_VALID_FLAGS)
6751 +               && !(info->invflags & ~info->flags)
6752 +               && ((!(info->flags & IPT_SCTP_CHUNK_TYPES)) || 
6753 +                       (info->chunk_match_type &
6754 +                               (SCTP_CHUNK_MATCH_ALL 
6755 +                               | SCTP_CHUNK_MATCH_ANY
6756 +                               | SCTP_CHUNK_MATCH_ONLY)));
6757 +}
6758 +
6759 +static struct ipt_match sctp_match = 
6760 +{ 
6761 +       .list = { NULL, NULL},
6762 +       .name = "sctp",
6763 +       .match = &match,
6764 +       .checkentry = &checkentry,
6765 +       .destroy = NULL,
6766 +       .me = THIS_MODULE
6767 +};
6768 +
6769 +static int __init init(void)
6770 +{
6771 +       return ipt_register_match(&sctp_match);
6772 +}
6773 +
6774 +static void __exit fini(void)
6775 +{
6776 +       ipt_unregister_match(&sctp_match);
6777 +}
6778 +
6779 +module_init(init);
6780 +module_exit(fini);
6781 +
6782 +MODULE_LICENSE("GPL");
6783 +MODULE_AUTHOR("Kiran Kumar Immidi");
6784 +MODULE_DESCRIPTION("Match for SCTP protocol packets");
6785 +
6786 diff -Nur linux-2.6.6-rc1.org/net/ipv4/netfilter/ipt_time.c linux-2.6.6-rc1/net/ipv4/netfilter/ipt_time.c
6787 --- linux-2.6.6-rc1.org/net/ipv4/netfilter/ipt_time.c   1970-01-01 01:00:00.000000000 +0100
6788 +++ linux-2.6.6-rc1/net/ipv4/netfilter/ipt_time.c       2004-04-19 10:08:41.000000000 +0200
6789 @@ -0,0 +1,185 @@
6790 +/*
6791 +  This is a module which is used for time matching
6792 +  It is using some modified code from dietlibc (localtime() function)
6793 +  that you can find at http://www.fefe.de/dietlibc/
6794 +  This file is distributed under the terms of the GNU General Public
6795 +  License (GPL). Copies of the GPL can be obtained from: ftp://prep.ai.mit.edu/pub/gnu/GPL
6796 +  2001-05-04 Fabrice MARIE <fabrice@netfilter.org> : initial development.
6797 +  2001-21-05 Fabrice MARIE <fabrice@netfilter.org> : bug fix in the match code,
6798 +     thanks to "Zeng Yu" <zengy@capitel.com.cn> for bug report.
6799 +  2001-26-09 Fabrice MARIE <fabrice@netfilter.org> : force the match to be in LOCAL_IN or PRE_ROUTING only.
6800 +  2001-30-11 Fabrice : added the possibility to use the match in FORWARD/OUTPUT with a little hack,
6801 +     added Nguyen Dang Phuoc Dong <dongnd@tlnet.com.vn> patch to support timezones.
6802 +*/
6803 +
6804 +#include <linux/module.h>
6805 +#include <linux/skbuff.h>
6806 +#include <linux/netfilter_ipv4/ip_tables.h>
6807 +#include <linux/netfilter_ipv4/ipt_time.h>
6808 +#include <linux/time.h>
6809 +
6810 +MODULE_AUTHOR("Fabrice MARIE <fabrice@netfilter.org>");
6811 +MODULE_DESCRIPTION("Match arrival timestamp");
6812 +MODULE_LICENSE("GPL");
6813 +
6814 +struct tm
6815 +{
6816 +       int tm_sec;                   /* Seconds.     [0-60] (1 leap second) */
6817 +       int tm_min;                   /* Minutes.     [0-59] */
6818 +       int tm_hour;                  /* Hours.       [0-23] */
6819 +       int tm_mday;                  /* Day.         [1-31] */
6820 +       int tm_mon;                   /* Month.       [0-11] */
6821 +       int tm_year;                  /* Year - 1900.  */
6822 +       int tm_wday;                  /* Day of week. [0-6] */
6823 +       int tm_yday;                  /* Days in year.[0-365] */
6824 +       int tm_isdst;                 /* DST.         [-1/0/1]*/
6825 +
6826 +       long int tm_gmtoff;           /* we don't care, we count from GMT */
6827 +       const char *tm_zone;          /* we don't care, we count from GMT */
6828 +};
6829 +
6830 +void
6831 +localtime(const time_t *timepr, struct tm *r);
6832 +
6833 +static int
6834 +match(const struct sk_buff *skb,
6835 +      const struct net_device *in,
6836 +      const struct net_device *out,
6837 +      const void *matchinfo,
6838 +      int offset,
6839 +      const void *hdr,
6840 +      u_int16_t datalen,
6841 +      int *hotdrop)
6842 +{
6843 +       const struct ipt_time_info *info = matchinfo;   /* match info for rule */
6844 +       struct tm currenttime;                          /* time human readable */
6845 +       u_int8_t days_of_week[7] = {64, 32, 16, 8, 4, 2, 1};
6846 +       u_int16_t packet_time;
6847 +       struct timeval kerneltimeval;
6848 +       time_t packet_local_time;
6849 +
6850 +       /* if kerneltime=1, we don't read the skb->timestamp but kernel time instead */
6851 +       if (info->kerneltime)
6852 +       {
6853 +               do_gettimeofday(&kerneltimeval);
6854 +               packet_local_time = kerneltimeval.tv_sec;
6855 +       }
6856 +       else
6857 +               packet_local_time = skb->stamp.tv_sec;
6858 +
6859 +       /* Transform the timestamp of the packet, in a human readable form */
6860 +       localtime(&packet_local_time, &currenttime);
6861 +
6862 +       /* check if we match this timestamp, we start by the days... */
6863 +       if ((days_of_week[currenttime.tm_wday] & info->days_match) != days_of_week[currenttime.tm_wday])
6864 +               return 0; /* the day doesn't match */
6865 +
6866 +       /* ... check the time now */
6867 +       packet_time = (currenttime.tm_hour * 60) + currenttime.tm_min;
6868 +       if ((packet_time < info->time_start) || (packet_time > info->time_stop))
6869 +               return 0;
6870 +
6871 +       /* here we match ! */
6872 +       return 1;
6873 +}
6874 +
6875 +static int
6876 +checkentry(const char *tablename,
6877 +           const struct ipt_ip *ip,
6878 +           void *matchinfo,
6879 +           unsigned int matchsize,
6880 +           unsigned int hook_mask)
6881 +{
6882 +       struct ipt_time_info *info = matchinfo;   /* match info for rule */
6883 +
6884 +       /* First, check that we are in the correct hook */
6885 +       /* PRE_ROUTING, LOCAL_IN or FROWARD */
6886 +       if (hook_mask
6887 +            & ~((1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_LOCAL_IN) | (1 << NF_IP_FORWARD) | (1 << NF_IP_LOCAL_OUT)))
6888 +       {
6889 +               printk("ipt_time: error, only valid for PRE_ROUTING, LOCAL_IN, FORWARD and OUTPUT)\n");
6890 +               return 0;
6891 +       }
6892 +       /* we use the kerneltime if we are in forward or output */
6893 +       info->kerneltime = 1;
6894 +       if (hook_mask & ~((1 << NF_IP_FORWARD) | (1 << NF_IP_LOCAL_OUT))) 
6895 +               /* if not, we use the skb time */
6896 +               info->kerneltime = 0;
6897 +
6898 +       /* Check the size */
6899 +       if (matchsize != IPT_ALIGN(sizeof(struct ipt_time_info)))
6900 +               return 0;
6901 +       /* Now check the coherence of the data ... */
6902 +       if ((info->time_start > 1439) ||        /* 23*60+59 = 1439*/
6903 +           (info->time_stop  > 1439))
6904 +       {
6905 +               printk(KERN_WARNING "ipt_time: invalid argument\n");
6906 +               return 0;
6907 +       }
6908 +
6909 +       return 1;
6910 +}
6911 +
6912 +static struct ipt_match time_match
6913 += { { NULL, NULL }, "time", &match, &checkentry, NULL, THIS_MODULE };
6914 +
6915 +static int __init init(void)
6916 +{
6917 +       printk("ipt_time loading\n");
6918 +       return ipt_register_match(&time_match);
6919 +}
6920 +
6921 +static void __exit fini(void)
6922 +{
6923 +       ipt_unregister_match(&time_match);
6924 +       printk("ipt_time unloaded\n");
6925 +}
6926 +
6927 +module_init(init);
6928 +module_exit(fini);
6929 +
6930 +
6931 +/* The part below is borowed and modified from dietlibc */
6932 +
6933 +/* seconds per day */
6934 +#define SPD 24*60*60
6935 +
6936 +void
6937 +localtime(const time_t *timepr, struct tm *r) {
6938 +       time_t i;
6939 +       time_t timep;
6940 +       extern struct timezone sys_tz;
6941 +       const unsigned int __spm[12] =
6942 +               { 0,
6943 +                 (31),
6944 +                 (31+28),
6945 +                 (31+28+31),
6946 +                 (31+28+31+30),
6947 +                 (31+28+31+30+31),
6948 +                 (31+28+31+30+31+30),
6949 +                 (31+28+31+30+31+30+31),
6950 +                 (31+28+31+30+31+30+31+31),
6951 +                 (31+28+31+30+31+30+31+31+30),
6952 +                 (31+28+31+30+31+30+31+31+30+31),
6953 +                 (31+28+31+30+31+30+31+31+30+31+30),
6954 +               };
6955 +       register time_t work;
6956 +
6957 +       timep = (*timepr) - (sys_tz.tz_minuteswest * 60);
6958 +       work=timep%(SPD);
6959 +       r->tm_sec=work%60; work/=60;
6960 +       r->tm_min=work%60; r->tm_hour=work/60;
6961 +       work=timep/(SPD);
6962 +       r->tm_wday=(4+work)%7;
6963 +       for (i=1970; ; ++i) {
6964 +               register time_t k= (!(i%4) && ((i%100) || !(i%400)))?366:365;
6965 +               if (work>k)
6966 +                       work-=k;
6967 +               else
6968 +                       break;
6969 +       }
6970 +       r->tm_year=i-1900;
6971 +       for (i=11; i && __spm[i]>work; --i) ;
6972 +       r->tm_mon=i;
6973 +       r->tm_mday=work-__spm[i]+1;
6974 +}
6975 diff -Nur linux-2.6.6-rc1.org/net/ipv4/netfilter/ipt_u32.c linux-2.6.6-rc1/net/ipv4/netfilter/ipt_u32.c
6976 --- linux-2.6.6-rc1.org/net/ipv4/netfilter/ipt_u32.c    1970-01-01 01:00:00.000000000 +0100
6977 +++ linux-2.6.6-rc1/net/ipv4/netfilter/ipt_u32.c        2004-04-19 10:08:46.000000000 +0200
6978 @@ -0,0 +1,211 @@
6979 +/* Kernel module to match u32 packet content. */
6980 +
6981 +/* 
6982 +U32 tests whether quantities of up to 4 bytes extracted from a packet 
6983 +have specified values.  The specification of what to extract is general 
6984 +enough to find data at given offsets from tcp headers or payloads.
6985 +
6986 + --u32 tests
6987 + The argument amounts to a program in a small language described below.
6988 + tests := location = value |  tests && location = value
6989 + value := range | value , range
6990 + range := number | number : number
6991 +  a single number, n, is interpreted the same as n:n
6992 +  n:m is interpreted as the range of numbers >=n and <=m
6993 + location := number | location operator number
6994 + operator := & | << | >> | @
6995 +
6996 + The operators &, <<, >>, && mean the same as in c.  The = is really a set
6997 + membership operator and the value syntax describes a set.  The @ operator
6998 + is what allows moving to the next header and is described further below.
6999 +
7000 + *** Until I can find out how to avoid it, there are some artificial limits
7001 + on the size of the tests:
7002 + - no more than 10 ='s (and 9 &&'s) in the u32 argument
7003 + - no more than 10 ranges (and 9 commas) per value
7004 + - no more than 10 numbers (and 9 operators) per location
7005 +
7006 + To describe the meaning of location, imagine the following machine that
7007 + interprets it.  There are three registers:
7008 +  A is of type char*, initially the address of the IP header
7009 +  B and C are unsigned 32 bit integers, initially zero
7010 +
7011 +  The instructions are:
7012 +   number      B = number;
7013 +               C = (*(A+B)<<24)+(*(A+B+1)<<16)+(*(A+B+2)<<8)+*(A+B+3)
7014 +   &number     C = C&number
7015 +   <<number    C = C<<number
7016 +   >>number    C = C>>number
7017 +   @number     A = A+C; then do the instruction number
7018 +  Any access of memory outside [skb->head,skb->end] causes the match to fail.
7019 +  Otherwise the result of the computation is the final value of C.
7020 +
7021 + Whitespace is allowed but not required in the tests.
7022 + However the characters that do occur there are likely to require
7023 + shell quoting, so it's a good idea to enclose the arguments in quotes.
7024 +
7025 +Example:
7026 + match IP packets with total length >= 256
7027 + The IP header contains a total length field in bytes 2-3.
7028 + --u32 "0&0xFFFF=0x100:0xFFFF" 
7029 + read bytes 0-3
7030 + AND that with FFFF (giving bytes 2-3),
7031 + and test whether that's in the range [0x100:0xFFFF]
7032 +
7033 +Example: (more realistic, hence more complicated)
7034 + match icmp packets with icmp type 0
7035 + First test that it's an icmp packet, true iff byte 9 (protocol) = 1
7036 + --u32 "6&0xFF=1 && ...
7037 + read bytes 6-9, use & to throw away bytes 6-8 and compare the result to 1
7038 + Next test that it's not a fragment.
7039 +  (If so it might be part of such a packet but we can't always tell.)
7040 +  n.b. This test is generally needed if you want to match anything
7041 +  beyond the IP header.
7042 + The last 6 bits of byte 6 and all of byte 7 are 0 iff this is a complete
7043 + packet (not a fragment).  Alternatively, you can allow first fragments
7044 + by only testing the last 5 bits of byte 6.
7045 + ... 4&0x3FFF=0 && ...
7046 + Last test: the first byte past the IP header (the type) is 0
7047 + This is where we have to use the @syntax.  The length of the IP header
7048 + (IHL) in 32 bit words is stored in the right half of byte 0 of the
7049 + IP header itself.
7050 + ... 0>>22&0x3C@0>>24=0"
7051 + The first 0 means read bytes 0-3,
7052 + >>22 means shift that 22 bits to the right.  Shifting 24 bits would give
7053 +   the first byte, so only 22 bits is four times that plus a few more bits.
7054 + &3C then eliminates the two extra bits on the right and the first four 
7055 + bits of the first byte.
7056 + For instance, if IHL=5 then the IP header is 20 (4 x 5) bytes long.
7057 + In this case bytes 0-1 are (in binary) xxxx0101 yyzzzzzz, 
7058 + >>22 gives the 10 bit value xxxx0101yy and &3C gives 010100.
7059 + @ means to use this number as a new offset into the packet, and read
7060 + four bytes starting from there.  This is the first 4 bytes of the icmp
7061 + payload, of which byte 0 is the icmp type.  Therefore we simply shift
7062 + the value 24 to the right to throw out all but the first byte and compare
7063 + the result with 0.
7064 +
7065 +Example: 
7066 + tcp payload bytes 8-12 is any of 1, 2, 5 or 8
7067 + First we test that the packet is a tcp packet (similar to icmp).
7068 + --u32 "6&0xFF=6 && ...
7069 + Next, test that it's not a fragment (same as above).
7070 + ... 0>>22&0x3C@12>>26&0x3C@8=1,2,5,8"
7071 + 0>>22&3C as above computes the number of bytes in the IP header.
7072 + @ makes this the new offset into the packet, which is the start of the
7073 + tcp header.  The length of the tcp header (again in 32 bit words) is
7074 + the left half of byte 12 of the tcp header.  The 12>>26&3C
7075 + computes this length in bytes (similar to the IP header before).
7076 + @ makes this the new offset, which is the start of the tcp payload.
7077 + Finally 8 reads bytes 8-12 of the payload and = checks whether the
7078 + result is any of 1, 2, 5 or 8
7079 +*/
7080 +
7081 +#include <linux/module.h>
7082 +#include <linux/skbuff.h>
7083 +
7084 +#include <linux/netfilter_ipv4/ipt_u32.h>
7085 +#include <linux/netfilter_ipv4/ip_tables.h>
7086 +
7087 +/* #include <asm-i386/timex.h> for timing */
7088 +
7089 +MODULE_AUTHOR("Don Cohen <don@isis.cs3-inc.com>");
7090 +MODULE_DESCRIPTION("IP tables u32 matching module");
7091 +MODULE_LICENSE("GPL");
7092 +
7093 +static int
7094 +match(const struct sk_buff *skb,
7095 +      const struct net_device *in,
7096 +      const struct net_device *out,
7097 +      const void *matchinfo,
7098 +      int offset,
7099 +      const void *hdr,
7100 +      u_int16_t datalen,
7101 +      int *hotdrop)
7102 +{
7103 +       const struct ipt_u32 *data = matchinfo;
7104 +       int testind, i;
7105 +       unsigned char* origbase = (char*)skb->nh.iph;
7106 +       unsigned char* base = origbase;
7107 +       unsigned char* head = skb->head;
7108 +       unsigned char* end = skb->end;
7109 +       int nnums, nvals;
7110 +       u_int32_t pos, val;
7111 +       /* unsigned long long cycles1, cycles2, cycles3, cycles4;
7112 +          cycles1 = get_cycles(); */
7113 +
7114 +       for (testind=0; testind < data->ntests; testind++) {
7115 +               base = origbase; /* reset for each test */
7116 +               pos = data->tests[testind].location[0].number;
7117 +               if (base+pos+3 > end || base+pos < head) 
7118 +                       return 0;
7119 +               val = (base[pos]<<24) + (base[pos+1]<<16) +
7120 +                       (base[pos+2]<<8) + base[pos+3];
7121 +               nnums = data->tests[testind].nnums;
7122 +               for (i=1; i < nnums; i++) {
7123 +                       u_int32_t number = data->tests[testind].location[i].number;
7124 +                       switch (data->tests[testind].location[i].nextop) {
7125 +                       case IPT_U32_AND: 
7126 +                               val = val & number; 
7127 +                               break;
7128 +                       case IPT_U32_LEFTSH: 
7129 +                               val = val << number;
7130 +                               break;
7131 +                       case IPT_U32_RIGHTSH: 
7132 +                               val = val >> number; 
7133 +                               break;
7134 +                       case IPT_U32_AT:
7135 +                               base = base + val;
7136 +                               pos = number;
7137 +                               if (base+pos+3 > end || base+pos < head) 
7138 +                                       return 0;
7139 +                               val = (base[pos]<<24) + (base[pos+1]<<16) +
7140 +                                       (base[pos+2]<<8) + base[pos+3];
7141 +                               break;
7142 +                       }
7143 +               }
7144 +               nvals = data->tests[testind].nvalues;
7145 +               for (i=0; i < nvals; i++) {
7146 +                       if ((data->tests[testind].value[i].min <= val) &&
7147 +                           (val <= data->tests[testind].value[i].max)) {
7148 +                               break;
7149 +                       }
7150 +               }
7151 +               if (i >= data->tests[testind].nvalues) {
7152 +                       /* cycles2 = get_cycles(); 
7153 +                          printk("failed %d in %d cycles\n", testind, 
7154 +                                 cycles2-cycles1); */
7155 +                       return 0;
7156 +               }
7157 +       }
7158 +       /* cycles2 = get_cycles();
7159 +          printk("succeeded in %d cycles\n", cycles2-cycles1); */
7160 +       return 1;
7161 +}
7162 +
7163 +static int
7164 +checkentry(const char *tablename,
7165 +           const struct ipt_ip *ip,
7166 +           void *matchinfo,
7167 +           unsigned int matchsize,
7168 +           unsigned int hook_mask)
7169 +{
7170 +       if (matchsize != IPT_ALIGN(sizeof(struct ipt_u32)))
7171 +               return 0;
7172 +       return 1;
7173 +}
7174 +
7175 +static struct ipt_match u32_match
7176 += { { NULL, NULL }, "u32", &match, &checkentry, NULL, THIS_MODULE };
7177 +
7178 +static int __init init(void)
7179 +{
7180 +       return ipt_register_match(&u32_match);
7181 +}
7182 +
7183 +static void __exit fini(void)
7184 +{
7185 +       ipt_unregister_match(&u32_match);
7186 +}
7187 +
7188 +module_init(init);
7189 +module_exit(fini);
7190 diff -Nur linux-2.6.6-rc1.org/net/ipv6/ip6_tunnel.c linux-2.6.6-rc1/net/ipv6/ip6_tunnel.c
7191 --- linux-2.6.6-rc1.org/net/ipv6/ip6_tunnel.c   2004-04-15 03:33:53.000000000 +0200
7192 +++ linux-2.6.6-rc1/net/ipv6/ip6_tunnel.c       2004-04-19 10:08:24.000000000 +0200
7193 @@ -715,13 +715,7 @@
7194         ipv6h->nexthdr = proto;
7195         ipv6_addr_copy(&ipv6h->saddr, &fl.fl6_src);
7196         ipv6_addr_copy(&ipv6h->daddr, &fl.fl6_dst);
7197 -#ifdef CONFIG_NETFILTER
7198 -       nf_conntrack_put(skb->nfct);
7199 -       skb->nfct = NULL;
7200 -#ifdef CONFIG_NETFILTER_DEBUG
7201 -       skb->nf_debug = 0;
7202 -#endif
7203 -#endif
7204 +       nf_reset(skb);
7205         pkt_len = skb->len;
7206         err = NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, 
7207                       skb->dst->dev, dst_output);
7208 diff -Nur linux-2.6.6-rc1.org/net/ipv6/netfilter/Kconfig linux-2.6.6-rc1/net/ipv6/netfilter/Kconfig
7209 --- linux-2.6.6-rc1.org/net/ipv6/netfilter/Kconfig      2004-04-19 09:59:33.000000000 +0200
7210 +++ linux-2.6.6-rc1/net/ipv6/netfilter/Kconfig  2004-04-19 10:08:38.000000000 +0200
7211 @@ -230,5 +230,30 @@
7212           <file:Documentation/modules.txt>.  If unsure, say `N'.
7213           help
7214  
7215 +config IP6_NF_TARGET_HL
7216 +       tristate  'HL target support'
7217 +       depends on IP6_NF_MANGLE
7218 +         help
7219 +
7220 +config IP6_NF_TARGET_REJECT
7221 +       tristate  'REJECT target support'
7222 +       depends on IP6_NF_FILTER
7223 +         help
7224 +
7225 +config IP6_NF_MATCH_FUZZY
7226 +       tristate  'Fuzzy match support'
7227 +       depends on IP6_NF_FILTER
7228 +         help
7229 +
7230 +config IP6_NF_MATCH_NTH
7231 +       tristate  'Nth match support'
7232 +       depends on IP6_NF_IPTABLES
7233 +         help
7234 +
7235 +config IP6_NF_MATCH_RANDOM
7236 +       tristate  'Random match support'
7237 +       depends on IP6_NF_IPTABLES
7238 +         help
7239 +
7240  endmenu
7241  
7242 diff -Nur linux-2.6.6-rc1.org/net/ipv6/netfilter/Makefile linux-2.6.6-rc1/net/ipv6/netfilter/Makefile
7243 --- linux-2.6.6-rc1.org/net/ipv6/netfilter/Makefile     2004-04-19 09:59:33.000000000 +0200
7244 +++ linux-2.6.6-rc1/net/ipv6/netfilter/Makefile 2004-04-19 10:08:38.000000000 +0200
7245 @@ -8,6 +8,7 @@
7246  obj-$(CONFIG_IP6_NF_MATCH_MARK) += ip6t_mark.o
7247  obj-$(CONFIG_IP6_NF_MATCH_LENGTH) += ip6t_length.o
7248  obj-$(CONFIG_IP6_NF_MATCH_MAC) += ip6t_mac.o
7249 +obj-$(CONFIG_IP6_NF_MATCH_FUZZY) += ip6t_fuzzy.o
7250  obj-$(CONFIG_IP6_NF_MATCH_RT) += ip6t_rt.o
7251  obj-$(CONFIG_IP6_NF_MATCH_OPTS) += ip6t_hbh.o ip6t_dst.o
7252  obj-$(CONFIG_IP6_NF_MATCH_IPV6HEADER) += ip6t_ipv6header.o
7253 @@ -19,7 +20,13 @@
7254  obj-$(CONFIG_IP6_NF_FILTER) += ip6table_filter.o
7255  obj-$(CONFIG_IP6_NF_MANGLE) += ip6table_mangle.o
7256  obj-$(CONFIG_IP6_NF_TARGET_MARK) += ip6t_MARK.o
7257 +obj-$(CONFIG_IP6_NF_TARGET_REJECT) += ip6t_REJECT.o
7258  obj-$(CONFIG_IP6_NF_QUEUE) += ip6_queue.o
7259  obj-$(CONFIG_IP6_NF_TARGET_LOG) += ip6t_LOG.o
7260 +
7261 +obj-$(CONFIG_IP6_NF_MATCH_RANDOM) += ip6t_random.o
7262 +
7263 +obj-$(CONFIG_IP6_NF_MATCH_NTH) += ip6t_nth.o
7264 +obj-$(CONFIG_IP6_NF_TARGET_HL) += ip6t_HL.o
7265  obj-$(CONFIG_IP6_NF_RAW) += ip6table_raw.o
7266  obj-$(CONFIG_IP6_NF_MATCH_HL) += ip6t_hl.o
7267 diff -Nur linux-2.6.6-rc1.org/net/ipv6/netfilter/ip6t_HL.c linux-2.6.6-rc1/net/ipv6/netfilter/ip6t_HL.c
7268 --- linux-2.6.6-rc1.org/net/ipv6/netfilter/ip6t_HL.c    1970-01-01 01:00:00.000000000 +0100
7269 +++ linux-2.6.6-rc1/net/ipv6/netfilter/ip6t_HL.c        2004-04-19 10:08:26.000000000 +0200
7270 @@ -0,0 +1,105 @@
7271 +/* 
7272 + * Hop Limit modification target for ip6tables
7273 + * Maciej Soltysiak <solt@dns.toxicfilms.tv>
7274 + * Based on HW's TTL module
7275 + *
7276 + * This software is distributed under the terms of GNU GPL
7277 + */
7278 +
7279 +#include <linux/module.h>
7280 +#include <linux/skbuff.h>
7281 +#include <linux/ip.h>
7282 +
7283 +#include <linux/netfilter_ipv6/ip6_tables.h>
7284 +#include <linux/netfilter_ipv6/ip6t_HL.h>
7285 +
7286 +MODULE_AUTHOR("Maciej Soltysiak <solt@dns.toxicfilms.tv>");
7287 +MODULE_DESCRIPTION("IP tables Hop Limit modification module");
7288 +MODULE_LICENSE("GPL");
7289 +
7290 +static unsigned int ip6t_hl_target(struct sk_buff **pskb, unsigned int hooknum,
7291 +               const struct net_device *in, const struct net_device *out,
7292 +               const void *targinfo, void *userinfo)
7293 +{
7294 +       struct ipv6hdr *ip6h = (*pskb)->nh.ipv6h;
7295 +       const struct ip6t_HL_info *info = targinfo;
7296 +       u_int16_t diffs[2];
7297 +       int new_hl;
7298 +                        
7299 +       switch (info->mode) {
7300 +               case IP6T_HL_SET:
7301 +                       new_hl = info->hop_limit;
7302 +                       break;
7303 +               case IP6T_HL_INC:
7304 +                       new_hl = ip6h->hop_limit + info->hop_limit;
7305 +                       if (new_hl > 255)
7306 +                               new_hl = 255;
7307 +                       break;
7308 +               case IP6T_HL_DEC:
7309 +                       new_hl = ip6h->hop_limit + info->hop_limit;
7310 +                       if (new_hl < 0)
7311 +                               new_hl = 0;
7312 +                       break;
7313 +               default:
7314 +                       new_hl = ip6h->hop_limit;
7315 +                       break;
7316 +       }
7317 +
7318 +       if (new_hl != ip6h->hop_limit) {
7319 +               diffs[0] = htons(((unsigned)ip6h->hop_limit) << 8) ^ 0xFFFF;
7320 +               ip6h->hop_limit = new_hl;
7321 +               diffs[1] = htons(((unsigned)ip6h->hop_limit) << 8);
7322 +       }
7323 +
7324 +       return IP6T_CONTINUE;
7325 +}
7326 +
7327 +static int ip6t_hl_checkentry(const char *tablename,
7328 +               const struct ip6t_entry *e,
7329 +               void *targinfo,
7330 +               unsigned int targinfosize,
7331 +               unsigned int hook_mask)
7332 +{
7333 +       struct ip6t_HL_info *info = targinfo;
7334 +
7335 +       if (targinfosize != IP6T_ALIGN(sizeof(struct ip6t_HL_info))) {
7336 +               printk(KERN_WARNING "HL: targinfosize %u != %Zu\n",
7337 +                               targinfosize,
7338 +                               IP6T_ALIGN(sizeof(struct ip6t_HL_info)));
7339 +               return 0;       
7340 +       }       
7341 +
7342 +       if (strcmp(tablename, "mangle")) {
7343 +               printk(KERN_WARNING "HL: can only be called from \"mangle\" table, not \"%s\"\n", tablename);
7344 +               return 0;
7345 +       }
7346 +
7347 +       if (info->mode > IP6T_HL_MAXMODE) {
7348 +               printk(KERN_WARNING "HL: invalid or unknown Mode %u\n", 
7349 +                       info->mode);
7350 +               return 0;
7351 +       }
7352 +
7353 +       if ((info->mode != IP6T_HL_SET) && (info->hop_limit == 0)) {
7354 +               printk(KERN_WARNING "HL: increment/decrement doesn't make sense with value 0\n");
7355 +               return 0;
7356 +       }
7357 +       
7358 +       return 1;
7359 +}
7360 +
7361 +static struct ip6t_target ip6t_HL = { { NULL, NULL }, "HL", 
7362 +       ip6t_hl_target, ip6t_hl_checkentry, NULL, THIS_MODULE };
7363 +
7364 +static int __init init(void)
7365 +{
7366 +       return ip6t_register_target(&ip6t_HL);
7367 +}
7368 +
7369 +static void __exit fini(void)
7370 +{
7371 +       ip6t_unregister_target(&ip6t_HL);
7372 +}
7373 +
7374 +module_init(init);
7375 +module_exit(fini);
7376 diff -Nur linux-2.6.6-rc1.org/net/ipv6/netfilter/ip6t_REJECT.c linux-2.6.6-rc1/net/ipv6/netfilter/ip6t_REJECT.c
7377 --- linux-2.6.6-rc1.org/net/ipv6/netfilter/ip6t_REJECT.c        1970-01-01 01:00:00.000000000 +0100
7378 +++ linux-2.6.6-rc1/net/ipv6/netfilter/ip6t_REJECT.c    2004-04-19 10:08:28.000000000 +0200
7379 @@ -0,0 +1,458 @@
7380 +/*
7381 + * IP6 tables REJECT target module
7382 + * Linux INET6 implementation
7383 + *
7384 + * Copyright (C)2003 USAGI/WIDE Project
7385 + *
7386 + * Authors:
7387 + *     Yasuyuki Kozakai        <yasuyuki.kozakai@toshiba.co.jp>
7388 + *
7389 + * Based on net/ipv4/netfilter/ipt_REJECT.c
7390 + *
7391 + * This program is free software; you can redistribute it and/or
7392 + * modify it under the terms of the GNU General Public License
7393 + * as published by the Free Software Foundation; either version
7394 + * 2 of the License, or (at your option) any later version.
7395 + */
7396 +
7397 +#include <linux/config.h>
7398 +#include <linux/module.h>
7399 +#include <linux/skbuff.h>
7400 +#include <linux/icmpv6.h>
7401 +#include <net/ipv6.h>
7402 +#include <net/tcp.h>
7403 +#include <net/icmp.h>
7404 +#include <net/ip6_fib.h>
7405 +#include <net/ip6_route.h>
7406 +#include <net/flow.h>
7407 +#include <linux/netfilter_ipv6/ip6_tables.h>
7408 +#include <linux/netfilter_ipv6/ip6t_REJECT.h>
7409 +
7410 +MODULE_AUTHOR("Yasuyuki KOZAKAI <yasuyuki.kozakai@toshiba.co.jp>");
7411 +MODULE_DESCRIPTION("IP6 tables REJECT target module");
7412 +MODULE_LICENSE("GPL");
7413 +
7414 +#if 0
7415 +#define DEBUGP printk
7416 +#else
7417 +#define DEBUGP(format, args...)
7418 +#endif
7419 +
7420 +#if 0
7421 +static void connection_attach(struct sk_buff *new_skb, struct nf_ct_info *nfct)
7422 +{
7423 +       void (*attach)(struct sk_buff *, struct nf_ct_info *);
7424 +       if (nfct && (attach = ip6_ct_attach) != NULL) {
7425 +               mb();
7426 +               attach(new_skb, nfct);
7427 +       }
7428 +}
7429 +#endif
7430 +
7431 +static int maybe_reroute(struct sk_buff *skb)
7432 +{
7433 +       if (skb->nfcache & NFC_ALTERED){
7434 +               if (ip6_route_me_harder(skb) != 0){
7435 +                       kfree_skb(skb);
7436 +                       return -EINVAL;
7437 +               }
7438 +       }
7439 +
7440 +       return dst_output(skb);
7441 +}
7442 +
7443 +/* Send RST reply */
7444 +static void send_reset(struct sk_buff *oldskb)
7445 +{
7446 +       struct sk_buff *nskb;
7447 +       struct tcphdr otcph, *tcph;
7448 +       unsigned int otcplen, tcphoff, hh_len;
7449 +       int needs_ack;
7450 +       struct ipv6hdr *oip6h = oldskb->nh.ipv6h, *ip6h;
7451 +       struct dst_entry *dst = NULL;
7452 +       u8 proto;
7453 +       struct flowi fl;
7454 +       proto = oip6h->nexthdr;
7455 +       int err;
7456 +
7457 +       if ((!(ipv6_addr_type(&oip6h->saddr) & IPV6_ADDR_UNICAST)) ||
7458 +           (!(ipv6_addr_type(&oip6h->daddr) & IPV6_ADDR_UNICAST))) {
7459 +               DEBUGP("ip6t_REJECT: addr is not unicast.\n");
7460 +               return;
7461 +       }
7462 +
7463 +       tcphoff = ipv6_skip_exthdr(oldskb, ((u8*)(oip6h+1) - oldskb->data),
7464 +                                  &proto, oldskb->len - ((u8*)(oip6h+1)
7465 +                                                         - oldskb->data));
7466 +
7467 +       if ((tcphoff < 0) || (tcphoff > oldskb->len)) {
7468 +               DEBUGP("ip6t_REJECT: Can't get TCP header.\n");
7469 +               return;
7470 +       }
7471 +
7472 +       otcplen = oldskb->len - tcphoff;
7473 +
7474 +       /* IP header checks: fragment, too short. */
7475 +       if ((proto != IPPROTO_TCP) || (otcplen < sizeof(struct tcphdr))) {
7476 +               DEBUGP("ip6t_REJECT: proto(%d) != IPPROTO_TCP, or too short. otcplen = %d\n",
7477 +                       proto, otcplen);
7478 +               return;
7479 +       }
7480 +
7481 +       if (skb_copy_bits(oldskb, tcphoff, &otcph, sizeof(struct tcphdr))) {
7482 +               if (net_ratelimit())
7483 +                       printk("ip6t_REJECT: Can't copy tcp header\n");
7484 +               return;
7485 +       }
7486 +
7487 +       /* No RST for RST. */
7488 +       if (otcph.rst) {
7489 +               DEBUGP("ip6t_REJECT: RST is set\n");
7490 +               return;
7491 +       }
7492 +
7493 +       /* Check checksum. */
7494 +       if (csum_ipv6_magic(&oip6h->saddr, &oip6h->daddr, otcplen, IPPROTO_TCP,
7495 +                           skb_checksum(oldskb, tcphoff, otcplen, 0))) {
7496 +               DEBUGP("ip6t_REJECT: TCP checksum is invalid\n");
7497 +               return;
7498 +       }
7499 +
7500 +       memset(&fl, 0, sizeof(fl));
7501 +       fl.proto = IPPROTO_TCP;
7502 +       ipv6_addr_copy(&fl.fl6_src, &oip6h->daddr);
7503 +       ipv6_addr_copy(&fl.fl6_dst, &oip6h->saddr);
7504 +       fl.fl_ip_sport = otcph.dest;
7505 +       fl.fl_ip_dport = otcph.source;
7506 +       err = ip6_dst_lookup(NULL, &dst, &fl);
7507 +       if (err) {
7508 +               if (net_ratelimit())
7509 +                       printk("ip6t_REJECT: can't find dst. err = %d\n", err);
7510 +               return;
7511 +       }
7512 +
7513 +       hh_len = (dst->dev->hard_header_len + 15)&~15;
7514 +       nskb = alloc_skb(hh_len + 15 + dst->header_len + sizeof(struct ipv6hdr)
7515 +                        + sizeof(struct tcphdr) + dst->trailer_len,
7516 +                        GFP_ATOMIC);
7517 +
7518 +       if (!nskb) {
7519 +               if (net_ratelimit())
7520 +                       printk("ip6t_REJECT: Can't alloc skb\n");
7521 +               dst_release(dst);
7522 +               return;
7523 +       }
7524 +
7525 +       nskb->dst = dst;
7526 +       dst_hold(dst);
7527 +
7528 +       skb_reserve(nskb, hh_len + dst->header_len);
7529 +
7530 +       ip6h = nskb->nh.ipv6h = (struct ipv6hdr *)
7531 +                                       skb_put(nskb, sizeof(struct ipv6hdr));
7532 +       ip6h->version = 6;
7533 +       ip6h->hop_limit = dst_metric(dst, RTAX_HOPLIMIT);
7534 +       ip6h->nexthdr = IPPROTO_TCP;
7535 +       ip6h->payload_len = htons(sizeof(struct tcphdr));
7536 +       ipv6_addr_copy(&ip6h->saddr, &oip6h->daddr);
7537 +       ipv6_addr_copy(&ip6h->daddr, &oip6h->saddr);
7538 +
7539 +       tcph = (struct tcphdr *)skb_put(nskb, sizeof(struct tcphdr));
7540 +       /* Truncate to length (no data) */
7541 +       tcph->doff = sizeof(struct tcphdr)/4;
7542 +       tcph->source = otcph.dest;
7543 +       tcph->dest = otcph.source;
7544 +
7545 +       if (otcph.ack) {
7546 +               needs_ack = 0;
7547 +               tcph->seq = otcph.ack_seq;
7548 +               tcph->ack_seq = 0;
7549 +       } else {
7550 +               needs_ack = 1;
7551 +               tcph->ack_seq = htonl(ntohl(otcph.seq) + otcph.syn + otcph.fin
7552 +                                     + otcplen - (otcph.doff<<2));
7553 +               tcph->seq = 0;
7554 +       }
7555 +
7556 +       /* Reset flags */
7557 +       ((u_int8_t *)tcph)[13] = 0;
7558 +       tcph->rst = 1;
7559 +       tcph->ack = needs_ack;
7560 +       tcph->window = 0;
7561 +       tcph->urg_ptr = 0;
7562 +       tcph->check = 0;
7563 +
7564 +       /* Adjust TCP checksum */
7565 +       tcph->check = csum_ipv6_magic(&nskb->nh.ipv6h->saddr,
7566 +                                     &nskb->nh.ipv6h->daddr,
7567 +                                     sizeof(struct tcphdr), IPPROTO_TCP,
7568 +                                     csum_partial((char *)tcph,
7569 +                                                  sizeof(struct tcphdr), 0));
7570 +
7571 +#if 0
7572 +       connection_attach(nskb, oldskb->nfct);
7573 +#endif
7574 +
7575 +       NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, nskb, NULL, nskb->dst->dev,
7576 +               maybe_reroute);
7577 +
7578 +       dst_release(dst);
7579 +}
7580 +
7581 +static void send_unreach(struct sk_buff *skb_in, unsigned char code)
7582 +{
7583 +       struct ipv6hdr *ip6h, *hdr = skb_in->nh.ipv6h;
7584 +       struct icmp6hdr *icmp6h;
7585 +       struct dst_entry *dst = NULL;
7586 +       struct rt6_info *rt;
7587 +       int tmo;
7588 +       __u32 csum;
7589 +       unsigned int len, datalen, hh_len;
7590 +       int saddr_type, daddr_type;
7591 +       unsigned int ptr, ip6off;
7592 +       u8 proto;
7593 +       struct flowi fl;
7594 +       struct sk_buff *nskb;
7595 +       char *data;
7596 +
7597 +       saddr_type = ipv6_addr_type(&hdr->saddr);
7598 +       daddr_type = ipv6_addr_type(&hdr->daddr);
7599 +
7600 +       if ((!(saddr_type & IPV6_ADDR_UNICAST)) ||
7601 +           (!(daddr_type & IPV6_ADDR_UNICAST))) {
7602 +               DEBUGP("ip6t_REJECT: addr is not unicast.\n");
7603 +               return;
7604 +       }
7605 +
7606 +       ip6off = skb_in->nh.raw - skb_in->data;
7607 +       proto = hdr->nexthdr;
7608 +       ptr = ipv6_skip_exthdr(skb_in, ip6off + sizeof(struct ipv6hdr), &proto,
7609 +                              skb_in->len - ip6off);
7610 +
7611 +       if ((ptr < 0) || (ptr > skb_in->len)) {
7612 +               ptr = ip6off + sizeof(struct ipv6hdr);
7613 +               proto = hdr->nexthdr;
7614 +       } else if (proto == IPPROTO_ICMPV6) {
7615 +                u8 type;
7616 +
7617 +                if (skb_copy_bits(skb_in, ptr + offsetof(struct icmp6hdr,
7618 +                                                     icmp6_type), &type, 1)) {
7619 +                       DEBUGP("ip6t_REJECT: Can't get ICMPv6 type\n");
7620 +                       return;
7621 +               }
7622 +
7623 +               if (!(type & ICMPV6_INFOMSG_MASK)) {
7624 +                       DEBUGP("ip6t_REJECT: no reply to icmp error\n");
7625 +                       return;
7626 +               }
7627 +        } else if (proto == IPPROTO_UDP) {
7628 +               int plen = skb_in->len - (ptr - ip6off);
7629 +               uint16_t check;
7630 +
7631 +               if (plen < sizeof(struct udphdr)) {
7632 +                       DEBUGP("ip6t_REJECT: too short\n");
7633 +                       return;
7634 +               }
7635 +
7636 +               if (skb_copy_bits(skb_in, ptr + offsetof(struct udphdr, check),
7637 +                                 &check, 2)) {
7638 +                       if (net_ratelimit())
7639 +                               printk("ip6t_REJECT: can't get copy from skb");
7640 +                       return;
7641 +               }
7642 +
7643 +               if (check &&
7644 +                   csum_ipv6_magic(&hdr->saddr, &hdr->daddr, plen,
7645 +                                   IPPROTO_UDP,
7646 +                                   skb_checksum(skb_in, ptr, plen, 0))) {
7647 +                       DEBUGP("ip6t_REJECT: UDP checksum is invalid.\n");
7648 +                       return;
7649 +               }
7650 +       }
7651 +
7652 +       memset(&fl, 0, sizeof(fl));
7653 +       fl.proto = IPPROTO_ICMPV6;
7654 +       ipv6_addr_copy(&fl.fl6_src, &hdr->daddr);
7655 +       ipv6_addr_copy(&fl.fl6_dst, &hdr->saddr);
7656 +       fl.fl_icmp_type = ICMPV6_DEST_UNREACH;
7657 +       fl.fl_icmp_code = code;
7658 +
7659 +       if (ip6_dst_lookup(NULL, &dst, &fl)) {
7660 +               return;
7661 +       }
7662 +
7663 +       rt = (struct rt6_info *)dst;
7664 +       tmo = 1*HZ;
7665 +
7666 +       if (rt->rt6i_dst.plen < 128)
7667 +               tmo >>= ((128 - rt->rt6i_dst.plen)>>5);
7668 +
7669 +       if (!xrlim_allow(dst, tmo)) {
7670 +               if (net_ratelimit())
7671 +                       printk("ip6t_REJECT: rate limitted\n");
7672 +               goto dst_release_out;
7673 +       }
7674 +
7675 +       len = skb_in->len + sizeof(struct ipv6hdr) + sizeof(struct icmp6hdr);
7676 +
7677 +       if (len > dst_pmtu(dst))
7678 +               len = dst_pmtu(dst);
7679 +       if (len > IPV6_MIN_MTU)
7680 +               len = IPV6_MIN_MTU;
7681 +
7682 +       datalen = len - sizeof(struct ipv6hdr) - sizeof(struct icmp6hdr);
7683 +       hh_len = (rt->u.dst.dev->hard_header_len + 15)&~15;
7684 +
7685 +       nskb = alloc_skb(hh_len + 15 + dst->header_len + dst->trailer_len + len,
7686 +                        GFP_ATOMIC);
7687 +
7688 +       if (!nskb) {
7689 +               if (net_ratelimit())
7690 +                       printk("ip6t_REJECT: can't alloc skb\n");
7691 +               goto dst_release_out;
7692 +       }
7693 +
7694 +       nskb->priority = 0;
7695 +       nskb->dst = dst;
7696 +       dst_hold(dst);
7697 +
7698 +       skb_reserve(nskb, hh_len + dst->header_len);
7699 +
7700 +       ip6h = nskb->nh.ipv6h = (struct ipv6hdr *)
7701 +                                       skb_put(nskb, sizeof(struct ipv6hdr));
7702 +       ip6h->version = 6;
7703 +       ip6h->hop_limit = dst_metric(dst, RTAX_HOPLIMIT);
7704 +       ip6h->nexthdr = IPPROTO_ICMPV6;
7705 +       ip6h->payload_len = htons(datalen + sizeof(struct icmp6hdr));
7706 +       ipv6_addr_copy(&ip6h->saddr, &hdr->daddr);
7707 +       ipv6_addr_copy(&ip6h->daddr, &hdr->saddr);
7708 +
7709 +       icmp6h = (struct icmp6hdr *) skb_put(nskb, sizeof(struct icmp6hdr));
7710 +       icmp6h->icmp6_type = ICMPV6_DEST_UNREACH;
7711 +       icmp6h->icmp6_code = code;
7712 +       icmp6h->icmp6_cksum = 0;
7713 +
7714 +       data = skb_put(nskb, datalen);
7715 +
7716 +       csum = csum_partial((unsigned char *)icmp6h, sizeof(struct icmp6hdr), 0);
7717 +       csum = skb_copy_and_csum_bits(skb_in, ip6off, data, datalen, csum);
7718 +       icmp6h->icmp6_cksum = csum_ipv6_magic(&hdr->saddr, &hdr->daddr,
7719 +                                            datalen + sizeof(struct icmp6hdr),
7720 +                                            IPPROTO_ICMPV6, csum);
7721 +
7722 +#if 0
7723 +       connection_attach(nskb, skb_in->nfct);
7724 +#endif
7725 +       NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, nskb, NULL, nskb->dst->dev,
7726 +               maybe_reroute);
7727 +
7728 +dst_release_out:
7729 +       dst_release(dst);
7730 +}
7731 +
7732 +static unsigned int reject6_target(struct sk_buff **pskb,
7733 +                          unsigned int hooknum,
7734 +                          const struct net_device *in,
7735 +                          const struct net_device *out,
7736 +                          const void *targinfo,
7737 +                          void *userinfo)
7738 +{
7739 +       const struct ip6t_reject_info *reject = targinfo;
7740 +
7741 +       DEBUGP(KERN_DEBUG "%s: medium point\n", __FUNCTION__);
7742 +       /* WARNING: This code causes reentry within ip6tables.
7743 +          This means that the ip6tables jump stack is now crap.  We
7744 +          must return an absolute verdict. --RR */
7745 +       switch (reject->with) {
7746 +       case IP6T_ICMP6_NO_ROUTE:
7747 +               send_unreach(*pskb, ICMPV6_NOROUTE);
7748 +               break;
7749 +       case IP6T_ICMP6_ADM_PROHIBITED:
7750 +               send_unreach(*pskb, ICMPV6_ADM_PROHIBITED);
7751 +               break;
7752 +       case IP6T_ICMP6_NOT_NEIGHBOUR:
7753 +               send_unreach(*pskb, ICMPV6_NOT_NEIGHBOUR);
7754 +               break;
7755 +       case IP6T_ICMP6_ADDR_UNREACH:
7756 +               send_unreach(*pskb, ICMPV6_ADDR_UNREACH);
7757 +               break;
7758 +       case IP6T_ICMP6_PORT_UNREACH:
7759 +               send_unreach(*pskb, ICMPV6_PORT_UNREACH);
7760 +               break;
7761 +       case IP6T_ICMP6_ECHOREPLY:
7762 +               /* Do nothing */
7763 +               break;
7764 +       case IP6T_TCP_RESET:
7765 +               send_reset(*pskb);
7766 +               break;
7767 +       default:
7768 +               if (net_ratelimit())
7769 +                       printk(KERN_WARNING "ip6t_REJECT: case %u not handled yet\n", reject->with);
7770 +               break;
7771 +       }
7772 +
7773 +       return NF_DROP;
7774 +}
7775 +
7776 +static int check(const char *tablename,
7777 +                const struct ip6t_entry *e,
7778 +                void *targinfo,
7779 +                unsigned int targinfosize,
7780 +                unsigned int hook_mask)
7781 +{
7782 +       const struct ip6t_reject_info *rejinfo = targinfo;
7783 +
7784 +       if (targinfosize != IP6T_ALIGN(sizeof(struct ip6t_reject_info))) {
7785 +               DEBUGP("ip6t_REJECT: targinfosize %u != 0\n", targinfosize);
7786 +               return 0;
7787 +       }
7788 +
7789 +       /* Only allow these for packet filtering. */
7790 +       if (strcmp(tablename, "filter") != 0) {
7791 +               DEBUGP("ip6t_REJECT: bad table `%s'.\n", tablename);
7792 +               return 0;
7793 +       }
7794 +
7795 +       if ((hook_mask & ~((1 << NF_IP6_LOCAL_IN)
7796 +                          | (1 << NF_IP6_FORWARD)
7797 +                          | (1 << NF_IP6_LOCAL_OUT))) != 0) {
7798 +               DEBUGP("ip6t_REJECT: bad hook mask %X\n", hook_mask);
7799 +               return 0;
7800 +       }
7801 +
7802 +       if (rejinfo->with == IP6T_ICMP6_ECHOREPLY) {
7803 +               printk("ip6t_REJECT: ECHOREPLY is not supported.\n");
7804 +               return 0;
7805 +       } else if (rejinfo->with == IP6T_TCP_RESET) {
7806 +               /* Must specify that it's a TCP packet */
7807 +               if (e->ipv6.proto != IPPROTO_TCP
7808 +                   || (e->ipv6.invflags & IP6T_INV_PROTO)) {
7809 +                       DEBUGP("ip6t_REJECT: TCP_RESET illegal for non-tcp\n");
7810 +                       return 0;
7811 +               }
7812 +       }
7813 +
7814 +       return 1;
7815 +}
7816 +
7817 +static struct ip6t_target ip6t_reject_reg = {
7818 +       .name           = "REJECT",
7819 +       .target         = reject6_target,
7820 +       .checkentry     = check,
7821 +       .me             = THIS_MODULE
7822 +};
7823 +
7824 +static int __init init(void)
7825 +{
7826 +       if (ip6t_register_target(&ip6t_reject_reg))
7827 +               return -EINVAL;
7828 +       return 0;
7829 +}
7830 +
7831 +static void __exit fini(void)
7832 +{
7833 +       ip6t_unregister_target(&ip6t_reject_reg);
7834 +}
7835 +
7836 +module_init(init);
7837 +module_exit(fini);
7838 diff -Nur linux-2.6.6-rc1.org/net/ipv6/netfilter/ip6t_fuzzy.c linux-2.6.6-rc1/net/ipv6/netfilter/ip6t_fuzzy.c
7839 --- linux-2.6.6-rc1.org/net/ipv6/netfilter/ip6t_fuzzy.c 1970-01-01 01:00:00.000000000 +0100
7840 +++ linux-2.6.6-rc1/net/ipv6/netfilter/ip6t_fuzzy.c     2004-04-19 10:08:31.000000000 +0200
7841 @@ -0,0 +1,189 @@
7842 +/*
7843 + * This module implements a simple TSK FLC
7844 + * (Takagi-Sugeno-Kang Fuzzy Logic Controller) that aims
7845 + * to limit , in an adaptive and flexible way , the packet rate crossing
7846 + * a given stream . It serves as an initial and very simple (but effective)
7847 + * example of how Fuzzy Logic techniques can be applied to defeat DoS attacks.
7848 + *  As a matter of fact , Fuzzy Logic can help us to insert any "behavior"
7849 + * into our code in a precise , adaptive and efficient manner.
7850 + *  The goal is very similar to that of "limit" match , but using techniques of
7851 + * Fuzzy Control , that allow us to shape the transfer functions precisely ,
7852 + * avoiding over and undershoots - and stuff like that .
7853 + *
7854 + *
7855 + * 2002-08-10  Hime Aguiar e Oliveira Jr. <hime@engineer.com> : Initial version.
7856 + * 2002-08-17  : Changed to eliminate floating point operations .
7857 + * 2002-08-23  : Coding style changes .
7858 + * 2003-04-08  Maciej Soltysiak <solt@dns.toxicilms.tv> : IPv6 Port
7859 + */
7860 +
7861 +#include <linux/module.h>
7862 +#include <linux/skbuff.h>
7863 +#include <linux/ipv6.h>
7864 +#include <linux/random.h>
7865 +#include <net/tcp.h>
7866 +#include <linux/spinlock.h>
7867 +#include <linux/netfilter_ipv6/ip6_tables.h>
7868 +#include <linux/netfilter_ipv6/ip6t_fuzzy.h>
7869 +
7870 +/*
7871 + Packet Acceptance Rate - LOW and Packet Acceptance Rate - HIGH
7872 + Expressed in percentage
7873 +*/
7874 +
7875 +#define PAR_LOW                1/100
7876 +#define PAR_HIGH       1
7877 +
7878 +static spinlock_t fuzzy_lock = SPIN_LOCK_UNLOCKED;
7879 +
7880 +MODULE_AUTHOR("Hime Aguiar e Oliveira Junior <hime@engineer.com>");
7881 +MODULE_DESCRIPTION("IP tables Fuzzy Logic Controller match module");
7882 +MODULE_LICENSE("GPL");
7883 +
7884 +static  u_int8_t mf_high(u_int32_t tx,u_int32_t mini,u_int32_t maxi)
7885 +{
7886 +       if (tx >= maxi) return 100;
7887 +
7888 +       if (tx <= mini) return 0;
7889 +
7890 +       return ((100 * (tx-mini)) / (maxi-mini));
7891 +}
7892 +
7893 +static u_int8_t mf_low(u_int32_t tx,u_int32_t mini,u_int32_t maxi)
7894 +{
7895 +       if (tx <= mini) return 100;
7896 +
7897 +       if (tx >= maxi) return 0;
7898 +
7899 +       return ((100 * (maxi - tx)) / (maxi - mini));
7900 +
7901 +}
7902 +
7903 +static int
7904 +ip6t_fuzzy_match(const struct sk_buff *pskb,
7905 +              const struct net_device *in,
7906 +              const struct net_device *out,
7907 +              const void *matchinfo,
7908 +              int offset,
7909 +              const void *hdr,
7910 +              u_int16_t datalen,
7911 +              int *hotdrop)
7912 +{
7913 +       /* From userspace */
7914 +
7915 +       struct ip6t_fuzzy_info *info = (struct ip6t_fuzzy_info *) matchinfo;
7916 +
7917 +       u_int8_t random_number;
7918 +       unsigned long amount;
7919 +       u_int8_t howhigh, howlow;
7920 +
7921 +
7922 +       spin_lock_bh(&fuzzy_lock); /* Rise the lock */
7923 +
7924 +       info->bytes_total += pskb->len;
7925 +       info->packets_total++;
7926 +
7927 +       info->present_time = jiffies;
7928 +
7929 +       if (info->present_time >= info->previous_time)
7930 +               amount = info->present_time - info->previous_time;
7931 +       else {
7932 +               /* There was a transition : I choose to re-sample
7933 +                  and keep the old acceptance rate...
7934 +               */
7935 +
7936 +               amount = 0;
7937 +               info->previous_time = info->present_time;
7938 +               info->bytes_total = info->packets_total = 0;
7939 +            };
7940 +
7941 +       if ( amount > HZ/10) {/* More than 100 ms elapsed ... */
7942 +
7943 +               info->mean_rate = (u_int32_t) ((HZ * info->packets_total) \
7944 +                                       / amount);
7945 +
7946 +               info->previous_time = info->present_time;
7947 +               info->bytes_total = info->packets_total = 0;
7948 +
7949 +               howhigh = mf_high(info->mean_rate,info->minimum_rate,info->maximum_rate);
7950 +               howlow  = mf_low(info->mean_rate,info->minimum_rate,info->maximum_rate);
7951 +
7952 +               info->acceptance_rate = (u_int8_t) \
7953 +                               (howhigh * PAR_LOW + PAR_HIGH * howlow);
7954 +
7955 +       /* In fact, the above defuzzification would require a denominator
7956 +        * proportional to (howhigh+howlow) but, in this particular case,
7957 +        * that expression is constant.
7958 +        * An imediate consequence is that it is not necessary to call
7959 +        * both mf_high and mf_low - but to keep things understandable,
7960 +        * I did so.
7961 +        */
7962 +
7963 +       }
7964 +
7965 +       spin_unlock_bh(&fuzzy_lock); /* Release the lock */
7966 +
7967 +
7968 +       if (info->acceptance_rate < 100)
7969 +       {
7970 +               get_random_bytes((void *)(&random_number), 1);
7971 +
7972 +               /*  If within the acceptance , it can pass => don't match */
7973 +               if (random_number <= (255 * info->acceptance_rate) / 100)
7974 +                       return 0;
7975 +               else
7976 +                       return 1; /* It can't pass (It matches) */
7977 +       };
7978 +
7979 +       return 0; /* acceptance_rate == 100 % => Everything passes ... */
7980 +
7981 +}
7982 +
7983 +static int
7984 +ip6t_fuzzy_checkentry(const char *tablename,
7985 +                  const struct ip6t_ip6 *ip,
7986 +                  void *matchinfo,
7987 +                  unsigned int matchsize,
7988 +                  unsigned int hook_mask)
7989 +{
7990 +
7991 +       const struct ip6t_fuzzy_info *info = matchinfo;
7992 +
7993 +       if (matchsize != IP6T_ALIGN(sizeof(struct ip6t_fuzzy_info))) {
7994 +               printk("ip6t_fuzzy: matchsize %u != %u\n", matchsize,
7995 +                      IP6T_ALIGN(sizeof(struct ip6t_fuzzy_info)));
7996 +               return 0;
7997 +       }
7998 +
7999 +       if ((info->minimum_rate < MINFUZZYRATE) || (info->maximum_rate > MAXFUZZYRATE)
8000 +        || (info->minimum_rate >= info->maximum_rate)) {
8001 +               printk("ip6t_fuzzy: BAD limits , please verify !!!\n");
8002 +               return 0;
8003 +       }
8004 +
8005 +       return 1;
8006 +}
8007 +
8008 +static struct ip6t_match ip6t_fuzzy_reg = {
8009 +       {NULL, NULL},
8010 +       "fuzzy",
8011 +       ip6t_fuzzy_match,
8012 +       ip6t_fuzzy_checkentry,
8013 +       NULL,
8014 +       THIS_MODULE };
8015 +
8016 +static int __init init(void)
8017 +{
8018 +       if (ip6t_register_match(&ip6t_fuzzy_reg))
8019 +               return -EINVAL;
8020 +
8021 +       return 0;
8022 +}
8023 +
8024 +static void __exit fini(void)
8025 +{
8026 +       ip6t_unregister_match(&ip6t_fuzzy_reg);
8027 +}
8028 +
8029 +module_init(init);
8030 +module_exit(fini);
8031 diff -Nur linux-2.6.6-rc1.org/net/ipv6/netfilter/ip6t_nth.c linux-2.6.6-rc1/net/ipv6/netfilter/ip6t_nth.c
8032 --- linux-2.6.6-rc1.org/net/ipv6/netfilter/ip6t_nth.c   1970-01-01 01:00:00.000000000 +0100
8033 +++ linux-2.6.6-rc1/net/ipv6/netfilter/ip6t_nth.c       2004-04-19 10:08:34.000000000 +0200
8034 @@ -0,0 +1,173 @@
8035 +/*
8036 +  This is a module which is used for match support for every Nth packet
8037 +  This file is distributed under the terms of the GNU General Public
8038 +  License (GPL). Copies of the GPL can be obtained from:
8039 +     ftp://prep.ai.mit.edu/pub/gnu/GPL
8040 +
8041 +  2001-07-18 Fabrice MARIE <fabrice@netfilter.org> : initial implementation.
8042 +  2001-09-20 Richard Wagner (rwagner@cloudnet.com)
8043 +        * added support for multiple counters
8044 +        * added support for matching on individual packets
8045 +          in the counter cycle
8046 +  2003-04-30 Maciej Soltysiak <solt@dns.toxicfilms.tv> : IPv6 Port
8047 +
8048 +*/
8049 +
8050 +#include <linux/module.h>
8051 +#include <linux/skbuff.h>
8052 +#include <linux/ip.h>
8053 +#include <net/tcp.h>
8054 +#include <linux/spinlock.h>
8055 +#include <linux/netfilter_ipv6/ip6_tables.h>
8056 +#include <linux/netfilter_ipv6/ip6t_nth.h>
8057 +
8058 +MODULE_LICENSE("GPL");
8059 +
8060 +/*
8061 + * State information.
8062 + */
8063 +struct state {
8064 +       spinlock_t lock;
8065 +       u_int16_t number;
8066 +};
8067 +
8068 +static struct state states[IP6T_NTH_NUM_COUNTERS];
8069 +
8070 +static int
8071 +ip6t_nth_match(const struct sk_buff *pskb,
8072 +             const struct net_device *in,
8073 +             const struct net_device *out,
8074 +             const void *matchinfo,
8075 +             int offset,
8076 +             const void *hdr,
8077 +             u_int16_t datalen,
8078 +             int *hotdrop)
8079 +{
8080 +       /* Parameters from userspace */
8081 +       const struct ip6t_nth_info *info = matchinfo;
8082 +        unsigned counter = info->counter;
8083 +               if((counter < 0) || (counter >= IP6T_NTH_NUM_COUNTERS)) 
8084 +       {
8085 +                       printk(KERN_WARNING "nth: invalid counter %u. counter between 0 and %u\n", counter, IP6T_NTH_NUM_COUNTERS-1);
8086 +               return 0;
8087 +        };
8088 +
8089 +        spin_lock(&states[counter].lock);
8090 +
8091 +        /* Are we matching every nth packet?*/
8092 +        if (info->packet == 0xFF)
8093 +        {
8094 +               /* We're matching every nth packet and only every nth packet*/
8095 +               /* Do we match or invert match? */
8096 +               if (info->not == 0)
8097 +               {
8098 +                       if (states[counter].number == 0)
8099 +                       {
8100 +                               ++states[counter].number;
8101 +                               goto match;
8102 +                       }
8103 +                       if (states[counter].number >= info->every)
8104 +                               states[counter].number = 0; /* reset the counter */
8105 +                       else
8106 +                               ++states[counter].number;
8107 +                       goto dontmatch;
8108 +               }
8109 +               else
8110 +               {
8111 +                       if (states[counter].number == 0)
8112 +                       {
8113 +                               ++states[counter].number;
8114 +                               goto dontmatch;
8115 +                       }
8116 +                       if (states[counter].number >= info->every)
8117 +                               states[counter].number = 0;
8118 +                       else
8119 +                               ++states[counter].number;
8120 +                       goto match;
8121 +               }
8122 +        }
8123 +        else
8124 +        {
8125 +               /* We're using the --packet, so there must be a rule for every value */
8126 +               if (states[counter].number == info->packet)
8127 +               {
8128 +                       /* only increment the counter when a match happens */
8129 +                       if (states[counter].number >= info->every)
8130 +                               states[counter].number = 0; /* reset the counter */
8131 +                       else
8132 +                               ++states[counter].number;
8133 +                       goto match;
8134 +               }
8135 +               else
8136 +                       goto dontmatch;
8137 +       }
8138 +
8139 + dontmatch:
8140 +       /* don't match */
8141 +       spin_unlock(&states[counter].lock);
8142 +       return 0;
8143 +
8144 + match:
8145 +       spin_unlock(&states[counter].lock);
8146 +       return 1;
8147 +}
8148 +
8149 +static int
8150 +ip6t_nth_checkentry(const char *tablename,
8151 +                  const struct ip6t_ip6 *e,
8152 +                  void *matchinfo,
8153 +                  unsigned int matchsize,
8154 +                  unsigned int hook_mask)
8155 +{
8156 +       /* Parameters from userspace */
8157 +       const struct ip6t_nth_info *info = matchinfo;
8158 +        unsigned counter = info->counter;
8159 +        if((counter < 0) || (counter >= IP6T_NTH_NUM_COUNTERS)) 
8160 +       {
8161 +               printk(KERN_WARNING "nth: invalid counter %u. counter between 0 and %u\n", counter, IP6T_NTH_NUM_COUNTERS-1);
8162 +                       return 0;
8163 +               };
8164 +
8165 +       if (matchsize != IP6T_ALIGN(sizeof(struct ip6t_nth_info))) {
8166 +               printk("nth: matchsize %u != %u\n", matchsize,
8167 +                      IP6T_ALIGN(sizeof(struct ip6t_nth_info)));
8168 +               return 0;
8169 +       }
8170 +
8171 +       states[counter].number = info->startat;
8172 +
8173 +       return 1;
8174 +}
8175 +
8176 +static struct ip6t_match ip6t_nth_reg = { 
8177 +       {NULL, NULL},
8178 +       "nth",
8179 +       ip6t_nth_match,
8180 +       ip6t_nth_checkentry,
8181 +       NULL,
8182 +       THIS_MODULE };
8183 +
8184 +static int __init init(void)
8185 +{
8186 +       unsigned counter;
8187 +        memset(&states, 0, sizeof(states));
8188 +       if (ip6t_register_match(&ip6t_nth_reg))
8189 +               return -EINVAL;
8190 +
8191 +        for(counter = 0; counter < IP6T_NTH_NUM_COUNTERS; counter++) 
8192 +       {
8193 +               spin_lock_init(&(states[counter].lock));
8194 +        };
8195 +
8196 +       printk("ip6t_nth match loaded\n");
8197 +       return 0;
8198 +}
8199 +
8200 +static void __exit fini(void)
8201 +{
8202 +       ip6t_unregister_match(&ip6t_nth_reg);
8203 +       printk("ip6t_nth match unloaded\n");
8204 +}
8205 +
8206 +module_init(init);
8207 +module_exit(fini);
8208 diff -Nur linux-2.6.6-rc1.org/net/ipv6/netfilter/ip6t_random.c linux-2.6.6-rc1/net/ipv6/netfilter/ip6t_random.c
8209 --- linux-2.6.6-rc1.org/net/ipv6/netfilter/ip6t_random.c        1970-01-01 01:00:00.000000000 +0100
8210 +++ linux-2.6.6-rc1/net/ipv6/netfilter/ip6t_random.c    2004-04-19 10:08:38.000000000 +0200
8211 @@ -0,0 +1,97 @@
8212 +/*
8213 +  This is a module which is used for a "random" match support.
8214 +  This file is distributed under the terms of the GNU General Public
8215 +  License (GPL). Copies of the GPL can be obtained from:
8216 +     ftp://prep.ai.mit.edu/pub/gnu/GPL
8217 +
8218 +  2001-10-14 Fabrice MARIE <fabrice@netfilter.org> : initial implementation.
8219 +  2003-04-30 Maciej Soltysiak <solt@dns.toxicfilms.tv> : IPv6 Port
8220 +*/
8221 +
8222 +#include <linux/module.h>
8223 +#include <linux/skbuff.h>
8224 +#include <linux/ip.h>
8225 +#include <linux/random.h>
8226 +#include <net/tcp.h>
8227 +#include <linux/spinlock.h>
8228 +#include <linux/netfilter_ipv6/ip6_tables.h>
8229 +#include <linux/netfilter_ipv6/ip6t_random.h>
8230 +
8231 +MODULE_LICENSE("GPL");
8232 +
8233 +static int
8234 +ip6t_rand_match(const struct sk_buff *pskb,
8235 +              const struct net_device *in,
8236 +              const struct net_device *out,
8237 +              const void *matchinfo,
8238 +              int offset,
8239 +              const void *hdr,
8240 +              u_int16_t datalen,
8241 +              int *hotdrop)
8242 +{
8243 +       /* Parameters from userspace */
8244 +       const struct ip6t_rand_info *info = matchinfo;
8245 +       u_int8_t random_number;
8246 +
8247 +       /* get 1 random number from the kernel random number generation routine */
8248 +       get_random_bytes((void *)(&random_number), 1);
8249 +
8250 +       /* Do we match ? */
8251 +       if (random_number <= info->average)
8252 +               return 1;
8253 +       else
8254 +               return 0;
8255 +}
8256 +
8257 +static int
8258 +ip6t_rand_checkentry(const char *tablename,
8259 +                  const struct ip6t_ip6 *e,
8260 +                  void *matchinfo,
8261 +                  unsigned int matchsize,
8262 +                  unsigned int hook_mask)
8263 +{
8264 +       /* Parameters from userspace */
8265 +       const struct ip6t_rand_info *info = matchinfo;
8266 +
8267 +       if (matchsize != IP6T_ALIGN(sizeof(struct ip6t_rand_info))) {
8268 +               printk("ip6t_random: matchsize %u != %u\n", matchsize,
8269 +                      IP6T_ALIGN(sizeof(struct ip6t_rand_info)));
8270 +               return 0;
8271 +       }
8272 +
8273 +       /* must be  1 <= average % <= 99 */
8274 +       /* 1  x 2.55 = 2   */
8275 +       /* 99 x 2.55 = 252 */
8276 +       if ((info->average < 2) || (info->average > 252)) {
8277 +               printk("ip6t_random:  invalid average %u\n", info->average);
8278 +               return 0;
8279 +       }
8280 +
8281 +       return 1;
8282 +}
8283 +
8284 +static struct ip6t_match ip6t_rand_reg = { 
8285 +       {NULL, NULL},
8286 +       "random",
8287 +       ip6t_rand_match,
8288 +       ip6t_rand_checkentry,
8289 +       NULL,
8290 +       THIS_MODULE };
8291 +
8292 +static int __init init(void)
8293 +{
8294 +       if (ip6t_register_match(&ip6t_rand_reg))
8295 +               return -EINVAL;
8296 +
8297 +       printk("ip6t_random match loaded\n");
8298 +       return 0;
8299 +}
8300 +
8301 +static void __exit fini(void)
8302 +{
8303 +       ip6t_unregister_match(&ip6t_rand_reg);
8304 +       printk("ip6t_random match unloaded\n");
8305 +}
8306 +
8307 +module_init(init);
8308 +module_exit(fini);
8309 diff -Nur linux-2.6.6-rc1.org/net/ipv6/sit.c linux-2.6.6-rc1/net/ipv6/sit.c
8310 --- linux-2.6.6-rc1.org/net/ipv6/sit.c  2004-04-15 03:35:37.000000000 +0200
8311 +++ linux-2.6.6-rc1/net/ipv6/sit.c      2004-04-19 10:08:24.000000000 +0200
8312 @@ -388,13 +388,7 @@
8313                 skb->dev = tunnel->dev;
8314                 dst_release(skb->dst);
8315                 skb->dst = NULL;
8316 -#ifdef CONFIG_NETFILTER
8317 -               nf_conntrack_put(skb->nfct);
8318 -               skb->nfct = NULL;
8319 -#ifdef CONFIG_NETFILTER_DEBUG
8320 -               skb->nf_debug = 0;
8321 -#endif
8322 -#endif
8323 +               nf_reset(skb);
8324                 ipip6_ecn_decapsulate(iph, skb);
8325                 netif_rx(skb);
8326                 read_unlock(&ipip6_lock);
8327 @@ -580,13 +574,7 @@
8328         if ((iph->ttl = tiph->ttl) == 0)
8329                 iph->ttl        =       iph6->hop_limit;
8330  
8331 -#ifdef CONFIG_NETFILTER
8332 -       nf_conntrack_put(skb->nfct);
8333 -       skb->nfct = NULL;
8334 -#ifdef CONFIG_NETFILTER_DEBUG
8335 -       skb->nf_debug = 0;
8336 -#endif
8337 -#endif
8338 +       nf_reset(skb);
8339  
8340         IPTUNNEL_XMIT();
8341         tunnel->recursion--;
This page took 0.680976 seconds and 3 git commands to generate.