]> git.pld-linux.org Git - packages/kernel.git/blob - 2.6.x-patch-o-matic-ng-base-20040305.patch
- CSZ scheduler removed from kernel tree.
[packages/kernel.git] / 2.6.x-patch-o-matic-ng-base-20040305.patch
1 diff -Nur linux-2.6.4-rc2.org/include/linux/netfilter.h linux-2.6.4-rc2/include/linux/netfilter.h
2 --- linux-2.6.4-rc2.org/include/linux/netfilter.h       2004-03-04 06:16:47.000000000 +0000
3 +++ linux-2.6.4-rc2/include/linux/netfilter.h   2004-03-05 09:55:08.000000000 +0000
4 @@ -99,6 +99,24 @@
5  
6  extern struct list_head nf_hooks[NPROTO][NF_MAX_HOOKS];
7  
8 +typedef void nf_logfn(unsigned int hooknum,
9 +                     const struct sk_buff *skb,
10 +                     const struct net_device *in,
11 +                     const struct net_device *out,
12 +                     const char *prefix);
13 +
14 +/* Function to register/unregister log function. */
15 +int nf_log_register(int pf, nf_logfn *logfn);
16 +void nf_log_unregister(int pf, nf_logfn *logfn);
17 +
18 +/* Calls the registered backend logging function */
19 +void nf_log_packet(int pf,
20 +                  unsigned int hooknum,
21 +                  const struct sk_buff *skb,
22 +                  const struct net_device *in,
23 +                  const struct net_device *out,
24 +                  const char *fmt, ...);
25 +                   
26  /* Activate hook; either okfn or kfree_skb called, unless a hook
27     returns NF_STOLEN (in which case, it's up to the hook to deal with
28     the consequences).
29 diff -Nur linux-2.6.4-rc2.org/include/linux/netfilter_ipv4/ip_conntrack.h linux-2.6.4-rc2/include/linux/netfilter_ipv4/ip_conntrack.h
30 --- linux-2.6.4-rc2.org/include/linux/netfilter_ipv4/ip_conntrack.h     2004-03-04 06:17:04.000000000 +0000
31 +++ linux-2.6.4-rc2/include/linux/netfilter_ipv4/ip_conntrack.h 2004-03-05 09:55:23.000000000 +0000
32 @@ -251,6 +251,9 @@
33  /* Call me when a conntrack is destroyed. */
34  extern void (*ip_conntrack_destroyed)(struct ip_conntrack *conntrack);
35  
36 +/* Fake conntrack entry for untracked connections */
37 +extern struct ip_conntrack ip_conntrack_untracked;
38 +
39  /* Returns new sk_buff, or NULL */
40  struct sk_buff *
41  ip_ct_gather_frags(struct sk_buff *skb);
42 diff -Nur linux-2.6.4-rc2.org/include/linux/netfilter_ipv4/ipt_TTL.h linux-2.6.4-rc2/include/linux/netfilter_ipv4/ipt_TTL.h
43 --- linux-2.6.4-rc2.org/include/linux/netfilter_ipv4/ipt_TTL.h  1970-01-01 00:00:00.000000000 +0000
44 +++ linux-2.6.4-rc2/include/linux/netfilter_ipv4/ipt_TTL.h      2004-03-05 09:55:14.000000000 +0000
45 @@ -0,0 +1,21 @@
46 +/* TTL modification module for IP tables
47 + * (C) 2000 by Harald Welte <laforge@gnumonks.org> */
48 +
49 +#ifndef _IPT_TTL_H
50 +#define _IPT_TTL_H
51 +
52 +enum {
53 +       IPT_TTL_SET = 0,
54 +       IPT_TTL_INC,
55 +       IPT_TTL_DEC
56 +};
57 +
58 +#define IPT_TTL_MAXMODE        IPT_TTL_DEC
59 +
60 +struct ipt_TTL_info {
61 +       u_int8_t        mode;
62 +       u_int8_t        ttl;
63 +};
64 +
65 +
66 +#endif
67 diff -Nur linux-2.6.4-rc2.org/include/linux/netfilter_ipv4/ipt_ULOG.h linux-2.6.4-rc2/include/linux/netfilter_ipv4/ipt_ULOG.h
68 --- linux-2.6.4-rc2.org/include/linux/netfilter_ipv4/ipt_ULOG.h 2004-03-04 06:16:43.000000000 +0000
69 +++ linux-2.6.4-rc2/include/linux/netfilter_ipv4/ipt_ULOG.h     2004-03-05 09:55:08.000000000 +0000
70 @@ -11,6 +11,9 @@
71  #define NETLINK_NFLOG  5
72  #endif
73  
74 +#define ULOG_DEFAULT_NLGROUP   1
75 +#define ULOG_DEFAULT_QTHRESHOLD        1
76 +
77  #define ULOG_MAC_LEN   80
78  #define ULOG_PREFIX_LEN        32
79  
80 diff -Nur linux-2.6.4-rc2.org/include/linux/netfilter_ipv4/ipt_connlimit.h linux-2.6.4-rc2/include/linux/netfilter_ipv4/ipt_connlimit.h
81 --- linux-2.6.4-rc2.org/include/linux/netfilter_ipv4/ipt_connlimit.h    1970-01-01 00:00:00.000000000 +0000
82 +++ linux-2.6.4-rc2/include/linux/netfilter_ipv4/ipt_connlimit.h        2004-03-05 09:55:15.000000000 +0000
83 @@ -0,0 +1,12 @@
84 +#ifndef _IPT_CONNLIMIT_H
85 +#define _IPT_CONNLIMIT_H
86 +
87 +struct ipt_connlimit_data;
88 +
89 +struct ipt_connlimit_info {
90 +       int limit;
91 +       int inverse;
92 +       u_int32_t mask;
93 +       struct ipt_connlimit_data *data;
94 +};
95 +#endif /* _IPT_CONNLIMIT_H */
96 diff -Nur linux-2.6.4-rc2.org/include/linux/netfilter_ipv4/ipt_conntrack.h linux-2.6.4-rc2/include/linux/netfilter_ipv4/ipt_conntrack.h
97 --- linux-2.6.4-rc2.org/include/linux/netfilter_ipv4/ipt_conntrack.h    2004-03-04 06:16:55.000000000 +0000
98 +++ linux-2.6.4-rc2/include/linux/netfilter_ipv4/ipt_conntrack.h        2004-03-05 09:55:23.000000000 +0000
99 @@ -10,6 +10,7 @@
100  
101  #define IPT_CONNTRACK_STATE_SNAT (1 << (IP_CT_NUMBER + 1))
102  #define IPT_CONNTRACK_STATE_DNAT (1 << (IP_CT_NUMBER + 2))
103 +#define IPT_CONNTRACK_STATE_UNTRACKED (1 << (IP_CT_NUMBER + 3))
104  
105  /* flags, invflags: */
106  #define IPT_CONNTRACK_STATE    0x01
107 diff -Nur linux-2.6.4-rc2.org/include/linux/netfilter_ipv4/ipt_dstlimit.h linux-2.6.4-rc2/include/linux/netfilter_ipv4/ipt_dstlimit.h
108 --- linux-2.6.4-rc2.org/include/linux/netfilter_ipv4/ipt_dstlimit.h     1970-01-01 00:00:00.000000000 +0000
109 +++ linux-2.6.4-rc2/include/linux/netfilter_ipv4/ipt_dstlimit.h 2004-03-05 09:55:17.000000000 +0000
110 @@ -0,0 +1,39 @@
111 +#ifndef _IPT_DSTLIMIT_H
112 +#define _IPT_DSTLIMIT_H
113 +
114 +/* timings are in milliseconds. */
115 +#define IPT_DSTLIMIT_SCALE 10000
116 +/* 1/10,000 sec period => max of 10,000/sec.  Min rate is then 429490
117 +   seconds, or one every 59 hours. */
118 +
119 +/* details of this structure hidden by the implementation */
120 +struct ipt_dstlimit_htable;
121 +
122 +#define IPT_DSTLIMIT_HASH_DIP  0x0001
123 +#define IPT_DSTLIMIT_HASH_DPT  0x0002
124 +#define IPT_DSTLIMIT_HASH_SIP  0x0004
125 +
126 +struct dstlimit_cfg {
127 +       u_int32_t mode;   /* bitmask of IPT_DSTLIMIT_HASH_* */
128 +       u_int32_t avg;    /* Average secs between packets * scale */
129 +       u_int32_t burst;  /* Period multiplier for upper limit. */
130 +
131 +       /* user specified */
132 +       u_int32_t size;         /* how many buckets */
133 +       u_int32_t max;          /* max number of entries */
134 +       u_int32_t gc_interval;  /* gc interval */
135 +       u_int32_t expire;       /* when do entries expire? */
136 +};
137 +
138 +struct ipt_dstlimit_info {
139 +       char name [IFNAMSIZ];           /* name */
140 +       struct dstlimit_cfg cfg;
141 +       struct ipt_dstlimit_htable *hinfo;
142 +
143 +       /* Used internally by the kernel */
144 +       union {
145 +               void *ptr;
146 +               struct ipt_dstlimit_info *master;
147 +       } u;
148 +};
149 +#endif /*_IPT_DSTLIMIT_H*/
150 diff -Nur linux-2.6.4-rc2.org/include/linux/netfilter_ipv4/ipt_fuzzy.h linux-2.6.4-rc2/include/linux/netfilter_ipv4/ipt_fuzzy.h
151 --- linux-2.6.4-rc2.org/include/linux/netfilter_ipv4/ipt_fuzzy.h        1970-01-01 00:00:00.000000000 +0000
152 +++ linux-2.6.4-rc2/include/linux/netfilter_ipv4/ipt_fuzzy.h    2004-03-05 09:55:18.000000000 +0000
153 @@ -0,0 +1,21 @@
154 +#ifndef _IPT_FUZZY_H
155 +#define _IPT_FUZZY_H
156 +
157 +#include <linux/param.h>
158 +#include <linux/types.h>
159 +
160 +#define MAXFUZZYRATE 10000000
161 +#define MINFUZZYRATE 3
162 +
163 +struct ipt_fuzzy_info {
164 +       u_int32_t minimum_rate;
165 +       u_int32_t maximum_rate;
166 +       u_int32_t packets_total;
167 +       u_int32_t bytes_total;
168 +       u_int32_t previous_time;
169 +       u_int32_t present_time;
170 +       u_int32_t mean_rate;
171 +       u_int8_t acceptance_rate;
172 +};
173 +
174 +#endif /*_IPT_FUZZY_H*/
175 diff -Nur linux-2.6.4-rc2.org/include/linux/netfilter_ipv4/ipt_ipv4options.h linux-2.6.4-rc2/include/linux/netfilter_ipv4/ipt_ipv4options.h
176 --- linux-2.6.4-rc2.org/include/linux/netfilter_ipv4/ipt_ipv4options.h  1970-01-01 00:00:00.000000000 +0000
177 +++ linux-2.6.4-rc2/include/linux/netfilter_ipv4/ipt_ipv4options.h      2004-03-05 09:55:19.000000000 +0000
178 @@ -0,0 +1,21 @@
179 +#ifndef __ipt_ipv4options_h_included__
180 +#define __ipt_ipv4options_h_included__
181 +
182 +#define IPT_IPV4OPTION_MATCH_SSRR              0x01  /* For strict source routing */
183 +#define IPT_IPV4OPTION_MATCH_LSRR              0x02  /* For loose source routing */
184 +#define IPT_IPV4OPTION_DONT_MATCH_SRR          0x04  /* any source routing */
185 +#define IPT_IPV4OPTION_MATCH_RR                        0x08  /* For Record route */
186 +#define IPT_IPV4OPTION_DONT_MATCH_RR           0x10
187 +#define IPT_IPV4OPTION_MATCH_TIMESTAMP         0x20  /* For timestamp request */
188 +#define IPT_IPV4OPTION_DONT_MATCH_TIMESTAMP    0x40
189 +#define IPT_IPV4OPTION_MATCH_ROUTER_ALERT      0x80  /* For router-alert */
190 +#define IPT_IPV4OPTION_DONT_MATCH_ROUTER_ALERT 0x100
191 +#define IPT_IPV4OPTION_MATCH_ANY_OPT           0x200 /* match packet with any option */
192 +#define IPT_IPV4OPTION_DONT_MATCH_ANY_OPT      0x400 /* match packet with no option */
193 +
194 +struct ipt_ipv4options_info {
195 +       u_int16_t options;
196 +};
197 +
198 +
199 +#endif /* __ipt_ipv4options_h_included__ */
200 diff -Nur linux-2.6.4-rc2.org/include/linux/netfilter_ipv4/ipt_mport.h linux-2.6.4-rc2/include/linux/netfilter_ipv4/ipt_mport.h
201 --- linux-2.6.4-rc2.org/include/linux/netfilter_ipv4/ipt_mport.h        1970-01-01 00:00:00.000000000 +0000
202 +++ linux-2.6.4-rc2/include/linux/netfilter_ipv4/ipt_mport.h    2004-03-05 09:55:20.000000000 +0000
203 @@ -0,0 +1,24 @@
204 +#ifndef _IPT_MPORT_H
205 +#define _IPT_MPORT_H
206 +#include <linux/netfilter_ipv4/ip_tables.h>
207 +
208 +#define IPT_MPORT_SOURCE (1<<0)
209 +#define IPT_MPORT_DESTINATION (1<<1)
210 +#define IPT_MPORT_EITHER (IPT_MPORT_SOURCE|IPT_MPORT_DESTINATION)
211 +
212 +#define IPT_MULTI_PORTS        15
213 +
214 +/* Must fit inside union ipt_matchinfo: 32 bytes */
215 +/* every entry in ports[] except for the last one has one bit in pflags
216 + * associated with it. If this bit is set, the port is the first port of
217 + * a portrange, with the next entry being the last.
218 + * End of list is marked with pflags bit set and port=65535.
219 + * If 14 ports are used (last one does not have a pflag), the last port
220 + * is repeated to fill the last entry in ports[] */
221 +struct ipt_mport
222 +{
223 +       u_int8_t flags:2;                       /* Type of comparison */
224 +       u_int16_t pflags:14;                    /* Port flags */
225 +       u_int16_t ports[IPT_MULTI_PORTS];       /* Ports */
226 +};
227 +#endif /*_IPT_MPORT_H*/
228 diff -Nur linux-2.6.4-rc2.org/include/linux/netfilter_ipv4/ipt_nth.h linux-2.6.4-rc2/include/linux/netfilter_ipv4/ipt_nth.h
229 --- linux-2.6.4-rc2.org/include/linux/netfilter_ipv4/ipt_nth.h  1970-01-01 00:00:00.000000000 +0000
230 +++ linux-2.6.4-rc2/include/linux/netfilter_ipv4/ipt_nth.h      2004-03-05 09:55:21.000000000 +0000
231 @@ -0,0 +1,19 @@
232 +#ifndef _IPT_NTH_H
233 +#define _IPT_NTH_H
234 +
235 +#include <linux/param.h>
236 +#include <linux/types.h>
237 +
238 +#ifndef IPT_NTH_NUM_COUNTERS
239 +#define IPT_NTH_NUM_COUNTERS 16
240 +#endif
241 +
242 +struct ipt_nth_info {
243 +       u_int8_t every;
244 +       u_int8_t not;
245 +       u_int8_t startat;
246 +       u_int8_t counter;
247 +       u_int8_t packet;
248 +};
249 +
250 +#endif /*_IPT_NTH_H*/
251 diff -Nur linux-2.6.4-rc2.org/include/linux/netfilter_ipv4/ipt_quota.h linux-2.6.4-rc2/include/linux/netfilter_ipv4/ipt_quota.h
252 --- linux-2.6.4-rc2.org/include/linux/netfilter_ipv4/ipt_quota.h        1970-01-01 00:00:00.000000000 +0000
253 +++ linux-2.6.4-rc2/include/linux/netfilter_ipv4/ipt_quota.h    2004-03-05 09:55:22.000000000 +0000
254 @@ -0,0 +1,11 @@
255 +#ifndef _IPT_QUOTA_H
256 +#define _IPT_QUOTA_H
257 +
258 +/* print debug info in both kernel/netfilter module & iptable library */
259 +//#define DEBUG_IPT_QUOTA
260 +
261 +struct ipt_quota_info {
262 +        u_int64_t quota;
263 +};
264 +
265 +#endif /*_IPT_QUOTA_H*/
266 diff -Nur linux-2.6.4-rc2.org/include/linux/netfilter_ipv4/ipt_realm.h linux-2.6.4-rc2/include/linux/netfilter_ipv4/ipt_realm.h
267 --- linux-2.6.4-rc2.org/include/linux/netfilter_ipv4/ipt_realm.h        1970-01-01 00:00:00.000000000 +0000
268 +++ linux-2.6.4-rc2/include/linux/netfilter_ipv4/ipt_realm.h    2004-03-05 09:55:23.000000000 +0000
269 @@ -0,0 +1,9 @@
270 +#ifndef _IPT_REALM_H
271 +#define _IPT_REALM_H
272 +
273 +struct ipt_realm_info {
274 +       u_int32_t id;
275 +       u_int32_t mask;
276 +       u_int8_t invert;
277 +};
278 +#endif /*_IPT_REALM_H*/
279 diff -Nur linux-2.6.4-rc2.org/include/linux/netfilter_ipv4/ipt_sctp.h linux-2.6.4-rc2/include/linux/netfilter_ipv4/ipt_sctp.h
280 --- linux-2.6.4-rc2.org/include/linux/netfilter_ipv4/ipt_sctp.h 1970-01-01 00:00:00.000000000 +0000
281 +++ linux-2.6.4-rc2/include/linux/netfilter_ipv4/ipt_sctp.h     2004-03-05 09:55:25.000000000 +0000
282 @@ -0,0 +1,107 @@
283 +#ifndef _IPT_SCTP_H_
284 +#define _IPT_SCTP_H_
285 +
286 +#define IPT_SCTP_SRC_PORTS             0x01
287 +#define IPT_SCTP_DEST_PORTS            0x02
288 +#define IPT_SCTP_CHUNK_TYPES           0x04
289 +
290 +#define IPT_SCTP_VALID_FLAGS           0x07
291 +
292 +#define ELEMCOUNT(x) (sizeof(x)/sizeof(x[0]))
293 +
294 +
295 +struct ipt_sctp_flag_info {
296 +       u_int8_t chunktype;
297 +       u_int8_t flag;
298 +       u_int8_t flag_mask;
299 +};
300 +
301 +#define IPT_NUM_SCTP_FLAGS     4
302 +
303 +struct ipt_sctp_info {
304 +       u_int16_t dpts[2];  /* Min, Max */
305 +       u_int16_t spts[2];  /* Min, Max */
306 +
307 +       u_int32_t chunkmap[256 / sizeof (u_int32_t)];  /* Bit mask of chunks to be matched according to RFC 2960 */
308 +
309 +#define SCTP_CHUNK_MATCH_ANY   0x01  /* Match if any of the chunk types are present */
310 +#define SCTP_CHUNK_MATCH_ALL   0x02  /* Match if all of the chunk types are present */
311 +#define SCTP_CHUNK_MATCH_ONLY  0x04  /* Match if these are the only chunk types present */
312 +
313 +       u_int32_t chunk_match_type;
314 +       struct ipt_sctp_flag_info flag_info[IPT_NUM_SCTP_FLAGS];
315 +       int flag_count;
316 +
317 +       u_int32_t flags;
318 +       u_int32_t invflags;
319 +};
320 +
321 +#define bytes(type) (sizeof(type) * 8)
322 +
323 +#define SCTP_CHUNKMAP_SET(chunkmap, type)              \
324 +       do {                                            \
325 +               chunkmap[type / bytes(u_int32_t)] |=    \
326 +                       1 << (type % bytes(u_int32_t)); \
327 +       } while (0)
328 +
329 +#define SCTP_CHUNKMAP_CLEAR(chunkmap, type)                    \
330 +       do {                                                    \
331 +               chunkmap[type / bytes(u_int32_t)] &=            \
332 +                       ~(1 << (type % bytes(u_int32_t)));      \
333 +       } while (0)
334 +
335 +#define SCTP_CHUNKMAP_IS_SET(chunkmap, type)                   \
336 +({                                                             \
337 +       (chunkmap[type / bytes (u_int32_t)] &                   \
338 +               (1 << (type % bytes (u_int32_t)))) ? 1: 0;      \
339 +})
340 +
341 +#define SCTP_CHUNKMAP_RESET(chunkmap)                          \
342 +       do {                                                    \
343 +               int i;                                          \
344 +               for (i = 0; i < ELEMCOUNT(chunkmap); i++)       \
345 +                       chunkmap[i] = 0;                        \
346 +       } while (0)
347 +
348 +#define SCTP_CHUNKMAP_SET_ALL(chunkmap)                        \
349 +       do {                                                    \
350 +               int i;                                          \
351 +               for (i = 0; i < ELEMCOUNT(chunkmap); i++)       \
352 +                       chunkmap[i] = ~0;                       \
353 +       } while (0)
354 +
355 +#define SCTP_CHUNKMAP_COPY(destmap, srcmap)                    \
356 +       do {                                                    \
357 +               int i;                                          \
358 +               for (i = 0; i < ELEMCOUNT(chunkmap); i++)       \
359 +                       destmap[i] = srcmap[i];                 \
360 +       } while (0)
361 +
362 +#define SCTP_CHUNKMAP_IS_CLEAR(chunkmap)               \
363 +({                                                     \
364 +       int i;                                          \
365 +       int flag = 1;                                   \
366 +       for (i = 0; i < ELEMCOUNT(chunkmap); i++) {     \
367 +               if (chunkmap[i]) {                      \
368 +                       flag = 0;                       \
369 +                       break;                          \
370 +               }                                       \
371 +       }                                               \
372 +        flag;                                          \
373 +})
374 +
375 +#define SCTP_CHUNKMAP_IS_ALL_SET(chunkmap)             \
376 +({                                                     \
377 +       int i;                                          \
378 +       int flag = 1;                                   \
379 +       for (i = 0; i < ELEMCOUNT(chunkmap); i++) {     \
380 +               if (chunkmap[i] != ~0) {                \
381 +                       flag = 0;                       \
382 +                               break;                  \
383 +               }                                       \
384 +       }                                               \
385 +        flag;                                          \
386 +})
387 +
388 +#endif /* _IPT_SCTP_H_ */
389 +
390 diff -Nur linux-2.6.4-rc2.org/include/linux/netfilter_ipv4/ipt_state.h linux-2.6.4-rc2/include/linux/netfilter_ipv4/ipt_state.h
391 --- linux-2.6.4-rc2.org/include/linux/netfilter_ipv4/ipt_state.h        2004-03-04 06:17:00.000000000 +0000
392 +++ linux-2.6.4-rc2/include/linux/netfilter_ipv4/ipt_state.h    2004-03-05 09:55:23.000000000 +0000
393 @@ -4,6 +4,8 @@
394  #define IPT_STATE_BIT(ctinfo) (1 << ((ctinfo)%IP_CT_IS_REPLY+1))
395  #define IPT_STATE_INVALID (1 << 0)
396  
397 +#define IPT_STATE_UNTRACKED (1 << (IP_CT_NUMBER + 1))
398 +
399  struct ipt_state_info
400  {
401         unsigned int statemask;
402 diff -Nur linux-2.6.4-rc2.org/include/linux/netfilter_ipv4/ipt_u32.h linux-2.6.4-rc2/include/linux/netfilter_ipv4/ipt_u32.h
403 --- linux-2.6.4-rc2.org/include/linux/netfilter_ipv4/ipt_u32.h  1970-01-01 00:00:00.000000000 +0000
404 +++ linux-2.6.4-rc2/include/linux/netfilter_ipv4/ipt_u32.h      2004-03-05 09:56:07.000000000 +0000
405 @@ -0,0 +1,40 @@
406 +#ifndef _IPT_U32_H
407 +#define _IPT_U32_H
408 +#include <linux/netfilter_ipv4/ip_tables.h>
409 +
410 +enum ipt_u32_ops
411 +{
412 +       IPT_U32_AND,
413 +       IPT_U32_LEFTSH,
414 +       IPT_U32_RIGHTSH,
415 +       IPT_U32_AT
416 +};
417 +
418 +struct ipt_u32_location_element
419 +{
420 +       u_int32_t number;
421 +       u_int8_t nextop;
422 +};
423 +struct ipt_u32_value_element
424 +{
425 +       u_int32_t min;
426 +       u_int32_t max;
427 +};
428 +/* *** any way to allow for an arbitrary number of elements?
429 +   for now I settle for a limit of 10 of each */
430 +#define U32MAXSIZE 10
431 +struct ipt_u32_test
432 +{
433 +       u_int8_t nnums;
434 +       struct ipt_u32_location_element location[U32MAXSIZE+1];
435 +       u_int8_t nvalues;
436 +       struct ipt_u32_value_element value[U32MAXSIZE+1];
437 +};
438 +
439 +struct ipt_u32
440 +{
441 +       u_int8_t ntests;
442 +       struct ipt_u32_test tests[U32MAXSIZE+1];
443 +};
444 +
445 +#endif /*_IPT_U32_H*/
446 diff -Nur linux-2.6.4-rc2.org/include/linux/netfilter_ipv4.h linux-2.6.4-rc2/include/linux/netfilter_ipv4.h
447 --- linux-2.6.4-rc2.org/include/linux/netfilter_ipv4.h  2004-03-04 06:16:58.000000000 +0000
448 +++ linux-2.6.4-rc2/include/linux/netfilter_ipv4.h      2004-03-05 09:55:23.000000000 +0000
449 @@ -51,6 +51,8 @@
450  
451  enum nf_ip_hook_priorities {
452         NF_IP_PRI_FIRST = INT_MIN,
453 +       NF_IP_PRI_CONNTRACK_DEFRAG = -400,
454 +       NF_IP_PRI_RAW = -300,
455         NF_IP_PRI_SELINUX_FIRST = -225,
456         NF_IP_PRI_CONNTRACK = -200,
457         NF_IP_PRI_BRIDGE_SABOTAGE_FORWARD = -175,
458 diff -Nur linux-2.6.4-rc2.org/include/linux/netfilter_ipv6/ip6t_HL.h linux-2.6.4-rc2/include/linux/netfilter_ipv6/ip6t_HL.h
459 --- linux-2.6.4-rc2.org/include/linux/netfilter_ipv6/ip6t_HL.h  1970-01-01 00:00:00.000000000 +0000
460 +++ linux-2.6.4-rc2/include/linux/netfilter_ipv6/ip6t_HL.h      2004-03-05 09:55:10.000000000 +0000
461 @@ -0,0 +1,22 @@
462 +/* Hop Limit modification module for ip6tables
463 + * Maciej Soltysiak <solt@dns.toxicfilms.tv>
464 + * Based on HW's TTL module */
465 +
466 +#ifndef _IP6T_HL_H
467 +#define _IP6T_HL_H
468 +
469 +enum {
470 +       IP6T_HL_SET = 0,
471 +       IP6T_HL_INC,
472 +       IP6T_HL_DEC
473 +};
474 +
475 +#define IP6T_HL_MAXMODE        IP6T_HL_DEC
476 +
477 +struct ip6t_HL_info {
478 +       u_int8_t        mode;
479 +       u_int8_t        hop_limit;
480 +};
481 +
482 +
483 +#endif
484 diff -Nur linux-2.6.4-rc2.org/include/linux/netfilter_ipv6/ip6t_REJECT.h linux-2.6.4-rc2/include/linux/netfilter_ipv6/ip6t_REJECT.h
485 --- linux-2.6.4-rc2.org/include/linux/netfilter_ipv6/ip6t_REJECT.h      2004-03-04 06:16:34.000000000 +0000
486 +++ linux-2.6.4-rc2/include/linux/netfilter_ipv6/ip6t_REJECT.h  2004-03-05 09:55:13.000000000 +0000
487 @@ -2,15 +2,17 @@
488  #define _IP6T_REJECT_H
489  
490  enum ip6t_reject_with {
491 -       IP6T_ICMP_NET_UNREACHABLE,
492 -       IP6T_ICMP_HOST_UNREACHABLE,
493 -       IP6T_ICMP_PROT_UNREACHABLE,
494 -       IP6T_ICMP_PORT_UNREACHABLE,
495 -       IP6T_ICMP_ECHOREPLY
496 +       IP6T_ICMP6_NO_ROUTE,
497 +       IP6T_ICMP6_ADM_PROHIBITED,
498 +       IP6T_ICMP6_NOT_NEIGHBOUR,
499 +       IP6T_ICMP6_ADDR_UNREACH,
500 +       IP6T_ICMP6_PORT_UNREACH,
501 +       IP6T_ICMP6_ECHOREPLY,
502 +       IP6T_TCP_RESET
503  };
504  
505  struct ip6t_reject_info {
506         enum ip6t_reject_with with;      /* reject type */
507  };
508  
509 -#endif /*_IPT_REJECT_H*/
510 +#endif /*_IP6T_REJECT_H*/
511 diff -Nur linux-2.6.4-rc2.org/include/linux/netfilter_ipv6/ip6t_fuzzy.h linux-2.6.4-rc2/include/linux/netfilter_ipv6/ip6t_fuzzy.h
512 --- linux-2.6.4-rc2.org/include/linux/netfilter_ipv6/ip6t_fuzzy.h       1970-01-01 00:00:00.000000000 +0000
513 +++ linux-2.6.4-rc2/include/linux/netfilter_ipv6/ip6t_fuzzy.h   2004-03-05 09:55:18.000000000 +0000
514 @@ -0,0 +1,21 @@
515 +#ifndef _IP6T_FUZZY_H
516 +#define _IP6T_FUZZY_H
517 +
518 +#include <linux/param.h>
519 +#include <linux/types.h>
520 +
521 +#define MAXFUZZYRATE 10000000
522 +#define MINFUZZYRATE 3
523 +
524 +struct ip6t_fuzzy_info {
525 +       u_int32_t minimum_rate;
526 +       u_int32_t maximum_rate;
527 +       u_int32_t packets_total;
528 +       u_int32_t bytes_total;
529 +       u_int32_t previous_time;
530 +       u_int32_t present_time;
531 +       u_int32_t mean_rate;
532 +       u_int8_t acceptance_rate;
533 +};
534 +
535 +#endif /*_IP6T_FUZZY_H*/
536 diff -Nur linux-2.6.4-rc2.org/include/linux/netfilter_ipv6/ip6t_nth.h linux-2.6.4-rc2/include/linux/netfilter_ipv6/ip6t_nth.h
537 --- linux-2.6.4-rc2.org/include/linux/netfilter_ipv6/ip6t_nth.h 1970-01-01 00:00:00.000000000 +0000
538 +++ linux-2.6.4-rc2/include/linux/netfilter_ipv6/ip6t_nth.h     2004-03-05 09:55:21.000000000 +0000
539 @@ -0,0 +1,19 @@
540 +#ifndef _IP6T_NTH_H
541 +#define _IP6T_NTH_H
542 +
543 +#include <linux/param.h>
544 +#include <linux/types.h>
545 +
546 +#ifndef IP6T_NTH_NUM_COUNTERS
547 +#define IP6T_NTH_NUM_COUNTERS 16
548 +#endif
549 +
550 +struct ip6t_nth_info {
551 +       u_int8_t every;
552 +       u_int8_t not;
553 +       u_int8_t startat;
554 +       u_int8_t counter;
555 +       u_int8_t packet;
556 +};
557 +
558 +#endif /*_IP6T_NTH_H*/
559 diff -Nur linux-2.6.4-rc2.org/net/core/netfilter.c linux-2.6.4-rc2/net/core/netfilter.c
560 --- linux-2.6.4-rc2.org/net/core/netfilter.c    2004-03-04 06:16:45.000000000 +0000
561 +++ linux-2.6.4-rc2/net/core/netfilter.c        2004-03-05 09:55:08.000000000 +0000
562 @@ -8,8 +8,10 @@
563   *
564   * February 2000: Modified by James Morris to have 1 queue per protocol.
565   * 15-Mar-2000:   Added NF_REPEAT --RR.
566 + * 08-May-2003:          Internal logging interface added by Jozsef Kadlecsik.
567   */
568  #include <linux/config.h>
569 +#include <linux/kernel.h>
570  #include <linux/netfilter.h>
571  #include <net/protocol.h>
572  #include <linux/init.h>
573 @@ -58,6 +60,10 @@
574  } queue_handler[NPROTO];
575  static rwlock_t queue_handler_lock = RW_LOCK_UNLOCKED;
576  
577 +/**
578 + * nf_register_hook - Register with a netfilter hook
579 + * @reg: Hook operations to be registered
580 + */
581  int nf_register_hook(struct nf_hook_ops *reg)
582  {
583         struct list_head *i;
584 @@ -74,6 +80,10 @@
585         return 0;
586  }
587  
588 +/**
589 + * nf_unregister_hook - Unregister from a netfilter hook
590 + * @reg: hook operations to be unregistered
591 + */
592  void nf_unregister_hook(struct nf_hook_ops *reg)
593  {
594         spin_lock_bh(&nf_hook_lock);
595 @@ -386,6 +396,18 @@
596         return NF_ACCEPT;
597  }
598  
599 +/**
600 + * nf_register_queue_handler - Registere a queue handler with netfilter
601 + * @pf: protocol family
602 + * @outfn: function called by core to enqueue a packet
603 + * @data: opaque parameter, passed through
604 + *
605 + * This function registers a queue handler with netfilter.  There can only
606 + * be one queue handler for every protocol family.
607 + *
608 + * A queue handler _must_ reinject every packet via nf_reinject, no
609 + * matter what.
610 + */
611  int nf_register_queue_handler(int pf, nf_queue_outfn_t outfn, void *data)
612  {      
613         int ret;
614 @@ -403,7 +425,12 @@
615         return ret;
616  }
617  
618 -/* The caller must flush their queue before this */
619 +/**
620 + * nf_unregister_queue_handler - Unregister queue handler from netfilter
621 + * @pf: protocol family
622 + *
623 + * The caller must flush their queue before unregistering
624 + */
625  int nf_unregister_queue_handler(int pf)
626  {
627         write_lock_bh(&queue_handler_lock);
628 @@ -546,6 +573,15 @@
629         return ret;
630  }
631  
632 +/**
633 + * nf_reinject - Reinject a packet from a queue handler
634 + * @skb: the packet to be reinjected
635 + * @info: info which was passed to the outfn() of the queue handler
636 + * @verdict: verdict (NF_ACCEPT, ...) for this packet
637 + *
638 + * This is the function called by a queue handler to reinject a
639 + * packet.
640 + */
641  void nf_reinject(struct sk_buff *skb, struct nf_info *info,
642                  unsigned int verdict)
643  {
644 @@ -740,6 +776,72 @@
645  EXPORT_SYMBOL(skb_ip_make_writable);
646  #endif /*CONFIG_INET*/
647  
648 +/* Internal logging interface, which relies on the real 
649 +   LOG target modules */
650 +
651 +#define NF_LOG_PREFIXLEN               128
652 +
653 +static nf_logfn *nf_logging[NPROTO]; /* = NULL */
654 +static int reported = 0;
655 +static spinlock_t nf_log_lock = SPIN_LOCK_UNLOCKED;
656 +
657 +int nf_log_register(int pf, nf_logfn *logfn)
658 +{
659 +       int ret = -EBUSY;
660 +
661 +       /* Any setup of logging members must be done before
662 +        * substituting pointer. */
663 +       smp_wmb();
664 +       spin_lock(&nf_log_lock);
665 +       if (!nf_logging[pf]) {
666 +               nf_logging[pf] = logfn;
667 +               ret = 0;
668 +       }
669 +       spin_unlock(&nf_log_lock);
670 +       return ret;
671 +}              
672 +
673 +void nf_log_unregister(int pf, nf_logfn *logfn)
674 +{
675 +       spin_lock(&nf_log_lock);
676 +       if (nf_logging[pf] == logfn)
677 +               nf_logging[pf] = NULL;
678 +       spin_unlock(&nf_log_lock);
679 +
680 +       /* Give time to concurrent readers. */
681 +       synchronize_net();
682 +}              
683 +
684 +void nf_log_packet(int pf,
685 +                  unsigned int hooknum,
686 +                  const struct sk_buff *skb,
687 +                  const struct net_device *in,
688 +                  const struct net_device *out,
689 +                  const char *fmt, ...)
690 +{
691 +       va_list args;
692 +       char prefix[NF_LOG_PREFIXLEN];
693 +       nf_logfn *logfn;
694 +       
695 +       rcu_read_lock();
696 +       logfn = nf_logging[pf];
697 +       if (logfn) {
698 +               va_start(args, fmt);
699 +               vsnprintf(prefix, sizeof(prefix), fmt, args);
700 +               va_end(args);
701 +               /* We must read logging before nf_logfn[pf] */
702 +               smp_read_barrier_depends();
703 +               logfn(hooknum, skb, in, out, prefix);
704 +       } else if (!reported) {
705 +               printk(KERN_WARNING "nf_log_packet: can\'t log yet, "
706 +                      "no backend logging module loaded in!\n");
707 +               reported++;
708 +       }
709 +       rcu_read_unlock();
710 +}
711 +EXPORT_SYMBOL(nf_log_register);
712 +EXPORT_SYMBOL(nf_log_unregister);
713 +EXPORT_SYMBOL(nf_log_packet);
714  
715  /* This does not belong here, but ipt_REJECT needs it if connection
716     tracking in use: without this, connection may not be in hash table,
717 diff -Nur linux-2.6.4-rc2.org/net/core/netfilter.c.orig linux-2.6.4-rc2/net/core/netfilter.c.orig
718 --- linux-2.6.4-rc2.org/net/core/netfilter.c.orig       1970-01-01 00:00:00.000000000 +0000
719 +++ linux-2.6.4-rc2/net/core/netfilter.c.orig   2004-03-05 09:55:06.000000000 +0000
720 @@ -0,0 +1,806 @@
721 +/* netfilter.c: look after the filters for various protocols. 
722 + * Heavily influenced by the old firewall.c by David Bonn and Alan Cox.
723 + *
724 + * Thanks to Rob `CmdrTaco' Malda for not influencing this code in any
725 + * way.
726 + *
727 + * Rusty Russell (C)2000 -- This code is GPL.
728 + *
729 + * February 2000: Modified by James Morris to have 1 queue per protocol.
730 + * 15-Mar-2000:   Added NF_REPEAT --RR.
731 + */
732 +#include <linux/config.h>
733 +#include <linux/netfilter.h>
734 +#include <net/protocol.h>
735 +#include <linux/init.h>
736 +#include <linux/skbuff.h>
737 +#include <linux/wait.h>
738 +#include <linux/module.h>
739 +#include <linux/interrupt.h>
740 +#include <linux/if.h>
741 +#include <linux/netdevice.h>
742 +#include <linux/inetdevice.h>
743 +#include <linux/tcp.h>
744 +#include <linux/udp.h>
745 +#include <linux/icmp.h>
746 +#include <net/sock.h>
747 +#include <net/route.h>
748 +#include <linux/ip.h>
749 +
750 +/* In this code, we can be waiting indefinitely for userspace to
751 + * service a packet if a hook returns NF_QUEUE.  We could keep a count
752 + * of skbuffs queued for userspace, and not deregister a hook unless
753 + * this is zero, but that sucks.  Now, we simply check when the
754 + * packets come back: if the hook is gone, the packet is discarded. */
755 +#ifdef CONFIG_NETFILTER_DEBUG
756 +#define NFDEBUG(format, args...)  printk(format , ## args)
757 +#else
758 +#define NFDEBUG(format, args...)
759 +#endif
760 +
761 +/* Sockopts only registered and called from user context, so
762 +   net locking would be overkill.  Also, [gs]etsockopt calls may
763 +   sleep. */
764 +static DECLARE_MUTEX(nf_sockopt_mutex);
765 +
766 +struct list_head nf_hooks[NPROTO][NF_MAX_HOOKS];
767 +static LIST_HEAD(nf_sockopts);
768 +static spinlock_t nf_hook_lock = SPIN_LOCK_UNLOCKED;
769 +
770 +/* 
771 + * A queue handler may be registered for each protocol.  Each is protected by
772 + * long term mutex.  The handler must provide an an outfn() to accept packets
773 + * for queueing and must reinject all packets it receives, no matter what.
774 + */
775 +static struct nf_queue_handler_t {
776 +       nf_queue_outfn_t outfn;
777 +       void *data;
778 +} queue_handler[NPROTO];
779 +static rwlock_t queue_handler_lock = RW_LOCK_UNLOCKED;
780 +
781 +/**
782 + * nf_register_hook - Register with a netfilter hook
783 + * @reg: Hook operations to be registered
784 + */
785 +int nf_register_hook(struct nf_hook_ops *reg)
786 +{
787 +       struct list_head *i;
788 +
789 +       spin_lock_bh(&nf_hook_lock);
790 +       list_for_each(i, &nf_hooks[reg->pf][reg->hooknum]) {
791 +               if (reg->priority < ((struct nf_hook_ops *)i)->priority)
792 +                       break;
793 +       }
794 +       list_add_rcu(&reg->list, i->prev);
795 +       spin_unlock_bh(&nf_hook_lock);
796 +
797 +       synchronize_net();
798 +       return 0;
799 +}
800 +
801 +/**
802 + * nf_unregister_hook - Unregister from a netfilter hook
803 + * @reg: hook operations to be unregistered
804 + */
805 +void nf_unregister_hook(struct nf_hook_ops *reg)
806 +{
807 +       spin_lock_bh(&nf_hook_lock);
808 +       list_del_rcu(&reg->list);
809 +       spin_unlock_bh(&nf_hook_lock);
810 +
811 +       synchronize_net();
812 +}
813 +
814 +/* Do exclusive ranges overlap? */
815 +static inline int overlap(int min1, int max1, int min2, int max2)
816 +{
817 +       return max1 > min2 && min1 < max2;
818 +}
819 +
820 +/* Functions to register sockopt ranges (exclusive). */
821 +int nf_register_sockopt(struct nf_sockopt_ops *reg)
822 +{
823 +       struct list_head *i;
824 +       int ret = 0;
825 +
826 +       if (down_interruptible(&nf_sockopt_mutex) != 0)
827 +               return -EINTR;
828 +
829 +       list_for_each(i, &nf_sockopts) {
830 +               struct nf_sockopt_ops *ops = (struct nf_sockopt_ops *)i;
831 +               if (ops->pf == reg->pf
832 +                   && (overlap(ops->set_optmin, ops->set_optmax, 
833 +                               reg->set_optmin, reg->set_optmax)
834 +                       || overlap(ops->get_optmin, ops->get_optmax, 
835 +                                  reg->get_optmin, reg->get_optmax))) {
836 +                       NFDEBUG("nf_sock overlap: %u-%u/%u-%u v %u-%u/%u-%u\n",
837 +                               ops->set_optmin, ops->set_optmax, 
838 +                               ops->get_optmin, ops->get_optmax, 
839 +                               reg->set_optmin, reg->set_optmax,
840 +                               reg->get_optmin, reg->get_optmax);
841 +                       ret = -EBUSY;
842 +                       goto out;
843 +               }
844 +       }
845 +
846 +       list_add(&reg->list, &nf_sockopts);
847 +out:
848 +       up(&nf_sockopt_mutex);
849 +       return ret;
850 +}
851 +
852 +void nf_unregister_sockopt(struct nf_sockopt_ops *reg)
853 +{
854 +       /* No point being interruptible: we're probably in cleanup_module() */
855 + restart:
856 +       down(&nf_sockopt_mutex);
857 +       if (reg->use != 0) {
858 +               /* To be woken by nf_sockopt call... */
859 +               /* FIXME: Stuart Young's name appears gratuitously. */
860 +               set_current_state(TASK_UNINTERRUPTIBLE);
861 +               reg->cleanup_task = current;
862 +               up(&nf_sockopt_mutex);
863 +               schedule();
864 +               goto restart;
865 +       }
866 +       list_del(&reg->list);
867 +       up(&nf_sockopt_mutex);
868 +}
869 +
870 +#ifdef CONFIG_NETFILTER_DEBUG
871 +#include <net/ip.h>
872 +#include <net/tcp.h>
873 +#include <linux/netfilter_ipv4.h>
874 +
875 +static void debug_print_hooks_ip(unsigned int nf_debug)
876 +{
877 +       if (nf_debug & (1 << NF_IP_PRE_ROUTING)) {
878 +               printk("PRE_ROUTING ");
879 +               nf_debug ^= (1 << NF_IP_PRE_ROUTING);
880 +       }
881 +       if (nf_debug & (1 << NF_IP_LOCAL_IN)) {
882 +               printk("LOCAL_IN ");
883 +               nf_debug ^= (1 << NF_IP_LOCAL_IN);
884 +       }
885 +       if (nf_debug & (1 << NF_IP_FORWARD)) {
886 +               printk("FORWARD ");
887 +               nf_debug ^= (1 << NF_IP_FORWARD);
888 +       }
889 +       if (nf_debug & (1 << NF_IP_LOCAL_OUT)) {
890 +               printk("LOCAL_OUT ");
891 +               nf_debug ^= (1 << NF_IP_LOCAL_OUT);
892 +       }
893 +       if (nf_debug & (1 << NF_IP_POST_ROUTING)) {
894 +               printk("POST_ROUTING ");
895 +               nf_debug ^= (1 << NF_IP_POST_ROUTING);
896 +       }
897 +       if (nf_debug)
898 +               printk("Crap bits: 0x%04X", nf_debug);
899 +       printk("\n");
900 +}
901 +
902 +void nf_dump_skb(int pf, struct sk_buff *skb)
903 +{
904 +       printk("skb: pf=%i %s dev=%s len=%u\n", 
905 +              pf,
906 +              skb->sk ? "(owned)" : "(unowned)",
907 +              skb->dev ? skb->dev->name : "(no dev)",
908 +              skb->len);
909 +       switch (pf) {
910 +       case PF_INET: {
911 +               const struct iphdr *ip = skb->nh.iph;
912 +               __u32 *opt = (__u32 *) (ip + 1);
913 +               int opti;
914 +               __u16 src_port = 0, dst_port = 0;
915 +
916 +               if (ip->protocol == IPPROTO_TCP
917 +                   || ip->protocol == IPPROTO_UDP) {
918 +                       struct tcphdr *tcp=(struct tcphdr *)((__u32 *)ip+ip->ihl);
919 +                       src_port = ntohs(tcp->source);
920 +                       dst_port = ntohs(tcp->dest);
921 +               }
922 +       
923 +               printk("PROTO=%d %u.%u.%u.%u:%hu %u.%u.%u.%u:%hu"
924 +                      " L=%hu S=0x%2.2hX I=%hu F=0x%4.4hX T=%hu",
925 +                      ip->protocol, NIPQUAD(ip->saddr),
926 +                      src_port, NIPQUAD(ip->daddr),
927 +                      dst_port,
928 +                      ntohs(ip->tot_len), ip->tos, ntohs(ip->id),
929 +                      ntohs(ip->frag_off), ip->ttl);
930 +
931 +               for (opti = 0; opti < (ip->ihl - sizeof(struct iphdr) / 4); opti++)
932 +                       printk(" O=0x%8.8X", *opt++);
933 +               printk("\n");
934 +       }
935 +       }
936 +}
937 +
938 +void nf_debug_ip_local_deliver(struct sk_buff *skb)
939 +{
940 +       /* If it's a loopback packet, it must have come through
941 +        * NF_IP_LOCAL_OUT, NF_IP_RAW_INPUT, NF_IP_PRE_ROUTING and
942 +        * NF_IP_LOCAL_IN.  Otherwise, must have gone through
943 +        * NF_IP_RAW_INPUT and NF_IP_PRE_ROUTING.  */
944 +       if (!skb->dev) {
945 +               printk("ip_local_deliver: skb->dev is NULL.\n");
946 +       }
947 +       else if (strcmp(skb->dev->name, "lo") == 0) {
948 +               if (skb->nf_debug != ((1 << NF_IP_LOCAL_OUT)
949 +                                     | (1 << NF_IP_POST_ROUTING)
950 +                                     | (1 << NF_IP_PRE_ROUTING)
951 +                                     | (1 << NF_IP_LOCAL_IN))) {
952 +                       printk("ip_local_deliver: bad loopback skb: ");
953 +                       debug_print_hooks_ip(skb->nf_debug);
954 +                       nf_dump_skb(PF_INET, skb);
955 +               }
956 +       }
957 +       else {
958 +               if (skb->nf_debug != ((1<<NF_IP_PRE_ROUTING)
959 +                                     | (1<<NF_IP_LOCAL_IN))) {
960 +                       printk("ip_local_deliver: bad non-lo skb: ");
961 +                       debug_print_hooks_ip(skb->nf_debug);
962 +                       nf_dump_skb(PF_INET, skb);
963 +               }
964 +       }
965 +}
966 +
967 +void nf_debug_ip_loopback_xmit(struct sk_buff *newskb)
968 +{
969 +       if (newskb->nf_debug != ((1 << NF_IP_LOCAL_OUT)
970 +                                | (1 << NF_IP_POST_ROUTING))) {
971 +               printk("ip_dev_loopback_xmit: bad owned skb = %p: ", 
972 +                      newskb);
973 +               debug_print_hooks_ip(newskb->nf_debug);
974 +               nf_dump_skb(PF_INET, newskb);
975 +       }
976 +       /* Clear to avoid confusing input check */
977 +       newskb->nf_debug = 0;
978 +}
979 +
980 +void nf_debug_ip_finish_output2(struct sk_buff *skb)
981 +{
982 +       /* If it's owned, it must have gone through the
983 +        * NF_IP_LOCAL_OUT and NF_IP_POST_ROUTING.
984 +        * Otherwise, must have gone through
985 +        * NF_IP_PRE_ROUTING, NF_IP_FORWARD and NF_IP_POST_ROUTING.
986 +        */
987 +       if (skb->sk) {
988 +               if (skb->nf_debug != ((1 << NF_IP_LOCAL_OUT)
989 +                                     | (1 << NF_IP_POST_ROUTING))) {
990 +                       printk("ip_finish_output: bad owned skb = %p: ", skb);
991 +                       debug_print_hooks_ip(skb->nf_debug);
992 +                       nf_dump_skb(PF_INET, skb);
993 +               }
994 +       } else {
995 +               if (skb->nf_debug != ((1 << NF_IP_PRE_ROUTING)
996 +                                     | (1 << NF_IP_FORWARD)
997 +                                     | (1 << NF_IP_POST_ROUTING))) {
998 +                       /* Fragments, entunnelled packets, TCP RSTs
999 +                           generated by ipt_REJECT will have no
1000 +                           owners, but still may be local */
1001 +                       if (skb->nf_debug != ((1 << NF_IP_LOCAL_OUT)
1002 +                                             | (1 << NF_IP_POST_ROUTING))){
1003 +                               printk("ip_finish_output:"
1004 +                                      " bad unowned skb = %p: ",skb);
1005 +                               debug_print_hooks_ip(skb->nf_debug);
1006 +                               nf_dump_skb(PF_INET, skb);
1007 +                       }
1008 +               }
1009 +       }
1010 +}
1011 +#endif /*CONFIG_NETFILTER_DEBUG*/
1012 +
1013 +/* Call get/setsockopt() */
1014 +static int nf_sockopt(struct sock *sk, int pf, int val, 
1015 +                     char *opt, int *len, int get)
1016 +{
1017 +       struct list_head *i;
1018 +       struct nf_sockopt_ops *ops;
1019 +       int ret;
1020 +
1021 +       if (down_interruptible(&nf_sockopt_mutex) != 0)
1022 +               return -EINTR;
1023 +
1024 +       list_for_each(i, &nf_sockopts) {
1025 +               ops = (struct nf_sockopt_ops *)i;
1026 +               if (ops->pf == pf) {
1027 +                       if (get) {
1028 +                               if (val >= ops->get_optmin
1029 +                                   && val < ops->get_optmax) {
1030 +                                       ops->use++;
1031 +                                       up(&nf_sockopt_mutex);
1032 +                                       ret = ops->get(sk, val, opt, len);
1033 +                                       goto out;
1034 +                               }
1035 +                       } else {
1036 +                               if (val >= ops->set_optmin
1037 +                                   && val < ops->set_optmax) {
1038 +                                       ops->use++;
1039 +                                       up(&nf_sockopt_mutex);
1040 +                                       ret = ops->set(sk, val, opt, *len);
1041 +                                       goto out;
1042 +                               }
1043 +                       }
1044 +               }
1045 +       }
1046 +       up(&nf_sockopt_mutex);
1047 +       return -ENOPROTOOPT;
1048 +       
1049 + out:
1050 +       down(&nf_sockopt_mutex);
1051 +       ops->use--;
1052 +       if (ops->cleanup_task)
1053 +               wake_up_process(ops->cleanup_task);
1054 +       up(&nf_sockopt_mutex);
1055 +       return ret;
1056 +}
1057 +
1058 +int nf_setsockopt(struct sock *sk, int pf, int val, char *opt,
1059 +                 int len)
1060 +{
1061 +       return nf_sockopt(sk, pf, val, opt, &len, 0);
1062 +}
1063 +
1064 +int nf_getsockopt(struct sock *sk, int pf, int val, char *opt, int *len)
1065 +{
1066 +       return nf_sockopt(sk, pf, val, opt, len, 1);
1067 +}
1068 +
1069 +static unsigned int nf_iterate(struct list_head *head,
1070 +                              struct sk_buff **skb,
1071 +                              int hook,
1072 +                              const struct net_device *indev,
1073 +                              const struct net_device *outdev,
1074 +                              struct list_head **i,
1075 +                              int (*okfn)(struct sk_buff *),
1076 +                              int hook_thresh)
1077 +{
1078 +       /*
1079 +        * The caller must not block between calls to this
1080 +        * function because of risk of continuing from deleted element.
1081 +        */
1082 +       list_for_each_continue_rcu(*i, head) {
1083 +               struct nf_hook_ops *elem = (struct nf_hook_ops *)*i;
1084 +
1085 +               if (hook_thresh > elem->priority)
1086 +                       continue;
1087 +
1088 +               /* Optimization: we don't need to hold module
1089 +                   reference here, since function can't sleep. --RR */
1090 +               switch (elem->hook(hook, skb, indev, outdev, okfn)) {
1091 +               case NF_QUEUE:
1092 +                       return NF_QUEUE;
1093 +
1094 +               case NF_STOLEN:
1095 +                       return NF_STOLEN;
1096 +
1097 +               case NF_DROP:
1098 +                       return NF_DROP;
1099 +
1100 +               case NF_REPEAT:
1101 +                       *i = (*i)->prev;
1102 +                       break;
1103 +
1104 +#ifdef CONFIG_NETFILTER_DEBUG
1105 +               case NF_ACCEPT:
1106 +                       break;
1107 +
1108 +               default:
1109 +                       NFDEBUG("Evil return from %p(%u).\n", 
1110 +                               elem->hook, hook);
1111 +#endif
1112 +               }
1113 +       }
1114 +       return NF_ACCEPT;
1115 +}
1116 +
1117 +/**
1118 + * nf_register_queue_handler - Registere a queue handler with netfilter
1119 + * @pf: protocol family
1120 + * @outfn: function called by core to enqueue a packet
1121 + * @data: opaque parameter, passed through
1122 + *
1123 + * This function registers a queue handler with netfilter.  There can only
1124 + * be one queue handler for every protocol family.
1125 + *
1126 + * A queue handler _must_ reinject every packet via nf_reinject, no
1127 + * matter what.
1128 + */
1129 +int nf_register_queue_handler(int pf, nf_queue_outfn_t outfn, void *data)
1130 +{      
1131 +       int ret;
1132 +
1133 +       write_lock_bh(&queue_handler_lock);
1134 +       if (queue_handler[pf].outfn)
1135 +               ret = -EBUSY;
1136 +       else {
1137 +               queue_handler[pf].outfn = outfn;
1138 +               queue_handler[pf].data = data;
1139 +               ret = 0;
1140 +       }
1141 +       write_unlock_bh(&queue_handler_lock);
1142 +
1143 +       return ret;
1144 +}
1145 +
1146 +/**
1147 + * nf_unregister_queue_handler - Unregister queue handler from netfilter
1148 + * @pf: protocol family
1149 + *
1150 + * The caller must flush their queue before unregistering
1151 + */
1152 +int nf_unregister_queue_handler(int pf)
1153 +{
1154 +       write_lock_bh(&queue_handler_lock);
1155 +       queue_handler[pf].outfn = NULL;
1156 +       queue_handler[pf].data = NULL;
1157 +       write_unlock_bh(&queue_handler_lock);
1158 +       
1159 +       return 0;
1160 +}
1161 +
1162 +/* 
1163 + * Any packet that leaves via this function must come back 
1164 + * through nf_reinject().
1165 + */
1166 +static int nf_queue(struct sk_buff *skb, 
1167 +                   struct list_head *elem, 
1168 +                   int pf, unsigned int hook,
1169 +                   struct net_device *indev,
1170 +                   struct net_device *outdev,
1171 +                   int (*okfn)(struct sk_buff *))
1172 +{
1173 +       int status;
1174 +       struct nf_info *info;
1175 +#ifdef CONFIG_BRIDGE_NETFILTER
1176 +       struct net_device *physindev = NULL;
1177 +       struct net_device *physoutdev = NULL;
1178 +#endif
1179 +
1180 +       /* QUEUE == DROP if noone is waiting, to be safe. */
1181 +       read_lock(&queue_handler_lock);
1182 +       if (!queue_handler[pf].outfn) {
1183 +               read_unlock(&queue_handler_lock);
1184 +               kfree_skb(skb);
1185 +               return 1;
1186 +       }
1187 +
1188 +       info = kmalloc(sizeof(*info), GFP_ATOMIC);
1189 +       if (!info) {
1190 +               if (net_ratelimit())
1191 +                       printk(KERN_ERR "OOM queueing packet %p\n",
1192 +                              skb);
1193 +               read_unlock(&queue_handler_lock);
1194 +               kfree_skb(skb);
1195 +               return 1;
1196 +       }
1197 +
1198 +       *info = (struct nf_info) { 
1199 +               (struct nf_hook_ops *)elem, pf, hook, indev, outdev, okfn };
1200 +
1201 +       /* If it's going away, ignore hook. */
1202 +       if (!try_module_get(info->elem->owner)) {
1203 +               read_unlock(&queue_handler_lock);
1204 +               kfree(info);
1205 +               return 0;
1206 +       }
1207 +
1208 +       /* Bump dev refs so they don't vanish while packet is out */
1209 +       if (indev) dev_hold(indev);
1210 +       if (outdev) dev_hold(outdev);
1211 +
1212 +#ifdef CONFIG_BRIDGE_NETFILTER
1213 +       if (skb->nf_bridge) {
1214 +               physindev = skb->nf_bridge->physindev;
1215 +               if (physindev) dev_hold(physindev);
1216 +               physoutdev = skb->nf_bridge->physoutdev;
1217 +               if (physoutdev) dev_hold(physoutdev);
1218 +       }
1219 +#endif
1220 +
1221 +       status = queue_handler[pf].outfn(skb, info, queue_handler[pf].data);
1222 +       read_unlock(&queue_handler_lock);
1223 +
1224 +       if (status < 0) {
1225 +               /* James M doesn't say fuck enough. */
1226 +               if (indev) dev_put(indev);
1227 +               if (outdev) dev_put(outdev);
1228 +#ifdef CONFIG_BRIDGE_NETFILTER
1229 +               if (physindev) dev_put(physindev);
1230 +               if (physoutdev) dev_put(physoutdev);
1231 +#endif
1232 +               module_put(info->elem->owner);
1233 +               kfree(info);
1234 +               kfree_skb(skb);
1235 +               return 1;
1236 +       }
1237 +       return 1;
1238 +}
1239 +
1240 +int nf_hook_slow(int pf, unsigned int hook, struct sk_buff *skb,
1241 +                struct net_device *indev,
1242 +                struct net_device *outdev,
1243 +                int (*okfn)(struct sk_buff *),
1244 +                int hook_thresh)
1245 +{
1246 +       struct list_head *elem;
1247 +       unsigned int verdict;
1248 +       int ret = 0;
1249 +
1250 +       if (skb->ip_summed == CHECKSUM_HW) {
1251 +               if (outdev == NULL) {
1252 +                       skb->ip_summed = CHECKSUM_NONE;
1253 +               } else {
1254 +                       skb_checksum_help(skb);
1255 +               }
1256 +       }
1257 +
1258 +       /* We may already have this, but read-locks nest anyway */
1259 +       rcu_read_lock();
1260 +
1261 +#ifdef CONFIG_NETFILTER_DEBUG
1262 +       if (skb->nf_debug & (1 << hook)) {
1263 +               printk("nf_hook: hook %i already set.\n", hook);
1264 +               nf_dump_skb(pf, skb);
1265 +       }
1266 +       skb->nf_debug |= (1 << hook);
1267 +#endif
1268 +
1269 +       elem = &nf_hooks[pf][hook];
1270 + next_hook:
1271 +       verdict = nf_iterate(&nf_hooks[pf][hook], &skb, hook, indev,
1272 +                            outdev, &elem, okfn, hook_thresh);
1273 +       if (verdict == NF_QUEUE) {
1274 +               NFDEBUG("nf_hook: Verdict = QUEUE.\n");
1275 +               if (!nf_queue(skb, elem, pf, hook, indev, outdev, okfn))
1276 +                       goto next_hook;
1277 +       }
1278 +
1279 +       switch (verdict) {
1280 +       case NF_ACCEPT:
1281 +               ret = okfn(skb);
1282 +               break;
1283 +
1284 +       case NF_DROP:
1285 +               kfree_skb(skb);
1286 +               ret = -EPERM;
1287 +               break;
1288 +       }
1289 +
1290 +       rcu_read_unlock();
1291 +       return ret;
1292 +}
1293 +
1294 +/**
1295 + * nf_reinject - Reinject a packet from a queue handler
1296 + * @skb: the packet to be reinjected
1297 + * @info: info which was passed to the outfn() of the queue handler
1298 + * @verdict: verdict (NF_ACCEPT, ...) for this packet
1299 + *
1300 + * This is the function called by a queue handler to reinject a
1301 + * packet.
1302 + */
1303 +void nf_reinject(struct sk_buff *skb, struct nf_info *info,
1304 +                unsigned int verdict)
1305 +{
1306 +       struct list_head *elem = &info->elem->list;
1307 +       struct list_head *i;
1308 +
1309 +       rcu_read_lock();
1310 +
1311 +       /* Release those devices we held, or Alexey will kill me. */
1312 +       if (info->indev) dev_put(info->indev);
1313 +       if (info->outdev) dev_put(info->outdev);
1314 +#ifdef CONFIG_BRIDGE_NETFILTER
1315 +       if (skb->nf_bridge) {
1316 +               if (skb->nf_bridge->physindev)
1317 +                       dev_put(skb->nf_bridge->physindev);
1318 +               if (skb->nf_bridge->physoutdev)
1319 +                       dev_put(skb->nf_bridge->physoutdev);
1320 +       }
1321 +#endif
1322 +
1323 +       /* Drop reference to owner of hook which queued us. */
1324 +       module_put(info->elem->owner);
1325 +
1326 +       list_for_each_rcu(i, &nf_hooks[info->pf][info->hook]) {
1327 +               if (i == elem) 
1328 +                       break;
1329 +       }
1330 +  
1331 +       if (elem == &nf_hooks[info->pf][info->hook]) {
1332 +               /* The module which sent it to userspace is gone. */
1333 +               NFDEBUG("%s: module disappeared, dropping packet.\n",
1334 +                       __FUNCTION__);
1335 +               verdict = NF_DROP;
1336 +       }
1337 +
1338 +       /* Continue traversal iff userspace said ok... */
1339 +       if (verdict == NF_REPEAT) {
1340 +               elem = elem->prev;
1341 +               verdict = NF_ACCEPT;
1342 +       }
1343 +
1344 +       if (verdict == NF_ACCEPT) {
1345 +       next_hook:
1346 +               verdict = nf_iterate(&nf_hooks[info->pf][info->hook],
1347 +                                    &skb, info->hook, 
1348 +                                    info->indev, info->outdev, &elem,
1349 +                                    info->okfn, INT_MIN);
1350 +       }
1351 +
1352 +       switch (verdict) {
1353 +       case NF_ACCEPT:
1354 +               info->okfn(skb);
1355 +               break;
1356 +
1357 +       case NF_QUEUE:
1358 +               if (!nf_queue(skb, elem, info->pf, info->hook, 
1359 +                             info->indev, info->outdev, info->okfn))
1360 +                       goto next_hook;
1361 +               break;
1362 +       }
1363 +       rcu_read_unlock();
1364 +
1365 +       if (verdict == NF_DROP)
1366 +               kfree_skb(skb);
1367 +
1368 +       kfree(info);
1369 +       return;
1370 +}
1371 +
1372 +#ifdef CONFIG_INET
1373 +/* route_me_harder function, used by iptable_nat, iptable_mangle + ip_queue */
1374 +int ip_route_me_harder(struct sk_buff **pskb)
1375 +{
1376 +       struct iphdr *iph = (*pskb)->nh.iph;
1377 +       struct rtable *rt;
1378 +       struct flowi fl = {};
1379 +       struct dst_entry *odst;
1380 +       unsigned int hh_len;
1381 +
1382 +       /* some non-standard hacks like ipt_REJECT.c:send_reset() can cause
1383 +        * packets with foreign saddr to appear on the NF_IP_LOCAL_OUT hook.
1384 +        */
1385 +       if (inet_addr_type(iph->saddr) == RTN_LOCAL) {
1386 +               fl.nl_u.ip4_u.daddr = iph->daddr;
1387 +               fl.nl_u.ip4_u.saddr = iph->saddr;
1388 +               fl.nl_u.ip4_u.tos = RT_TOS(iph->tos);
1389 +               fl.oif = (*pskb)->sk ? (*pskb)->sk->sk_bound_dev_if : 0;
1390 +#ifdef CONFIG_IP_ROUTE_FWMARK
1391 +               fl.nl_u.ip4_u.fwmark = (*pskb)->nfmark;
1392 +#endif
1393 +               if (ip_route_output_key(&rt, &fl) != 0)
1394 +                       return -1;
1395 +
1396 +               /* Drop old route. */
1397 +               dst_release((*pskb)->dst);
1398 +               (*pskb)->dst = &rt->u.dst;
1399 +       } else {
1400 +               /* non-local src, find valid iif to satisfy
1401 +                * rp-filter when calling ip_route_input. */
1402 +               fl.nl_u.ip4_u.daddr = iph->saddr;
1403 +               if (ip_route_output_key(&rt, &fl) != 0)
1404 +                       return -1;
1405 +
1406 +               odst = (*pskb)->dst;
1407 +               if (ip_route_input(*pskb, iph->daddr, iph->saddr,
1408 +                                  RT_TOS(iph->tos), rt->u.dst.dev) != 0) {
1409 +                       dst_release(&rt->u.dst);
1410 +                       return -1;
1411 +               }
1412 +               dst_release(&rt->u.dst);
1413 +               dst_release(odst);
1414 +       }
1415 +       
1416 +       if ((*pskb)->dst->error)
1417 +               return -1;
1418 +
1419 +       /* Change in oif may mean change in hh_len. */
1420 +       hh_len = (*pskb)->dst->dev->hard_header_len;
1421 +       if (skb_headroom(*pskb) < hh_len) {
1422 +               struct sk_buff *nskb;
1423 +
1424 +               nskb = skb_realloc_headroom(*pskb, hh_len);
1425 +               if (!nskb) 
1426 +                       return -1;
1427 +               if ((*pskb)->sk)
1428 +                       skb_set_owner_w(nskb, (*pskb)->sk);
1429 +               kfree_skb(*pskb);
1430 +               *pskb = nskb;
1431 +       }
1432 +
1433 +       return 0;
1434 +}
1435 +
1436 +int skb_ip_make_writable(struct sk_buff **pskb, unsigned int writable_len)
1437 +{
1438 +       struct sk_buff *nskb;
1439 +       unsigned int iplen;
1440 +
1441 +       if (writable_len > (*pskb)->len)
1442 +               return 0;
1443 +
1444 +       /* Not exclusive use of packet?  Must copy. */
1445 +       if (skb_shared(*pskb) || skb_cloned(*pskb))
1446 +               goto copy_skb;
1447 +
1448 +       /* Alexey says IP hdr is always modifiable and linear, so ok. */
1449 +       if (writable_len <= (*pskb)->nh.iph->ihl*4)
1450 +               return 1;
1451 +
1452 +       iplen = writable_len - (*pskb)->nh.iph->ihl*4;
1453 +
1454 +       /* DaveM says protocol headers are also modifiable. */
1455 +       switch ((*pskb)->nh.iph->protocol) {
1456 +       case IPPROTO_TCP: {
1457 +               struct tcphdr hdr;
1458 +               if (skb_copy_bits(*pskb, (*pskb)->nh.iph->ihl*4,
1459 +                                 &hdr, sizeof(hdr)) != 0)
1460 +                       goto copy_skb;
1461 +               if (writable_len <= (*pskb)->nh.iph->ihl*4 + hdr.doff*4)
1462 +                       goto pull_skb;
1463 +               goto copy_skb;
1464 +       }
1465 +       case IPPROTO_UDP:
1466 +               if (writable_len<=(*pskb)->nh.iph->ihl*4+sizeof(struct udphdr))
1467 +                       goto pull_skb;
1468 +               goto copy_skb;
1469 +       case IPPROTO_ICMP:
1470 +               if (writable_len
1471 +                   <= (*pskb)->nh.iph->ihl*4 + sizeof(struct icmphdr))
1472 +                       goto pull_skb;
1473 +               goto copy_skb;
1474 +       /* Insert other cases here as desired */
1475 +       }
1476 +
1477 +copy_skb:
1478 +       nskb = skb_copy(*pskb, GFP_ATOMIC);
1479 +       if (!nskb)
1480 +               return 0;
1481 +       BUG_ON(skb_is_nonlinear(nskb));
1482 +
1483 +       /* Rest of kernel will get very unhappy if we pass it a
1484 +          suddenly-orphaned skbuff */
1485 +       if ((*pskb)->sk)
1486 +               skb_set_owner_w(nskb, (*pskb)->sk);
1487 +       kfree_skb(*pskb);
1488 +       *pskb = nskb;
1489 +       return 1;
1490 +
1491 +pull_skb:
1492 +       return pskb_may_pull(*pskb, writable_len);
1493 +}
1494 +EXPORT_SYMBOL(skb_ip_make_writable);
1495 +#endif /*CONFIG_INET*/
1496 +
1497 +
1498 +/* This does not belong here, but ipt_REJECT needs it if connection
1499 +   tracking in use: without this, connection may not be in hash table,
1500 +   and hence manufactured ICMP or RST packets will not be associated
1501 +   with it. */
1502 +void (*ip_ct_attach)(struct sk_buff *, struct nf_ct_info *);
1503 +
1504 +void __init netfilter_init(void)
1505 +{
1506 +       int i, h;
1507 +
1508 +       for (i = 0; i < NPROTO; i++) {
1509 +               for (h = 0; h < NF_MAX_HOOKS; h++)
1510 +                       INIT_LIST_HEAD(&nf_hooks[i][h]);
1511 +       }
1512 +}
1513 +
1514 +EXPORT_SYMBOL(ip_ct_attach);
1515 +EXPORT_SYMBOL(ip_route_me_harder);
1516 +EXPORT_SYMBOL(nf_getsockopt);
1517 +EXPORT_SYMBOL(nf_hook_slow);
1518 +EXPORT_SYMBOL(nf_hooks);
1519 +EXPORT_SYMBOL(nf_register_hook);
1520 +EXPORT_SYMBOL(nf_register_queue_handler);
1521 +EXPORT_SYMBOL(nf_register_sockopt);
1522 +EXPORT_SYMBOL(nf_reinject);
1523 +EXPORT_SYMBOL(nf_setsockopt);
1524 +EXPORT_SYMBOL(nf_unregister_hook);
1525 +EXPORT_SYMBOL(nf_unregister_queue_handler);
1526 +EXPORT_SYMBOL(nf_unregister_sockopt);
1527 diff -Nur linux-2.6.4-rc2.org/net/ipv4/netfilter/Kconfig linux-2.6.4-rc2/net/ipv4/netfilter/Kconfig
1528 --- linux-2.6.4-rc2.org/net/ipv4/netfilter/Kconfig      2004-03-04 06:16:58.000000000 +0000
1529 +++ linux-2.6.4-rc2/net/ipv4/netfilter/Kconfig  2004-03-05 09:56:07.000000000 +0000
1530 @@ -579,5 +579,89 @@
1531  
1532           To compile it as a module, choose M here.  If unsure, say N.
1533  
1534 +config IP_NF_TARGET_IPV4OPTSSTRIP
1535 +       tristate  'IPV4OPTSSTRIP target support'
1536 +       depends on IP_NF_MANGLE
1537 +         help
1538 +
1539 +config IP_NF_TARGET_TTL
1540 +       tristate  'TTL target support'
1541 +       depends on IP_NF_MANGLE
1542 +         help
1543 +
1544 +config IP_NF_MATCH_CONNLIMIT
1545 +       tristate  'Connections/IP limit match support'
1546 +       depends on IP_NF_IPTABLES
1547 +         help
1548 +
1549 +config IP_NF_MATCH_DSTLIMIT
1550 +       tristate  'dstlimit match support'
1551 +       depends on IP_NF_IPTABLES
1552 +         help
1553 +
1554 +config IP_NF_MATCH_FUZZY
1555 +       tristate  'fuzzy match support'
1556 +       depends on IP_NF_IPTABLES
1557 +         help
1558 +
1559 +config IP_NF_MATCH_IPV4OPTIONS
1560 +       tristate  'IPV4OPTIONS match support'
1561 +       depends on IP_NF_IPTABLES
1562 +         help
1563 +
1564 +config IP_NF_MATCH_MPORT
1565 +       tristate  'Multiple port with ranges match support'
1566 +       depends on IP_NF_IPTABLES
1567 +         help
1568 +
1569 +config IP_NF_MATCH_NTH
1570 +       tristate  'Nth match support'
1571 +       depends on IP_NF_IPTABLES
1572 +         help
1573 +
1574 +config IP_NF_MATCH_QUOTA
1575 +       tristate  'quota match support'
1576 +       depends on IP_NF_IPTABLES
1577 +         help
1578 +
1579 +config IP_NF_TARGET_NOTRACK
1580 +       tristate  'NOTRACK target support'
1581 +       depends on IP_NF_RAW
1582 +       help
1583 +         The NOTRACK target allows a select rule to specify
1584 +         which packets *not* to enter the conntrack/NAT
1585 +         subsystem with all the consequences (no ICMP error tracking,
1586 +         no protocol helpers for the selected packets).
1587 +       
1588 +         If you want to compile it as a module, say M here and read
1589 +         <file:Documentation/modules.txt>.  If unsure, say `N'.
1590 +
1591 +config IP_NF_RAW
1592 +       tristate  'raw table support (required for NOTRACK/TRACE)'
1593 +       depends on IP_NF_IPTABLES
1594 +       help
1595 +         This option adds a `raw' table to iptables. This table is the very
1596 +         first in the netfilter framework and hooks in at the PREROUTING
1597 +         and OUTPUT chains.
1598 +       
1599 +         If you want to compile it as a module, say M here and read
1600 +         <file:Documentation/modules.txt>.  If unsure, say `N'.
1601 +         help
1602 +
1603 +config IP_NF_MATCH_REALM
1604 +       tristate  'realm match support'
1605 +       depends on IP_NF_IPTABLES && NET_CLS_ROUTE
1606 +         help
1607 +
1608 +config IP_NF_MATCH_SCTP
1609 +       tristate  'SCTP protocol match support'
1610 +       depends on IP_NF_IPTABLES
1611 +         help
1612 +
1613 +config IP_NF_MATCH_U32
1614 +       tristate  'U32 match support'
1615 +       depends on IP_NF_IPTABLES
1616 +         help
1617 +
1618  endmenu
1619  
1620 diff -Nur linux-2.6.4-rc2.org/net/ipv4/netfilter/Makefile linux-2.6.4-rc2/net/ipv4/netfilter/Makefile
1621 --- linux-2.6.4-rc2.org/net/ipv4/netfilter/Makefile     2004-03-04 06:16:38.000000000 +0000
1622 +++ linux-2.6.4-rc2/net/ipv4/netfilter/Makefile 2004-03-05 09:56:07.000000000 +0000
1623 @@ -38,19 +38,33 @@
1624  obj-$(CONFIG_IP_NF_FILTER) += iptable_filter.o
1625  obj-$(CONFIG_IP_NF_MANGLE) += iptable_mangle.o
1626  obj-$(CONFIG_IP_NF_NAT) += iptable_nat.o
1627 +obj-$(CONFIG_IP_NF_RAW) += iptable_raw.o
1628  
1629  # matches
1630  obj-$(CONFIG_IP_NF_MATCH_HELPER) += ipt_helper.o
1631  obj-$(CONFIG_IP_NF_MATCH_LIMIT) += ipt_limit.o
1632 +obj-$(CONFIG_IP_NF_MATCH_SCTP) += ipt_sctp.o
1633 +obj-$(CONFIG_IP_NF_MATCH_QUOTA) += ipt_quota.o
1634 +obj-$(CONFIG_IP_NF_MATCH_DSTLIMIT) += ipt_dstlimit.o
1635  obj-$(CONFIG_IP_NF_MATCH_MARK) += ipt_mark.o
1636  obj-$(CONFIG_IP_NF_MATCH_MAC) += ipt_mac.o
1637  obj-$(CONFIG_IP_NF_MATCH_IPRANGE) += ipt_iprange.o
1638  
1639  obj-$(CONFIG_IP_NF_MATCH_PKTTYPE) += ipt_pkttype.o
1640  obj-$(CONFIG_IP_NF_MATCH_MULTIPORT) += ipt_multiport.o
1641 +
1642 +obj-$(CONFIG_IP_NF_MATCH_MPORT) += ipt_mport.o
1643 +
1644  obj-$(CONFIG_IP_NF_MATCH_OWNER) += ipt_owner.o
1645  obj-$(CONFIG_IP_NF_MATCH_TOS) += ipt_tos.o
1646  
1647 +obj-$(CONFIG_IP_NF_MATCH_NTH) += ipt_nth.o
1648 +
1649 +obj-$(CONFIG_IP_NF_MATCH_IPV4OPTIONS) += ipt_ipv4options.o
1650 +
1651 +
1652 +obj-$(CONFIG_IP_NF_MATCH_FUZZY) += ipt_fuzzy.o
1653 +
1654  obj-$(CONFIG_IP_NF_MATCH_RECENT) += ipt_recent.o
1655  
1656  obj-$(CONFIG_IP_NF_MATCH_ECN) += ipt_ecn.o
1657 @@ -59,10 +73,15 @@
1658  
1659  obj-$(CONFIG_IP_NF_MATCH_LENGTH) += ipt_length.o
1660  
1661 +obj-$(CONFIG_IP_NF_MATCH_U32) += ipt_u32.o
1662 +
1663 +
1664  obj-$(CONFIG_IP_NF_MATCH_TTL) += ipt_ttl.o
1665  obj-$(CONFIG_IP_NF_MATCH_STATE) += ipt_state.o
1666 +obj-$(CONFIG_IP_NF_MATCH_CONNLIMIT) += ipt_connlimit.o
1667  obj-$(CONFIG_IP_NF_MATCH_CONNTRACK) += ipt_conntrack.o
1668  obj-$(CONFIG_IP_NF_MATCH_TCPMSS) += ipt_tcpmss.o
1669 +obj-$(CONFIG_IP_NF_MATCH_REALM) += ipt_realm.o
1670  
1671  obj-$(CONFIG_IP_NF_MATCH_PHYSDEV) += ipt_physdev.o
1672  
1673 @@ -79,8 +98,11 @@
1674  obj-$(CONFIG_IP_NF_TARGET_CLASSIFY) += ipt_CLASSIFY.o
1675  obj-$(CONFIG_IP_NF_NAT_SNMP_BASIC) += ip_nat_snmp_basic.o
1676  obj-$(CONFIG_IP_NF_TARGET_LOG) += ipt_LOG.o
1677 +obj-$(CONFIG_IP_NF_TARGET_TTL) += ipt_TTL.o
1678 +obj-$(CONFIG_IP_NF_TARGET_IPV4OPTSSTRIP) += ipt_IPV4OPTSSTRIP.o
1679  obj-$(CONFIG_IP_NF_TARGET_ULOG) += ipt_ULOG.o
1680  obj-$(CONFIG_IP_NF_TARGET_TCPMSS) += ipt_TCPMSS.o
1681 +obj-$(CONFIG_IP_NF_TARGET_NOTRACK) += ipt_NOTRACK.o
1682  
1683  # generic ARP tables
1684  obj-$(CONFIG_IP_NF_ARPTABLES) += arp_tables.o
1685 diff -Nur linux-2.6.4-rc2.org/net/ipv4/netfilter/ip_conntrack_core.c linux-2.6.4-rc2/net/ipv4/netfilter/ip_conntrack_core.c
1686 --- linux-2.6.4-rc2.org/net/ipv4/netfilter/ip_conntrack_core.c  2004-03-04 06:16:34.000000000 +0000
1687 +++ linux-2.6.4-rc2/net/ipv4/netfilter/ip_conntrack_core.c      2004-03-05 09:55:23.000000000 +0000
1688 @@ -15,6 +15,8 @@
1689   * 16 Jul 2002: Harald Welte <laforge@gnumonks.org>
1690   *     - add usage/reference counts to ip_conntrack_expect
1691   *     - export ip_conntrack[_expect]_{find_get,put} functions
1692 + * 05 Aug 2002: Harald Welte <laforge@gnumonks.org>
1693 + *     - added DocBook-style comments for public API
1694   * */
1695  
1696  #include <linux/config.h>
1697 @@ -67,6 +69,7 @@
1698  static atomic_t ip_conntrack_count = ATOMIC_INIT(0);
1699  struct list_head *ip_conntrack_hash;
1700  static kmem_cache_t *ip_conntrack_cachep;
1701 +struct ip_conntrack ip_conntrack_untracked;
1702  
1703  extern struct ip_conntrack_protocol ip_conntrack_generic_protocol;
1704  
1705 @@ -89,6 +92,10 @@
1706         return p;
1707  }
1708  
1709 +/**
1710 + * ip_ct_find_proto - Find layer 4 protocol helper for given protocol number
1711 + * @protocol: protocol number
1712 + */
1713  struct ip_conntrack_protocol *ip_ct_find_proto(u_int8_t protocol)
1714  {
1715         struct ip_conntrack_protocol *p;
1716 @@ -112,6 +119,11 @@
1717  static int ip_conntrack_hash_rnd_initted;
1718  static unsigned int ip_conntrack_hash_rnd;
1719  
1720 +/**
1721 + * hash_conntrack - Calculate the position of an entry in the connection 
1722 + * tracking table.
1723 + * @tuple: conntrack tuple which we want to calculate the hash position
1724 + */
1725  static u_int32_t
1726  hash_conntrack(const struct ip_conntrack_tuple *tuple)
1727  {
1728 @@ -124,6 +136,19 @@
1729                              ip_conntrack_hash_rnd) % ip_conntrack_htable_size);
1730  }
1731  
1732 +/**
1733 + * get_tuple - set all the fields of a tuple which is passed as parameter
1734 + * given a network buffer.
1735 + * @iph:pointer an IP header. 
1736 + * @skb:network buffer for which we want to generate the tuple
1737 + * @dataoff: FIXME: Deprecated?
1738 + * @tuple: tuple which will be generate. Used as return parameter.
1739 + * @protocol: structure which contains pointer to protocol specific functions.
1740 + *
1741 + * Note: This function doesn't allocate space for the tuple passed as 
1742 + * parameter. The function pkt_to_packet which set all the protocol specific
1743 + * fields of a given tuple.
1744 + */
1745  int
1746  get_tuple(const struct iphdr *iph,
1747           const struct sk_buff *skb,
1748 @@ -145,6 +170,15 @@
1749         return protocol->pkt_to_tuple(skb, dataoff, tuple);
1750  }
1751  
1752 +/**
1753 + * invert_tuple - Returns the inverse of a given tuple. It is used to 
1754 + * calculate the tuple which represents the other sense of the flow
1755 + * of a connection.
1756 + * @inverse: the inverted tuple. Use as return value.
1757 + * @orig: the original tuple which will be inverted.
1758 + * @protocol: a pointer to the protocol structure which contains all the
1759 + * specifical functions available for this tuple.
1760 + */
1761  static int
1762  invert_tuple(struct ip_conntrack_tuple *inverse,
1763              const struct ip_conntrack_tuple *orig,
1764 @@ -160,7 +194,15 @@
1765  
1766  /* ip_conntrack_expect helper functions */
1767  
1768 -/* Compare tuple parts depending on mask. */
1769 +/**
1770 + * expect_cmp - compare a tuple with a expectation depending on a mask
1771 + * @i: pointer to an expectation.
1772 + * @tuple: tuple which will be compared with the expectation tuple.
1773 + *
1774 + * Actually the tuple field of an expectation is compared with a tuple
1775 + * This function is used by LIST_FIND to find a expectation which match a te
1776 + * given tuple.
1777 + */
1778  static inline int expect_cmp(const struct ip_conntrack_expect *i,
1779                              const struct ip_conntrack_tuple *tuple)
1780  {
1781 @@ -168,6 +210,10 @@
1782         return ip_ct_tuple_mask_cmp(tuple, &i->tuple, &i->mask);
1783  }
1784  
1785 +/**
1786 + * destroy_expect - Release all the resources allocated by an expectation.
1787 + * @exp: pointer to the expectation which we want to release.
1788 + */
1789  static void
1790  destroy_expect(struct ip_conntrack_expect *exp)
1791  {
1792 @@ -178,7 +224,11 @@
1793         kfree(exp);
1794  }
1795  
1796 -
1797 +/**
1798 + * ip_conntrack_expect_put - it decrements the counter of use related 
1799 + * associated to an expectation and it calls destroy_expect.
1800 + * @exp: pointer to the expectation which we want to release.
1801 + */
1802  inline void ip_conntrack_expect_put(struct ip_conntrack_expect *exp)
1803  {
1804         IP_NF_ASSERT(exp);
1805 @@ -198,7 +248,14 @@
1806                          struct ip_conntrack_expect *, tuple);
1807  }
1808  
1809 -/* Find a expectation corresponding to a tuple. */
1810 +/**
1811 + * ip_conntrack_find_get - find conntrack according to tuple
1812 + * @tuple: conntrack tuple for which we search conntrack
1813 + * @ignored_conntrack: ignore this conntrack during search
1814 + *
1815 + * This function increments the reference count of the found
1816 + * conntrack (if any).
1817 + */
1818  struct ip_conntrack_expect *
1819  ip_conntrack_expect_find_get(const struct ip_conntrack_tuple *tuple)
1820  {
1821 @@ -381,7 +438,14 @@
1822         return h;
1823  }
1824  
1825 -/* Find a connection corresponding to a tuple. */
1826 +/**
1827 + * ip_conntrack_find_get - find conntrack according to tuple
1828 + * @tuple: conntrack tuple for which we search conntrack
1829 + * @ignored_conntrack: ignore this conntrack during search
1830 + *
1831 + * This function increments the reference count of the found
1832 + * conntrack (if any).
1833 + */
1834  struct ip_conntrack_tuple_hash *
1835  ip_conntrack_find_get(const struct ip_conntrack_tuple *tuple,
1836                       const struct ip_conntrack *ignored_conntrack)
1837 @@ -409,7 +473,14 @@
1838         return ct;
1839  }
1840  
1841 -/* Return conntrack and conntrack_info given skb->nfct->master */
1842 +/**
1843 + * ip_conntrack_get - Return conntrack and conntrack_info for given skb
1844 + * @skb: skb for which we want to find conntrack and conntrack_info
1845 + * @ctinfo: pointer to ctinfo, used as return value
1846 + *
1847 + * This function resolves the respective conntrack and conntrack_info
1848 + * structures for the connection this packet (skb) is part of.
1849 + */
1850  struct ip_conntrack *
1851  ip_conntrack_get(struct sk_buff *skb, enum ip_conntrack_info *ctinfo)
1852  {
1853 @@ -479,8 +550,14 @@
1854         return NF_DROP;
1855  }
1856  
1857 -/* Returns true if a connection correspondings to the tuple (required
1858 -   for NAT). */
1859 +/**
1860 + * ip_conntrack_tuple_taken - Find out if tuple is already in use
1861 + * @tuple: tuple to be used for this test
1862 + * @ignored_conntrack: conntrack which is excluded from result
1863 + *
1864 + * This function is called by the NAT code in order to find out if
1865 + * a particular tuple is already in use by some connection.
1866 + */
1867  int
1868  ip_conntrack_tuple_taken(const struct ip_conntrack_tuple *tuple,
1869                          const struct ip_conntrack *ignored_conntrack)
1870 @@ -606,7 +683,13 @@
1871  {
1872         return ip_ct_tuple_mask_cmp(rtuple, &i->tuple, &i->mask);
1873  }
1874 -
1875 +/**
1876 + * ip_ct_find_helper - Find application helper according to tuple
1877 + * @tuple: tuple for which helper needs to be found
1878 + *
1879 + * This function is used to determine if any registered conntrack helper
1880 + * is to be used for the given tuple.
1881 + */
1882  struct ip_conntrack_helper *ip_ct_find_helper(const struct ip_conntrack_tuple *tuple)
1883  {
1884         return LIST_FIND(&helpers, helper_cmp,
1885 @@ -691,42 +774,50 @@
1886                              struct ip_conntrack_expect *, tuple);
1887         READ_UNLOCK(&ip_conntrack_expect_tuple_lock);
1888  
1889 -       /* If master is not in hash table yet (ie. packet hasn't left
1890 -          this machine yet), how can other end know about expected?
1891 -          Hence these are not the droids you are looking for (if
1892 -          master ct never got confirmed, we'd hold a reference to it
1893 -          and weird things would happen to future packets). */
1894 -       if (expected && !is_confirmed(expected->expectant))
1895 -               expected = NULL;
1896 -
1897 -       /* Look up the conntrack helper for master connections only */
1898 -       if (!expected)
1899 -               conntrack->helper = ip_ct_find_helper(&repl_tuple);
1900 -
1901 -       /* If the expectation is dying, then this is a loser. */
1902 -       if (expected
1903 -           && expected->expectant->helper->timeout
1904 -           && ! del_timer(&expected->timeout))
1905 -               expected = NULL;
1906 -
1907         if (expected) {
1908 -               DEBUGP("conntrack: expectation arrives ct=%p exp=%p\n",
1909 -                       conntrack, expected);
1910 -               /* Welcome, Mr. Bond.  We've been expecting you... */
1911 -               IP_NF_ASSERT(master_ct(conntrack));
1912 -               __set_bit(IPS_EXPECTED_BIT, &conntrack->status);
1913 -               conntrack->master = expected;
1914 -               expected->sibling = conntrack;
1915 -               LIST_DELETE(&ip_conntrack_expect_list, expected);
1916 -               expected->expectant->expecting--;
1917 -               nf_conntrack_get(&master_ct(conntrack)->infos[0]);
1918 -       }
1919 -       atomic_inc(&ip_conntrack_count);
1920 +               /* If master is not in hash table yet (ie. packet hasn't left
1921 +                  this machine yet), how can other end know about expected?
1922 +                  Hence these are not the droids you are looking for (if
1923 +                  master ct never got confirmed, we'd hold a reference to it
1924 +                  and weird things would happen to future packets). */
1925 +               if (!is_confirmed(expected->expectant)) {
1926 +                       
1927 +                       conntrack->helper = ip_ct_find_helper(&repl_tuple);
1928 +                       goto end;
1929 +               }
1930 +
1931 +               /* Expectation is dying... */
1932 +               if (expected->expectant->helper->timeout
1933 +                   && ! del_timer(&expected->timeout)) {
1934 +                       goto end;       
1935 +               }
1936 +
1937 +                DEBUGP("conntrack: expectation arrives ct=%p exp=%p\n",
1938 +                       conntrack, expected);
1939 +                /* Welcome, Mr. Bond.  We've been expecting you... */
1940 +                IP_NF_ASSERT(master_ct(conntrack));
1941 +                __set_bit(IPS_EXPECTED_BIT, &conntrack->status);
1942 +                conntrack->master = expected;
1943 +                expected->sibling = conntrack;
1944 +                LIST_DELETE(&ip_conntrack_expect_list, expected);
1945 +                expected->expectant->expecting--;
1946 +                nf_conntrack_get(&master_ct(conntrack)->infos[0]);
1947 +
1948 +               /* this is a braindead... --pablo */
1949 +               atomic_inc(&ip_conntrack_count);
1950 +               WRITE_UNLOCK(&ip_conntrack_lock);
1951 +
1952 +               if (expected->expectfn)
1953 +                       expected->expectfn(conntrack);
1954 +
1955 +               goto ret;
1956 +        } else 
1957 +                conntrack->helper = ip_ct_find_helper(&repl_tuple);
1958 +
1959 +end:   atomic_inc(&ip_conntrack_count);
1960         WRITE_UNLOCK(&ip_conntrack_lock);
1961  
1962 -       if (expected && expected->expectfn)
1963 -               expected->expectfn(conntrack);
1964 -       return &conntrack->tuplehash[IP_CT_DIR_ORIGINAL];
1965 +ret:   return &conntrack->tuplehash[IP_CT_DIR_ORIGINAL];
1966  }
1967  
1968  /* On success, returns conntrack ptr, sets skb->nfct and ctinfo */
1969 @@ -794,6 +885,15 @@
1970         int set_reply;
1971         int ret;
1972  
1973 +       /* Never happen */
1974 +       if ((*pskb)->nh.iph->frag_off & htons(IP_OFFSET)) {
1975 +               if (net_ratelimit()) {
1976 +               printk(KERN_ERR "ip_conntrack_in: Frag of proto %u (hook=%u)\n",
1977 +                      (*pskb)->nh.iph->protocol, hooknum);
1978 +               }
1979 +               return NF_DROP;
1980 +       }
1981 +
1982         /* FIXME: Do this right please. --RR */
1983         (*pskb)->nfcache |= NFC_UNKNOWN;
1984  
1985 @@ -812,18 +912,10 @@
1986         }
1987  #endif
1988  
1989 -       /* Previously seen (loopback)?  Ignore.  Do this before
1990 -           fragment check. */
1991 +       /* Previously seen (loopback or untracked)?  Ignore. */
1992         if ((*pskb)->nfct)
1993                 return NF_ACCEPT;
1994  
1995 -       /* Gather fragments. */
1996 -       if ((*pskb)->nh.iph->frag_off & htons(IP_MF|IP_OFFSET)) {
1997 -               *pskb = ip_ct_gather_frags(*pskb);
1998 -               if (!*pskb)
1999 -                       return NF_STOLEN;
2000 -       }
2001 -
2002         proto = ip_ct_find_proto((*pskb)->nh.iph->protocol);
2003  
2004         /* It may be an icmp error... */
2005 @@ -900,6 +992,14 @@
2006         return ip_ct_tuple_mask_cmp(&i->tuple, tuple, &intersect_mask);
2007  }
2008  
2009 +/**
2010 + * ip_conntrack_unexpect_related - Unexpect a related connection
2011 + * @expect: expecattin to be removed
2012 + *
2013 + * This function removes an existing expectation, that has not yet been
2014 + * confirmed (i.e. expectation was issued, but expected connection didn't
2015 + * arrive yet)
2016 + */
2017  inline void ip_conntrack_unexpect_related(struct ip_conntrack_expect *expect)
2018  {
2019         WRITE_LOCK(&ip_conntrack_lock);
2020 @@ -917,7 +1017,20 @@
2021         WRITE_UNLOCK(&ip_conntrack_lock);
2022  }
2023  
2024 -/* Add a related connection. */
2025 +/**
2026 + * ip_conntrack_expect_related - Expect a related connection
2027 + * @related_to: master conntrack
2028 + * @expect: expectation with all values filled in
2029 + *
2030 + * This function is called by conntrack application helpers who
2031 + * have detected that the control (master) connection is just about
2032 + * to negotiate a related slave connection. 
2033 + *
2034 + * Note: This function allocates it's own struct ip_conntrack_expect,
2035 + * copying the values from the 'expect' parameter.  Thus, 'expect' can
2036 + * be allocated on the stack and does not need to be valid after this
2037 + * function returns.
2038 + */
2039  int ip_conntrack_expect_related(struct ip_conntrack *related_to,
2040                                 struct ip_conntrack_expect *expect)
2041  {
2042 @@ -1047,7 +1160,15 @@
2043         return ret;
2044  }
2045  
2046 -/* Change tuple in an existing expectation */
2047 +/**
2048 + * ip_conntrack_change_expect - Change tuple in existing expectation
2049 + * @expect: expectation which is to be changed
2050 + * @newtuple: new tuple for expect
2051 + *
2052 + * This function is mostly called by NAT application helpers, who want to
2053 + * change an expectation issued by their respective conntrack application
2054 + * helper counterpart.
2055 + */
2056  int ip_conntrack_change_expect(struct ip_conntrack_expect *expect,
2057                                struct ip_conntrack_tuple *newtuple)
2058  {
2059 @@ -1088,8 +1209,15 @@
2060         return ret;
2061  }
2062  
2063 -/* Alter reply tuple (maybe alter helper).  If it's already taken,
2064 -   return 0 and don't do alteration. */
2065 +/**
2066 + * ip_conntrack_alter_reply - Alter reply tuple of conntrack
2067 + * @conntrack: conntrack whose reply tuple we want to alter
2068 + * @newreply: designated reply tuple for this conntrack
2069 + *
2070 + * This function alters the reply tuple of a conntrack to the given
2071 + * newreply tuple.  If this newreply tuple is already taken, return 0
2072 + * and don't do alteration
2073 + */
2074  int ip_conntrack_alter_reply(struct ip_conntrack *conntrack,
2075                              const struct ip_conntrack_tuple *newreply)
2076  {
2077 @@ -1114,6 +1242,13 @@
2078         return 1;
2079  }
2080  
2081 +/**
2082 + * ip_conntrack_helper_register - Register a conntrack application helper
2083 + * @me: structure describing the helper
2084 + *
2085 + * This function is called by conntrack application helpers to register
2086 + * themselves with the conntrack core.
2087 + */
2088  int ip_conntrack_helper_register(struct ip_conntrack_helper *me)
2089  {
2090         WRITE_LOCK(&ip_conntrack_lock);
2091 @@ -1135,6 +1270,13 @@
2092         return 0;
2093  }
2094  
2095 +/**
2096 + * ip_conntrack_helper_unregister - Unregister a conntrack application helper
2097 + * @me: structure describing the helper
2098 + *
2099 + * This function is called by conntrack application helpers to unregister
2100 + * themselvers from the conntrack core.
2101 + */
2102  void ip_conntrack_helper_unregister(struct ip_conntrack_helper *me)
2103  {
2104         unsigned int i;
2105 @@ -1153,7 +1295,14 @@
2106         synchronize_net();
2107  }
2108  
2109 -/* Refresh conntrack for this many jiffies. */
2110 +/**
2111 + * ip_ct_refresh - Refresh conntrack timer for given conntrack
2112 + * @ct: conntrack which we want to refresh
2113 + * @extra_jiffies: number of jiffies to add
2114 + *
2115 + * This function is called by protocol helpers and application helpers in
2116 + * order to change the expiration timer of a conntrack entry.
2117 + */
2118  void ip_ct_refresh(struct ip_conntrack *ct, unsigned long extra_jiffies)
2119  {
2120         IP_NF_ASSERT(ct->timeout.data == (unsigned long)ct);
2121 @@ -1172,7 +1321,16 @@
2122         WRITE_UNLOCK(&ip_conntrack_lock);
2123  }
2124  
2125 -/* Returns new sk_buff, or NULL */
2126 +
2127 +/**
2128 + * ip_ct_gather_frags - Gather fragments of a particular skb
2129 + * @skb: pointer to sk_buff of fragmented IP packet
2130 + *
2131 + * This code is just a wrapper around the defragmentation code in the core IPv4
2132 + * stack.  It also takes care of nonlinear skb's.
2133 + *
2134 + * Returns new sk_buff, or NULL
2135 + */
2136  struct sk_buff *
2137  ip_ct_gather_frags(struct sk_buff *skb)
2138  {
2139 @@ -1256,6 +1414,16 @@
2140         return h;
2141  }
2142  
2143 +/**
2144 + * ip_ct_selective_cleanup - Selectively delete a set of conntrack entries
2145 + * @kill: callback function selecting which entries to delete
2146 + * @data: opaque data pointer, becomes 2nd argument for kill function
2147 + *
2148 + * This function can be used to selectively delete elements of the conntrack
2149 + * hashtable.  The function iterates over the list of conntrack entries and
2150 + * calls the 'kill' function for every entry.  If the return value is true,
2151 + * the connection is deleted (death_by_timeout).
2152 + */
2153  void
2154  ip_ct_selective_cleanup(int (*kill)(const struct ip_conntrack *i, void *data),
2155                         void *data)
2156 @@ -1422,6 +1590,18 @@
2157  
2158         /* For use by ipt_REJECT */
2159         ip_ct_attach = ip_conntrack_attach;
2160 +
2161 +       /* Set up fake conntrack:
2162 +           - to never be deleted, not in any hashes */
2163 +       atomic_set(&ip_conntrack_untracked.ct_general.use, 1);
2164 +       /*  - and look it like as a confirmed connection */
2165 +       set_bit(IPS_CONFIRMED_BIT, &ip_conntrack_untracked.status);
2166 +       /*  - and prepare the ctinfo field for REJECT & NAT. */
2167 +       ip_conntrack_untracked.infos[IP_CT_NEW].master =
2168 +       ip_conntrack_untracked.infos[IP_CT_RELATED].master =
2169 +       ip_conntrack_untracked.infos[IP_CT_RELATED + IP_CT_IS_REPLY].master = 
2170 +                       &ip_conntrack_untracked.ct_general;
2171 +
2172         return ret;
2173  
2174  err_free_hash:
2175 diff -Nur linux-2.6.4-rc2.org/net/ipv4/netfilter/ip_conntrack_core.c.orig linux-2.6.4-rc2/net/ipv4/netfilter/ip_conntrack_core.c.orig
2176 --- linux-2.6.4-rc2.org/net/ipv4/netfilter/ip_conntrack_core.c.orig     1970-01-01 00:00:00.000000000 +0000
2177 +++ linux-2.6.4-rc2/net/ipv4/netfilter/ip_conntrack_core.c.orig 2004-03-05 09:55:06.000000000 +0000
2178 @@ -0,0 +1,1599 @@
2179 +/* Connection state tracking for netfilter.  This is separated from,
2180 +   but required by, the NAT layer; it can also be used by an iptables
2181 +   extension. */
2182 +
2183 +/* (C) 1999-2001 Paul `Rusty' Russell  
2184 + * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org>
2185 + *
2186 + * This program is free software; you can redistribute it and/or modify
2187 + * it under the terms of the GNU General Public License version 2 as
2188 + * published by the Free Software Foundation.
2189 + *
2190 + * 23 Apr 2001: Harald Welte <laforge@gnumonks.org>
2191 + *     - new API and handling of conntrack/nat helpers
2192 + *     - now capable of multiple expectations for one master
2193 + * 16 Jul 2002: Harald Welte <laforge@gnumonks.org>
2194 + *     - add usage/reference counts to ip_conntrack_expect
2195 + *     - export ip_conntrack[_expect]_{find_get,put} functions
2196 + * 05 Aug 2002: Harald Welte <laforge@gnumonks.org>
2197 + *     - added DocBook-style comments for public API
2198 + * */
2199 +
2200 +#include <linux/config.h>
2201 +#include <linux/types.h>
2202 +#include <linux/icmp.h>
2203 +#include <linux/ip.h>
2204 +#include <linux/netfilter.h>
2205 +#include <linux/netfilter_ipv4.h>
2206 +#include <linux/module.h>
2207 +#include <linux/skbuff.h>
2208 +#include <linux/proc_fs.h>
2209 +#include <linux/vmalloc.h>
2210 +#include <net/checksum.h>
2211 +#include <linux/stddef.h>
2212 +#include <linux/sysctl.h>
2213 +#include <linux/slab.h>
2214 +#include <linux/random.h>
2215 +#include <linux/jhash.h>
2216 +/* For ERR_PTR().  Yeah, I know... --RR */
2217 +#include <linux/fs.h>
2218 +
2219 +/* This rwlock protects the main hash table, protocol/helper/expected
2220 +   registrations, conntrack timers*/
2221 +#define ASSERT_READ_LOCK(x) MUST_BE_READ_LOCKED(&ip_conntrack_lock)
2222 +#define ASSERT_WRITE_LOCK(x) MUST_BE_WRITE_LOCKED(&ip_conntrack_lock)
2223 +
2224 +#include <linux/netfilter_ipv4/ip_conntrack.h>
2225 +#include <linux/netfilter_ipv4/ip_conntrack_protocol.h>
2226 +#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
2227 +#include <linux/netfilter_ipv4/ip_conntrack_core.h>
2228 +#include <linux/netfilter_ipv4/listhelp.h>
2229 +
2230 +#define IP_CONNTRACK_VERSION   "2.1"
2231 +
2232 +#if 0
2233 +#define DEBUGP printk
2234 +#else
2235 +#define DEBUGP(format, args...)
2236 +#endif
2237 +
2238 +DECLARE_RWLOCK(ip_conntrack_lock);
2239 +DECLARE_RWLOCK(ip_conntrack_expect_tuple_lock);
2240 +
2241 +void (*ip_conntrack_destroyed)(struct ip_conntrack *conntrack) = NULL;
2242 +LIST_HEAD(ip_conntrack_expect_list);
2243 +LIST_HEAD(protocol_list);
2244 +static LIST_HEAD(helpers);
2245 +unsigned int ip_conntrack_htable_size = 0;
2246 +int ip_conntrack_max;
2247 +static atomic_t ip_conntrack_count = ATOMIC_INIT(0);
2248 +struct list_head *ip_conntrack_hash;
2249 +static kmem_cache_t *ip_conntrack_cachep;
2250 +
2251 +extern struct ip_conntrack_protocol ip_conntrack_generic_protocol;
2252 +
2253 +static inline int proto_cmpfn(const struct ip_conntrack_protocol *curr,
2254 +                             u_int8_t protocol)
2255 +{
2256 +       return protocol == curr->proto;
2257 +}
2258 +
2259 +struct ip_conntrack_protocol *__ip_ct_find_proto(u_int8_t protocol)
2260 +{
2261 +       struct ip_conntrack_protocol *p;
2262 +
2263 +       MUST_BE_READ_LOCKED(&ip_conntrack_lock);
2264 +       p = LIST_FIND(&protocol_list, proto_cmpfn,
2265 +                     struct ip_conntrack_protocol *, protocol);
2266 +       if (!p)
2267 +               p = &ip_conntrack_generic_protocol;
2268 +
2269 +       return p;
2270 +}
2271 +
2272 +/**
2273 + * ip_ct_find_proto - Find layer 4 protocol helper for given protocol number
2274 + * @protocol: protocol number
2275 + */
2276 +struct ip_conntrack_protocol *ip_ct_find_proto(u_int8_t protocol)
2277 +{
2278 +       struct ip_conntrack_protocol *p;
2279 +
2280 +       READ_LOCK(&ip_conntrack_lock);
2281 +       p = __ip_ct_find_proto(protocol);
2282 +       READ_UNLOCK(&ip_conntrack_lock);
2283 +       return p;
2284 +}
2285 +
2286 +inline void 
2287 +ip_conntrack_put(struct ip_conntrack *ct)
2288 +{
2289 +       IP_NF_ASSERT(ct);
2290 +       IP_NF_ASSERT(ct->infos[0].master);
2291 +       /* nf_conntrack_put wants to go via an info struct, so feed it
2292 +           one at random. */
2293 +       nf_conntrack_put(&ct->infos[0]);
2294 +}
2295 +
2296 +static int ip_conntrack_hash_rnd_initted;
2297 +static unsigned int ip_conntrack_hash_rnd;
2298 +
2299 +/**
2300 + * hash_conntrack - Calculate the position of an entry in the connection 
2301 + * tracking table.
2302 + * @tuple: conntrack tuple which we want to calculate the hash position
2303 + */
2304 +static u_int32_t
2305 +hash_conntrack(const struct ip_conntrack_tuple *tuple)
2306 +{
2307 +#if 0
2308 +       dump_tuple(tuple);
2309 +#endif
2310 +       return (jhash_3words(tuple->src.ip,
2311 +                            (tuple->dst.ip ^ tuple->dst.protonum),
2312 +                            (tuple->src.u.all | (tuple->dst.u.all << 16)),
2313 +                            ip_conntrack_hash_rnd) % ip_conntrack_htable_size);
2314 +}
2315 +
2316 +/**
2317 + * get_tuple - set all the fields of a tuple which is passed as parameter
2318 + * given a network buffer.
2319 + * @iph:pointer an IP header. 
2320 + * @skb:network buffer for which we want to generate the tuple
2321 + * @dataoff: FIXME: Deprecated?
2322 + * @tuple: tuple which will be generate. Used as return parameter.
2323 + * @protocol: structure which contains pointer to protocol specific functions.
2324 + *
2325 + * Note: This function doesn't allocate space for the tuple passed as 
2326 + * parameter. The function pkt_to_packet which set all the protocol specific
2327 + * fields of a given tuple.
2328 + */
2329 +int
2330 +get_tuple(const struct iphdr *iph,
2331 +         const struct sk_buff *skb,
2332 +         unsigned int dataoff,
2333 +         struct ip_conntrack_tuple *tuple,
2334 +         const struct ip_conntrack_protocol *protocol)
2335 +{
2336 +       /* Never happen */
2337 +       if (iph->frag_off & htons(IP_OFFSET)) {
2338 +               printk("ip_conntrack_core: Frag of proto %u.\n",
2339 +                      iph->protocol);
2340 +               return 0;
2341 +       }
2342 +
2343 +       tuple->src.ip = iph->saddr;
2344 +       tuple->dst.ip = iph->daddr;
2345 +       tuple->dst.protonum = iph->protocol;
2346 +
2347 +       return protocol->pkt_to_tuple(skb, dataoff, tuple);
2348 +}
2349 +
2350 +/**
2351 + * invert_tuple - Returns the inverse of a given tuple. It is used to 
2352 + * calculate the tuple which represents the other sense of the flow
2353 + * of a connection.
2354 + * @inverse: the inverted tuple. Use as return value.
2355 + * @orig: the original tuple which will be inverted.
2356 + * @protocol: a pointer to the protocol structure which contains all the
2357 + * specifical functions available for this tuple.
2358 + */
2359 +static int
2360 +invert_tuple(struct ip_conntrack_tuple *inverse,
2361 +            const struct ip_conntrack_tuple *orig,
2362 +            const struct ip_conntrack_protocol *protocol)
2363 +{
2364 +       inverse->src.ip = orig->dst.ip;
2365 +       inverse->dst.ip = orig->src.ip;
2366 +       inverse->dst.protonum = orig->dst.protonum;
2367 +
2368 +       return protocol->invert_tuple(inverse, orig);
2369 +}
2370 +
2371 +
2372 +/* ip_conntrack_expect helper functions */
2373 +
2374 +/**
2375 + * expect_cmp - compare a tuple with a expectation depending on a mask
2376 + * @i: pointer to an expectation.
2377 + * @tuple: tuple which will be compared with the expectation tuple.
2378 + *
2379 + * Actually the tuple field of an expectation is compared with a tuple
2380 + * This function is used by LIST_FIND to find a expectation which match a te
2381 + * given tuple.
2382 + */
2383 +static inline int expect_cmp(const struct ip_conntrack_expect *i,
2384 +                            const struct ip_conntrack_tuple *tuple)
2385 +{
2386 +       MUST_BE_READ_LOCKED(&ip_conntrack_expect_tuple_lock);
2387 +       return ip_ct_tuple_mask_cmp(tuple, &i->tuple, &i->mask);
2388 +}
2389 +
2390 +/**
2391 + * destroy_expect - Release all the resources allocated by an expectation.
2392 + * @exp: pointer to the expectation which we want to release.
2393 + */
2394 +static void
2395 +destroy_expect(struct ip_conntrack_expect *exp)
2396 +{
2397 +       DEBUGP("destroy_expect(%p) use=%d\n", exp, atomic_read(&exp->use));
2398 +       IP_NF_ASSERT(atomic_read(&exp->use));
2399 +       IP_NF_ASSERT(!timer_pending(&exp->timeout));
2400 +
2401 +       kfree(exp);
2402 +}
2403 +
2404 +/**
2405 + * ip_conntrack_expect_put - it decrements the counter of use related 
2406 + * associated to an expectation and it calls destroy_expect.
2407 + * @exp: pointer to the expectation which we want to release.
2408 + */
2409 +inline void ip_conntrack_expect_put(struct ip_conntrack_expect *exp)
2410 +{
2411 +       IP_NF_ASSERT(exp);
2412 +
2413 +       if (atomic_dec_and_test(&exp->use)) {
2414 +               /* usage count dropped to zero */
2415 +               destroy_expect(exp);
2416 +       }
2417 +}
2418 +
2419 +static inline struct ip_conntrack_expect *
2420 +__ip_ct_expect_find(const struct ip_conntrack_tuple *tuple)
2421 +{
2422 +       MUST_BE_READ_LOCKED(&ip_conntrack_lock);
2423 +       MUST_BE_READ_LOCKED(&ip_conntrack_expect_tuple_lock);
2424 +       return LIST_FIND(&ip_conntrack_expect_list, expect_cmp, 
2425 +                        struct ip_conntrack_expect *, tuple);
2426 +}
2427 +
2428 +/**
2429 + * ip_conntrack_find_get - find conntrack according to tuple
2430 + * @tuple: conntrack tuple for which we search conntrack
2431 + * @ignored_conntrack: ignore this conntrack during search
2432 + *
2433 + * This function increments the reference count of the found
2434 + * conntrack (if any).
2435 + */
2436 +struct ip_conntrack_expect *
2437 +ip_conntrack_expect_find_get(const struct ip_conntrack_tuple *tuple)
2438 +{
2439 +       struct ip_conntrack_expect *exp;
2440 +
2441 +       READ_LOCK(&ip_conntrack_lock);
2442 +       READ_LOCK(&ip_conntrack_expect_tuple_lock);
2443 +       exp = __ip_ct_expect_find(tuple);
2444 +       if (exp)
2445 +               atomic_inc(&exp->use);
2446 +       READ_UNLOCK(&ip_conntrack_expect_tuple_lock);
2447 +       READ_UNLOCK(&ip_conntrack_lock);
2448 +
2449 +       return exp;
2450 +}
2451 +
2452 +/* remove one specific expectation from all lists and drop refcount,
2453 + * does _NOT_ delete the timer. */
2454 +static void __unexpect_related(struct ip_conntrack_expect *expect)
2455 +{
2456 +       DEBUGP("unexpect_related(%p)\n", expect);
2457 +       MUST_BE_WRITE_LOCKED(&ip_conntrack_lock);
2458 +
2459 +       /* we're not allowed to unexpect a confirmed expectation! */
2460 +       IP_NF_ASSERT(!expect->sibling);
2461 +
2462 +       /* delete from global and local lists */
2463 +       list_del(&expect->list);
2464 +       list_del(&expect->expected_list);
2465 +
2466 +       /* decrement expect-count of master conntrack */
2467 +       if (expect->expectant)
2468 +               expect->expectant->expecting--;
2469 +
2470 +       ip_conntrack_expect_put(expect);
2471 +}
2472 +
2473 +/* remove one specific expecatation from all lists, drop refcount
2474 + * and expire timer. 
2475 + * This function can _NOT_ be called for confirmed expects! */
2476 +static void unexpect_related(struct ip_conntrack_expect *expect)
2477 +{
2478 +       IP_NF_ASSERT(expect->expectant);
2479 +       IP_NF_ASSERT(expect->expectant->helper);
2480 +       /* if we are supposed to have a timer, but we can't delete
2481 +        * it: race condition.  __unexpect_related will
2482 +        * be calledd by timeout function */
2483 +       if (expect->expectant->helper->timeout
2484 +           && !del_timer(&expect->timeout))
2485 +               return;
2486 +
2487 +       __unexpect_related(expect);
2488 +}
2489 +
2490 +/* delete all unconfirmed expectations for this conntrack */
2491 +static void remove_expectations(struct ip_conntrack *ct, int drop_refcount)
2492 +{
2493 +       struct list_head *exp_entry, *next;
2494 +       struct ip_conntrack_expect *exp;
2495 +
2496 +       DEBUGP("remove_expectations(%p)\n", ct);
2497 +
2498 +       list_for_each_safe(exp_entry, next, &ct->sibling_list) {
2499 +               exp = list_entry(exp_entry, struct ip_conntrack_expect,
2500 +                                expected_list);
2501 +
2502 +               /* we skip established expectations, as we want to delete
2503 +                * the un-established ones only */
2504 +               if (exp->sibling) {
2505 +                       DEBUGP("remove_expectations: skipping established %p of %p\n", exp->sibling, ct);
2506 +                       if (drop_refcount) {
2507 +                               /* Indicate that this expectations parent is dead */
2508 +                               ip_conntrack_put(exp->expectant);
2509 +                               exp->expectant = NULL;
2510 +                       }
2511 +                       continue;
2512 +               }
2513 +
2514 +               IP_NF_ASSERT(list_inlist(&ip_conntrack_expect_list, exp));
2515 +               IP_NF_ASSERT(exp->expectant == ct);
2516 +
2517 +               /* delete expectation from global and private lists */
2518 +               unexpect_related(exp);
2519 +       }
2520 +}
2521 +
2522 +static void
2523 +clean_from_lists(struct ip_conntrack *ct)
2524 +{
2525 +       unsigned int ho, hr;
2526 +       
2527 +       DEBUGP("clean_from_lists(%p)\n", ct);
2528 +       MUST_BE_WRITE_LOCKED(&ip_conntrack_lock);
2529 +
2530 +       ho = hash_conntrack(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
2531 +       hr = hash_conntrack(&ct->tuplehash[IP_CT_DIR_REPLY].tuple);
2532 +       LIST_DELETE(&ip_conntrack_hash[ho], &ct->tuplehash[IP_CT_DIR_ORIGINAL]);
2533 +       LIST_DELETE(&ip_conntrack_hash[hr], &ct->tuplehash[IP_CT_DIR_REPLY]);
2534 +
2535 +       /* Destroy all un-established, pending expectations */
2536 +       remove_expectations(ct, 1);
2537 +}
2538 +
2539 +static void
2540 +destroy_conntrack(struct nf_conntrack *nfct)
2541 +{
2542 +       struct ip_conntrack *ct = (struct ip_conntrack *)nfct, *master = NULL;
2543 +       struct ip_conntrack_protocol *proto;
2544 +
2545 +       DEBUGP("destroy_conntrack(%p)\n", ct);
2546 +       IP_NF_ASSERT(atomic_read(&nfct->use) == 0);
2547 +       IP_NF_ASSERT(!timer_pending(&ct->timeout));
2548 +
2549 +       /* To make sure we don't get any weird locking issues here:
2550 +        * destroy_conntrack() MUST NOT be called with a write lock
2551 +        * to ip_conntrack_lock!!! -HW */
2552 +       proto = ip_ct_find_proto(ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.protonum);
2553 +       if (proto && proto->destroy)
2554 +               proto->destroy(ct);
2555 +
2556 +       if (ip_conntrack_destroyed)
2557 +               ip_conntrack_destroyed(ct);
2558 +
2559 +       WRITE_LOCK(&ip_conntrack_lock);
2560 +       /* Delete us from our own list to prevent corruption later */
2561 +       list_del(&ct->sibling_list);
2562 +
2563 +       /* Delete our master expectation */
2564 +       if (ct->master) {
2565 +               if (ct->master->expectant) {
2566 +                       /* can't call __unexpect_related here,
2567 +                        * since it would screw up expect_list */
2568 +                       list_del(&ct->master->expected_list);
2569 +                       master = ct->master->expectant;
2570 +               }
2571 +               kfree(ct->master);
2572 +       }
2573 +       WRITE_UNLOCK(&ip_conntrack_lock);
2574 +
2575 +       if (master)
2576 +               ip_conntrack_put(master);
2577 +
2578 +       DEBUGP("destroy_conntrack: returning ct=%p to slab\n", ct);
2579 +       kmem_cache_free(ip_conntrack_cachep, ct);
2580 +       atomic_dec(&ip_conntrack_count);
2581 +}
2582 +
2583 +static void death_by_timeout(unsigned long ul_conntrack)
2584 +{
2585 +       struct ip_conntrack *ct = (void *)ul_conntrack;
2586 +
2587 +       WRITE_LOCK(&ip_conntrack_lock);
2588 +       clean_from_lists(ct);
2589 +       WRITE_UNLOCK(&ip_conntrack_lock);
2590 +       ip_conntrack_put(ct);
2591 +}
2592 +
2593 +static inline int
2594 +conntrack_tuple_cmp(const struct ip_conntrack_tuple_hash *i,
2595 +                   const struct ip_conntrack_tuple *tuple,
2596 +                   const struct ip_conntrack *ignored_conntrack)
2597 +{
2598 +       MUST_BE_READ_LOCKED(&ip_conntrack_lock);
2599 +       return i->ctrack != ignored_conntrack
2600 +               && ip_ct_tuple_equal(tuple, &i->tuple);
2601 +}
2602 +
2603 +static struct ip_conntrack_tuple_hash *
2604 +__ip_conntrack_find(const struct ip_conntrack_tuple *tuple,
2605 +                   const struct ip_conntrack *ignored_conntrack)
2606 +{
2607 +       struct ip_conntrack_tuple_hash *h;
2608 +       unsigned int hash = hash_conntrack(tuple);
2609 +
2610 +       MUST_BE_READ_LOCKED(&ip_conntrack_lock);
2611 +       h = LIST_FIND(&ip_conntrack_hash[hash],
2612 +                     conntrack_tuple_cmp,
2613 +                     struct ip_conntrack_tuple_hash *,
2614 +                     tuple, ignored_conntrack);
2615 +       return h;
2616 +}
2617 +
2618 +/**
2619 + * ip_conntrack_find_get - find conntrack according to tuple
2620 + * @tuple: conntrack tuple for which we search conntrack
2621 + * @ignored_conntrack: ignore this conntrack during search
2622 + *
2623 + * This function increments the reference count of the found
2624 + * conntrack (if any).
2625 + */
2626 +struct ip_conntrack_tuple_hash *
2627 +ip_conntrack_find_get(const struct ip_conntrack_tuple *tuple,
2628 +                     const struct ip_conntrack *ignored_conntrack)
2629 +{
2630 +       struct ip_conntrack_tuple_hash *h;
2631 +
2632 +       READ_LOCK(&ip_conntrack_lock);
2633 +       h = __ip_conntrack_find(tuple, ignored_conntrack);
2634 +       if (h)
2635 +               atomic_inc(&h->ctrack->ct_general.use);
2636 +       READ_UNLOCK(&ip_conntrack_lock);
2637 +
2638 +       return h;
2639 +}
2640 +
2641 +static inline struct ip_conntrack *
2642 +__ip_conntrack_get(struct nf_ct_info *nfct, enum ip_conntrack_info *ctinfo)
2643 +{
2644 +       struct ip_conntrack *ct
2645 +               = (struct ip_conntrack *)nfct->master;
2646 +
2647 +       /* ctinfo is the index of the nfct inside the conntrack */
2648 +       *ctinfo = nfct - ct->infos;
2649 +       IP_NF_ASSERT(*ctinfo >= 0 && *ctinfo < IP_CT_NUMBER);
2650 +       return ct;
2651 +}
2652 +
2653 +/**
2654 + * ip_conntrack_get - Return conntrack and conntrack_info for given skb
2655 + * @skb: skb for which we want to find conntrack and conntrack_info
2656 + * @ctinfo: pointer to ctinfo, used as return value
2657 + *
2658 + * This function resolves the respective conntrack and conntrack_info
2659 + * structures for the connection this packet (skb) is part of.
2660 + */
2661 +struct ip_conntrack *
2662 +ip_conntrack_get(struct sk_buff *skb, enum ip_conntrack_info *ctinfo)
2663 +{
2664 +       if (skb->nfct) 
2665 +               return __ip_conntrack_get(skb->nfct, ctinfo);
2666 +       return NULL;
2667 +}
2668 +
2669 +/* Confirm a connection given skb->nfct; places it in hash table */
2670 +int
2671 +__ip_conntrack_confirm(struct nf_ct_info *nfct)
2672 +{
2673 +       unsigned int hash, repl_hash;
2674 +       struct ip_conntrack *ct;
2675 +       enum ip_conntrack_info ctinfo;
2676 +
2677 +       ct = __ip_conntrack_get(nfct, &ctinfo);
2678 +
2679 +       /* ipt_REJECT uses ip_conntrack_attach to attach related
2680 +          ICMP/TCP RST packets in other direction.  Actual packet
2681 +          which created connection will be IP_CT_NEW or for an
2682 +          expected connection, IP_CT_RELATED. */
2683 +       if (CTINFO2DIR(ctinfo) != IP_CT_DIR_ORIGINAL)
2684 +               return NF_ACCEPT;
2685 +
2686 +       hash = hash_conntrack(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
2687 +       repl_hash = hash_conntrack(&ct->tuplehash[IP_CT_DIR_REPLY].tuple);
2688 +
2689 +       /* We're not in hash table, and we refuse to set up related
2690 +          connections for unconfirmed conns.  But packet copies and
2691 +          REJECT will give spurious warnings here. */
2692 +       /* IP_NF_ASSERT(atomic_read(&ct->ct_general.use) == 1); */
2693 +
2694 +       /* No external references means noone else could have
2695 +           confirmed us. */
2696 +       IP_NF_ASSERT(!is_confirmed(ct));
2697 +       DEBUGP("Confirming conntrack %p\n", ct);
2698 +
2699 +       WRITE_LOCK(&ip_conntrack_lock);
2700 +       /* See if there's one in the list already, including reverse:
2701 +           NAT could have grabbed it without realizing, since we're
2702 +           not in the hash.  If there is, we lost race. */
2703 +       if (!LIST_FIND(&ip_conntrack_hash[hash],
2704 +                      conntrack_tuple_cmp,
2705 +                      struct ip_conntrack_tuple_hash *,
2706 +                      &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple, NULL)
2707 +           && !LIST_FIND(&ip_conntrack_hash[repl_hash],
2708 +                         conntrack_tuple_cmp,
2709 +                         struct ip_conntrack_tuple_hash *,
2710 +                         &ct->tuplehash[IP_CT_DIR_REPLY].tuple, NULL)) {
2711 +               list_prepend(&ip_conntrack_hash[hash],
2712 +                            &ct->tuplehash[IP_CT_DIR_ORIGINAL]);
2713 +               list_prepend(&ip_conntrack_hash[repl_hash],
2714 +                            &ct->tuplehash[IP_CT_DIR_REPLY]);
2715 +               /* Timer relative to confirmation time, not original
2716 +                  setting time, otherwise we'd get timer wrap in
2717 +                  weird delay cases. */
2718 +               ct->timeout.expires += jiffies;
2719 +               add_timer(&ct->timeout);
2720 +               atomic_inc(&ct->ct_general.use);
2721 +               set_bit(IPS_CONFIRMED_BIT, &ct->status);
2722 +               WRITE_UNLOCK(&ip_conntrack_lock);
2723 +               return NF_ACCEPT;
2724 +       }
2725 +
2726 +       WRITE_UNLOCK(&ip_conntrack_lock);
2727 +       return NF_DROP;
2728 +}
2729 +
2730 +/**
2731 + * ip_conntrack_tuple_taken - Find out if tuple is already in use
2732 + * @tuple: tuple to be used for this test
2733 + * @ignored_conntrack: conntrack which is excluded from result
2734 + *
2735 + * This function is called by the NAT code in order to find out if
2736 + * a particular tuple is already in use by some connection.
2737 + */
2738 +int
2739 +ip_conntrack_tuple_taken(const struct ip_conntrack_tuple *tuple,
2740 +                        const struct ip_conntrack *ignored_conntrack)
2741 +{
2742 +       struct ip_conntrack_tuple_hash *h;
2743 +
2744 +       READ_LOCK(&ip_conntrack_lock);
2745 +       h = __ip_conntrack_find(tuple, ignored_conntrack);
2746 +       READ_UNLOCK(&ip_conntrack_lock);
2747 +
2748 +       return h != NULL;
2749 +}
2750 +
2751 +/* Returns conntrack if it dealt with ICMP, and filled in skb fields */
2752 +struct ip_conntrack *
2753 +icmp_error_track(struct sk_buff *skb,
2754 +                enum ip_conntrack_info *ctinfo,
2755 +                unsigned int hooknum)
2756 +{
2757 +       struct ip_conntrack_tuple innertuple, origtuple;
2758 +       struct {
2759 +               struct icmphdr icmp;
2760 +               struct iphdr ip;
2761 +       } inside;
2762 +       struct ip_conntrack_protocol *innerproto;
2763 +       struct ip_conntrack_tuple_hash *h;
2764 +       int dataoff;
2765 +
2766 +       IP_NF_ASSERT(skb->nfct == NULL);
2767 +
2768 +       /* Not enough header? */
2769 +       if (skb_copy_bits(skb, skb->nh.iph->ihl*4, &inside, sizeof(inside))!=0)
2770 +               return NULL;
2771 +
2772 +       if (inside.icmp.type != ICMP_DEST_UNREACH
2773 +           && inside.icmp.type != ICMP_SOURCE_QUENCH
2774 +           && inside.icmp.type != ICMP_TIME_EXCEEDED
2775 +           && inside.icmp.type != ICMP_PARAMETERPROB
2776 +           && inside.icmp.type != ICMP_REDIRECT)
2777 +               return NULL;
2778 +
2779 +       /* Ignore ICMP's containing fragments (shouldn't happen) */
2780 +       if (inside.ip.frag_off & htons(IP_OFFSET)) {
2781 +               DEBUGP("icmp_error_track: fragment of proto %u\n",
2782 +                      inside.ip.protocol);
2783 +               return NULL;
2784 +       }
2785 +
2786 +       innerproto = ip_ct_find_proto(inside.ip.protocol);
2787 +       dataoff = skb->nh.iph->ihl*4 + sizeof(inside.icmp) + inside.ip.ihl*4;
2788 +       /* Are they talking about one of our connections? */
2789 +       if (!get_tuple(&inside.ip, skb, dataoff, &origtuple, innerproto)) {
2790 +               DEBUGP("icmp_error: ! get_tuple p=%u", inside.ip.protocol);
2791 +               return NULL;
2792 +       }
2793 +
2794 +       /* Ordinarily, we'd expect the inverted tupleproto, but it's
2795 +          been preserved inside the ICMP. */
2796 +       if (!invert_tuple(&innertuple, &origtuple, innerproto)) {
2797 +               DEBUGP("icmp_error_track: Can't invert tuple\n");
2798 +               return NULL;
2799 +       }
2800 +
2801 +       *ctinfo = IP_CT_RELATED;
2802 +
2803 +       h = ip_conntrack_find_get(&innertuple, NULL);
2804 +       if (!h) {
2805 +               /* Locally generated ICMPs will match inverted if they
2806 +                  haven't been SNAT'ed yet */
2807 +               /* FIXME: NAT code has to handle half-done double NAT --RR */
2808 +               if (hooknum == NF_IP_LOCAL_OUT)
2809 +                       h = ip_conntrack_find_get(&origtuple, NULL);
2810 +
2811 +               if (!h) {
2812 +                       DEBUGP("icmp_error_track: no match\n");
2813 +                       return NULL;
2814 +               }
2815 +               /* Reverse direction from that found */
2816 +               if (DIRECTION(h) != IP_CT_DIR_REPLY)
2817 +                       *ctinfo += IP_CT_IS_REPLY;
2818 +       } else {
2819 +               if (DIRECTION(h) == IP_CT_DIR_REPLY)
2820 +                       *ctinfo += IP_CT_IS_REPLY;
2821 +       }
2822 +
2823 +       /* Update skb to refer to this connection */
2824 +       skb->nfct = &h->ctrack->infos[*ctinfo];
2825 +       return h->ctrack;
2826 +}
2827 +
2828 +/* There's a small race here where we may free a just-assured
2829 +   connection.  Too bad: we're in trouble anyway. */
2830 +static inline int unreplied(const struct ip_conntrack_tuple_hash *i)
2831 +{
2832 +       return !(test_bit(IPS_ASSURED_BIT, &i->ctrack->status));
2833 +}
2834 +
2835 +static int early_drop(struct list_head *chain)
2836 +{
2837 +       /* Traverse backwards: gives us oldest, which is roughly LRU */
2838 +       struct ip_conntrack_tuple_hash *h;
2839 +       int dropped = 0;
2840 +
2841 +       READ_LOCK(&ip_conntrack_lock);
2842 +       h = LIST_FIND_B(chain, unreplied, struct ip_conntrack_tuple_hash *);
2843 +       if (h)
2844 +               atomic_inc(&h->ctrack->ct_general.use);
2845 +       READ_UNLOCK(&ip_conntrack_lock);
2846 +
2847 +       if (!h)
2848 +               return dropped;
2849 +
2850 +       if (del_timer(&h->ctrack->timeout)) {
2851 +               death_by_timeout((unsigned long)h->ctrack);
2852 +               dropped = 1;
2853 +       }
2854 +       ip_conntrack_put(h->ctrack);
2855 +       return dropped;
2856 +}
2857 +
2858 +static inline int helper_cmp(const struct ip_conntrack_helper *i,
2859 +                            const struct ip_conntrack_tuple *rtuple)
2860 +{
2861 +       return ip_ct_tuple_mask_cmp(rtuple, &i->tuple, &i->mask);
2862 +}
2863 +/**
2864 + * ip_ct_find_helper - Find application helper according to tuple
2865 + * @tuple: tuple for which helper needs to be found
2866 + *
2867 + * This function is used to determine if any registered conntrack helper
2868 + * is to be used for the given tuple.
2869 + */
2870 +struct ip_conntrack_helper *ip_ct_find_helper(const struct ip_conntrack_tuple *tuple)
2871 +{
2872 +       return LIST_FIND(&helpers, helper_cmp,
2873 +                        struct ip_conntrack_helper *,
2874 +                        tuple);
2875 +}
2876 +
2877 +/* Allocate a new conntrack: we return -ENOMEM if classification
2878 +   failed due to stress.  Otherwise it really is unclassifiable. */
2879 +static struct ip_conntrack_tuple_hash *
2880 +init_conntrack(const struct ip_conntrack_tuple *tuple,
2881 +              struct ip_conntrack_protocol *protocol,
2882 +              struct sk_buff *skb)
2883 +{
2884 +       struct ip_conntrack *conntrack;
2885 +       struct ip_conntrack_tuple repl_tuple;
2886 +       size_t hash;
2887 +       struct ip_conntrack_expect *expected;
2888 +       int i;
2889 +       static unsigned int drop_next;
2890 +
2891 +       if (!ip_conntrack_hash_rnd_initted) {
2892 +               get_random_bytes(&ip_conntrack_hash_rnd, 4);
2893 +               ip_conntrack_hash_rnd_initted = 1;
2894 +       }
2895 +
2896 +       hash = hash_conntrack(tuple);
2897 +
2898 +       if (ip_conntrack_max &&
2899 +           atomic_read(&ip_conntrack_count) >= ip_conntrack_max) {
2900 +               /* Try dropping from random chain, or else from the
2901 +                   chain about to put into (in case they're trying to
2902 +                   bomb one hash chain). */
2903 +               unsigned int next = (drop_next++)%ip_conntrack_htable_size;
2904 +
2905 +               if (!early_drop(&ip_conntrack_hash[next])
2906 +                   && !early_drop(&ip_conntrack_hash[hash])) {
2907 +                       if (net_ratelimit())
2908 +                               printk(KERN_WARNING
2909 +                                      "ip_conntrack: table full, dropping"
2910 +                                      " packet.\n");
2911 +                       return ERR_PTR(-ENOMEM);
2912 +               }
2913 +       }
2914 +
2915 +       if (!invert_tuple(&repl_tuple, tuple, protocol)) {
2916 +               DEBUGP("Can't invert tuple.\n");
2917 +               return NULL;
2918 +       }
2919 +
2920 +       conntrack = kmem_cache_alloc(ip_conntrack_cachep, GFP_ATOMIC);
2921 +       if (!conntrack) {
2922 +               DEBUGP("Can't allocate conntrack.\n");
2923 +               return ERR_PTR(-ENOMEM);
2924 +       }
2925 +
2926 +       memset(conntrack, 0, sizeof(*conntrack));
2927 +       atomic_set(&conntrack->ct_general.use, 1);
2928 +       conntrack->ct_general.destroy = destroy_conntrack;
2929 +       conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple = *tuple;
2930 +       conntrack->tuplehash[IP_CT_DIR_ORIGINAL].ctrack = conntrack;
2931 +       conntrack->tuplehash[IP_CT_DIR_REPLY].tuple = repl_tuple;
2932 +       conntrack->tuplehash[IP_CT_DIR_REPLY].ctrack = conntrack;
2933 +       for (i=0; i < IP_CT_NUMBER; i++)
2934 +               conntrack->infos[i].master = &conntrack->ct_general;
2935 +
2936 +       if (!protocol->new(conntrack, skb)) {
2937 +               kmem_cache_free(ip_conntrack_cachep, conntrack);
2938 +               return NULL;
2939 +       }
2940 +       /* Don't set timer yet: wait for confirmation */
2941 +       init_timer(&conntrack->timeout);
2942 +       conntrack->timeout.data = (unsigned long)conntrack;
2943 +       conntrack->timeout.function = death_by_timeout;
2944 +
2945 +       INIT_LIST_HEAD(&conntrack->sibling_list);
2946 +
2947 +       WRITE_LOCK(&ip_conntrack_lock);
2948 +       /* Need finding and deleting of expected ONLY if we win race */
2949 +       READ_LOCK(&ip_conntrack_expect_tuple_lock);
2950 +       expected = LIST_FIND(&ip_conntrack_expect_list, expect_cmp,
2951 +                            struct ip_conntrack_expect *, tuple);
2952 +       READ_UNLOCK(&ip_conntrack_expect_tuple_lock);
2953 +
2954 +       if (expected) {
2955 +               /* If master is not in hash table yet (ie. packet hasn't left
2956 +                  this machine yet), how can other end know about expected?
2957 +                  Hence these are not the droids you are looking for (if
2958 +                  master ct never got confirmed, we'd hold a reference to it
2959 +                  and weird things would happen to future packets). */
2960 +               if (!is_confirmed(expected->expectant)) {
2961 +                       
2962 +                       conntrack->helper = ip_ct_find_helper(&repl_tuple);
2963 +                       goto end;
2964 +               }
2965 +
2966 +               /* Expectation is dying... */
2967 +               if (expected->expectant->helper->timeout
2968 +                   && ! del_timer(&expected->timeout)) {
2969 +                       goto end;       
2970 +               }
2971 +
2972 +                DEBUGP("conntrack: expectation arrives ct=%p exp=%p\n",
2973 +                       conntrack, expected);
2974 +                /* Welcome, Mr. Bond.  We've been expecting you... */
2975 +                IP_NF_ASSERT(master_ct(conntrack));
2976 +                __set_bit(IPS_EXPECTED_BIT, &conntrack->status);
2977 +                conntrack->master = expected;
2978 +                expected->sibling = conntrack;
2979 +                LIST_DELETE(&ip_conntrack_expect_list, expected);
2980 +                expected->expectant->expecting--;
2981 +                nf_conntrack_get(&master_ct(conntrack)->infos[0]);
2982 +
2983 +               /* this is a braindead... --pablo */
2984 +               atomic_inc(&ip_conntrack_count);
2985 +               WRITE_UNLOCK(&ip_conntrack_lock);
2986 +
2987 +               if (expected->expectfn)
2988 +                       expected->expectfn(conntrack);
2989 +
2990 +               goto ret;
2991 +        } else 
2992 +                conntrack->helper = ip_ct_find_helper(&repl_tuple);
2993 +
2994 +end:   atomic_inc(&ip_conntrack_count);
2995 +       WRITE_UNLOCK(&ip_conntrack_lock);
2996 +
2997 +ret:   return &conntrack->tuplehash[IP_CT_DIR_ORIGINAL];
2998 +}
2999 +
3000 +/* On success, returns conntrack ptr, sets skb->nfct and ctinfo */
3001 +static inline struct ip_conntrack *
3002 +resolve_normal_ct(struct sk_buff *skb,
3003 +                 struct ip_conntrack_protocol *proto,
3004 +                 int *set_reply,
3005 +                 unsigned int hooknum,
3006 +                 enum ip_conntrack_info *ctinfo)
3007 +{
3008 +       struct ip_conntrack_tuple tuple;
3009 +       struct ip_conntrack_tuple_hash *h;
3010 +
3011 +       IP_NF_ASSERT((skb->nh.iph->frag_off & htons(IP_OFFSET)) == 0);
3012 +
3013 +       if (!get_tuple(skb->nh.iph, skb, skb->nh.iph->ihl*4, &tuple, proto))
3014 +               return NULL;
3015 +
3016 +       /* look for tuple match */
3017 +       h = ip_conntrack_find_get(&tuple, NULL);
3018 +       if (!h) {
3019 +               h = init_conntrack(&tuple, proto, skb);
3020 +               if (!h)
3021 +                       return NULL;
3022 +               if (IS_ERR(h))
3023 +                       return (void *)h;
3024 +       }
3025 +
3026 +       /* It exists; we have (non-exclusive) reference. */
3027 +       if (DIRECTION(h) == IP_CT_DIR_REPLY) {
3028 +               *ctinfo = IP_CT_ESTABLISHED + IP_CT_IS_REPLY;
3029 +               /* Please set reply bit if this packet OK */
3030 +               *set_reply = 1;
3031 +       } else {
3032 +               /* Once we've had two way comms, always ESTABLISHED. */
3033 +               if (test_bit(IPS_SEEN_REPLY_BIT, &h->ctrack->status)) {
3034 +                       DEBUGP("ip_conntrack_in: normal packet for %p\n",
3035 +                              h->ctrack);
3036 +                       *ctinfo = IP_CT_ESTABLISHED;
3037 +               } else if (test_bit(IPS_EXPECTED_BIT, &h->ctrack->status)) {
3038 +                       DEBUGP("ip_conntrack_in: related packet for %p\n",
3039 +                              h->ctrack);
3040 +                       *ctinfo = IP_CT_RELATED;
3041 +               } else {
3042 +                       DEBUGP("ip_conntrack_in: new packet for %p\n",
3043 +                              h->ctrack);
3044 +                       *ctinfo = IP_CT_NEW;
3045 +               }
3046 +               *set_reply = 0;
3047 +       }
3048 +       skb->nfct = &h->ctrack->infos[*ctinfo];
3049 +       return h->ctrack;
3050 +}
3051 +
3052 +/* Netfilter hook itself. */
3053 +unsigned int ip_conntrack_in(unsigned int hooknum,
3054 +                            struct sk_buff **pskb,
3055 +                            const struct net_device *in,
3056 +                            const struct net_device *out,
3057 +                            int (*okfn)(struct sk_buff *))
3058 +{
3059 +       struct ip_conntrack *ct;
3060 +       enum ip_conntrack_info ctinfo;
3061 +       struct ip_conntrack_protocol *proto;
3062 +       int set_reply;
3063 +       int ret;
3064 +
3065 +       /* FIXME: Do this right please. --RR */
3066 +       (*pskb)->nfcache |= NFC_UNKNOWN;
3067 +
3068 +/* Doesn't cover locally-generated broadcast, so not worth it. */
3069 +#if 0
3070 +       /* Ignore broadcast: no `connection'. */
3071 +       if ((*pskb)->pkt_type == PACKET_BROADCAST) {
3072 +               printk("Broadcast packet!\n");
3073 +               return NF_ACCEPT;
3074 +       } else if (((*pskb)->nh.iph->daddr & htonl(0x000000FF)) 
3075 +                  == htonl(0x000000FF)) {
3076 +               printk("Should bcast: %u.%u.%u.%u->%u.%u.%u.%u (sk=%p, ptype=%u)\n",
3077 +                      NIPQUAD((*pskb)->nh.iph->saddr),
3078 +                      NIPQUAD((*pskb)->nh.iph->daddr),
3079 +                      (*pskb)->sk, (*pskb)->pkt_type);
3080 +       }
3081 +#endif
3082 +
3083 +       /* Previously seen (loopback)?  Ignore.  Do this before
3084 +           fragment check. */
3085 +       if ((*pskb)->nfct)
3086 +               return NF_ACCEPT;
3087 +
3088 +       /* Gather fragments. */
3089 +       if ((*pskb)->nh.iph->frag_off & htons(IP_MF|IP_OFFSET)) {
3090 +               *pskb = ip_ct_gather_frags(*pskb);
3091 +               if (!*pskb)
3092 +                       return NF_STOLEN;
3093 +       }
3094 +
3095 +       proto = ip_ct_find_proto((*pskb)->nh.iph->protocol);
3096 +
3097 +       /* It may be an icmp error... */
3098 +       if ((*pskb)->nh.iph->protocol == IPPROTO_ICMP 
3099 +           && icmp_error_track(*pskb, &ctinfo, hooknum))
3100 +               return NF_ACCEPT;
3101 +
3102 +       if (!(ct = resolve_normal_ct(*pskb, proto,&set_reply,hooknum,&ctinfo)))
3103 +               /* Not valid part of a connection */
3104 +               return NF_ACCEPT;
3105 +
3106 +       if (IS_ERR(ct))
3107 +               /* Too stressed to deal. */
3108 +               return NF_DROP;
3109 +
3110 +       IP_NF_ASSERT((*pskb)->nfct);
3111 +
3112 +       ret = proto->packet(ct, *pskb, ctinfo);
3113 +       if (ret == -1) {
3114 +               /* Invalid */
3115 +               nf_conntrack_put((*pskb)->nfct);
3116 +               (*pskb)->nfct = NULL;
3117 +               return NF_ACCEPT;
3118 +       }
3119 +
3120 +       if (ret != NF_DROP && ct->helper) {
3121 +               ret = ct->helper->help(*pskb, ct, ctinfo);
3122 +               if (ret == -1) {
3123 +                       /* Invalid */
3124 +                       nf_conntrack_put((*pskb)->nfct);
3125 +                       (*pskb)->nfct = NULL;
3126 +                       return NF_ACCEPT;
3127 +               }
3128 +       }
3129 +       if (set_reply)
3130 +               set_bit(IPS_SEEN_REPLY_BIT, &ct->status);
3131 +
3132 +       return ret;
3133 +}
3134 +
3135 +int invert_tuplepr(struct ip_conntrack_tuple *inverse,
3136 +                  const struct ip_conntrack_tuple *orig)
3137 +{
3138 +       return invert_tuple(inverse, orig, ip_ct_find_proto(orig->dst.protonum));
3139 +}
3140 +
3141 +static inline int resent_expect(const struct ip_conntrack_expect *i,
3142 +                               const struct ip_conntrack_tuple *tuple,
3143 +                               const struct ip_conntrack_tuple *mask)
3144 +{
3145 +       DEBUGP("resent_expect\n");
3146 +       DEBUGP("   tuple:   "); DUMP_TUPLE(&i->tuple);
3147 +       DEBUGP("ct_tuple:   "); DUMP_TUPLE(&i->ct_tuple);
3148 +       DEBUGP("test tuple: "); DUMP_TUPLE(tuple);
3149 +       return (((i->ct_tuple.dst.protonum == 0 && ip_ct_tuple_equal(&i->tuple, tuple))
3150 +                || (i->ct_tuple.dst.protonum && ip_ct_tuple_equal(&i->ct_tuple, tuple)))
3151 +               && ip_ct_tuple_equal(&i->mask, mask));
3152 +}
3153 +
3154 +/* Would two expected things clash? */
3155 +static inline int expect_clash(const struct ip_conntrack_expect *i,
3156 +                              const struct ip_conntrack_tuple *tuple,
3157 +                              const struct ip_conntrack_tuple *mask)
3158 +{
3159 +       /* Part covered by intersection of masks must be unequal,
3160 +           otherwise they clash */
3161 +       struct ip_conntrack_tuple intersect_mask
3162 +               = { { i->mask.src.ip & mask->src.ip,
3163 +                     { i->mask.src.u.all & mask->src.u.all } },
3164 +                   { i->mask.dst.ip & mask->dst.ip,
3165 +                     { i->mask.dst.u.all & mask->dst.u.all },
3166 +                     i->mask.dst.protonum & mask->dst.protonum } };
3167 +
3168 +       return ip_ct_tuple_mask_cmp(&i->tuple, tuple, &intersect_mask);
3169 +}
3170 +
3171 +/**
3172 + * ip_conntrack_unexpect_related - Unexpect a related connection
3173 + * @expect: expecattin to be removed
3174 + *
3175 + * This function removes an existing expectation, that has not yet been
3176 + * confirmed (i.e. expectation was issued, but expected connection didn't
3177 + * arrive yet)
3178 + */
3179 +inline void ip_conntrack_unexpect_related(struct ip_conntrack_expect *expect)
3180 +{
3181 +       WRITE_LOCK(&ip_conntrack_lock);
3182 +       unexpect_related(expect);
3183 +       WRITE_UNLOCK(&ip_conntrack_lock);
3184 +}
3185 +       
3186 +static void expectation_timed_out(unsigned long ul_expect)
3187 +{
3188 +       struct ip_conntrack_expect *expect = (void *) ul_expect;
3189 +
3190 +       DEBUGP("expectation %p timed out\n", expect);   
3191 +       WRITE_LOCK(&ip_conntrack_lock);
3192 +       __unexpect_related(expect);
3193 +       WRITE_UNLOCK(&ip_conntrack_lock);
3194 +}
3195 +
3196 +/**
3197 + * ip_conntrack_expect_related - Expect a related connection
3198 + * @related_to: master conntrack
3199 + * @expect: expectation with all values filled in
3200 + *
3201 + * This function is called by conntrack application helpers who
3202 + * have detected that the control (master) connection is just about
3203 + * to negotiate a related slave connection. 
3204 + *
3205 + * Note: This function allocates it's own struct ip_conntrack_expect,
3206 + * copying the values from the 'expect' parameter.  Thus, 'expect' can
3207 + * be allocated on the stack and does not need to be valid after this
3208 + * function returns.
3209 + */
3210 +int ip_conntrack_expect_related(struct ip_conntrack *related_to,
3211 +                               struct ip_conntrack_expect *expect)
3212 +{
3213 +       struct ip_conntrack_expect *old, *new;
3214 +       int ret = 0;
3215 +
3216 +       WRITE_LOCK(&ip_conntrack_lock);
3217 +       /* Because of the write lock, no reader can walk the lists,
3218 +        * so there is no need to use the tuple lock too */
3219 +
3220 +       DEBUGP("ip_conntrack_expect_related %p\n", related_to);
3221 +       DEBUGP("tuple: "); DUMP_TUPLE(&expect->tuple);
3222 +       DEBUGP("mask:  "); DUMP_TUPLE(&expect->mask);
3223 +
3224 +       old = LIST_FIND(&ip_conntrack_expect_list, resent_expect,
3225 +                       struct ip_conntrack_expect *, &expect->tuple, 
3226 +                       &expect->mask);
3227 +       if (old) {
3228 +               /* Helper private data may contain offsets but no pointers
3229 +                  pointing into the payload - otherwise we should have to copy 
3230 +                  the data filled out by the helper over the old one */
3231 +               DEBUGP("expect_related: resent packet\n");
3232 +               if (related_to->helper->timeout) {
3233 +                       if (!del_timer(&old->timeout)) {
3234 +                               /* expectation is dying. Fall through */
3235 +                               old = NULL;
3236 +                       } else {
3237 +                               old->timeout.expires = jiffies + 
3238 +                                       related_to->helper->timeout * HZ;
3239 +                               add_timer(&old->timeout);
3240 +                       }
3241 +               }
3242 +
3243 +               if (old) {
3244 +                       WRITE_UNLOCK(&ip_conntrack_lock);
3245 +                       return -EEXIST;
3246 +               }
3247 +       } else if (related_to->helper->max_expected && 
3248 +                  related_to->expecting >= related_to->helper->max_expected) {
3249 +               struct list_head *cur_item;
3250 +               /* old == NULL */
3251 +               if (!(related_to->helper->flags & 
3252 +                     IP_CT_HELPER_F_REUSE_EXPECT)) {
3253 +                       WRITE_UNLOCK(&ip_conntrack_lock);
3254 +                       if (net_ratelimit())
3255 +                               printk(KERN_WARNING
3256 +                                      "ip_conntrack: max number of expected "
3257 +                                      "connections %i of %s reached for "
3258 +                                      "%u.%u.%u.%u->%u.%u.%u.%u\n",
3259 +                                      related_to->helper->max_expected,
3260 +                                      related_to->helper->name,
3261 +                                      NIPQUAD(related_to->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip),
3262 +                                      NIPQUAD(related_to->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip));
3263 +                       return -EPERM;
3264 +               }
3265 +               DEBUGP("ip_conntrack: max number of expected "
3266 +                      "connections %i of %s reached for "
3267 +                      "%u.%u.%u.%u->%u.%u.%u.%u, reusing\n",
3268 +                      related_to->helper->max_expected,
3269 +                      related_to->helper->name,
3270 +                      NIPQUAD(related_to->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip),
3271 +                      NIPQUAD(related_to->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip));
3272
3273 +               /* choose the the oldest expectation to evict */
3274 +               list_for_each(cur_item, &related_to->sibling_list) { 
3275 +                       struct ip_conntrack_expect *cur;
3276 +
3277 +                       cur = list_entry(cur_item, 
3278 +                                        struct ip_conntrack_expect,
3279 +                                        expected_list);
3280 +                       if (cur->sibling == NULL) {
3281 +                               old = cur;
3282 +                               break;
3283 +                       }
3284 +               }
3285 +
3286 +               /* (!old) cannot happen, since related_to->expecting is the
3287 +                * number of unconfirmed expects */
3288 +               IP_NF_ASSERT(old);
3289 +
3290 +               /* newnat14 does not reuse the real allocated memory
3291 +                * structures but rather unexpects the old and
3292 +                * allocates a new.  unexpect_related will decrement
3293 +                * related_to->expecting. 
3294 +                */
3295 +               unexpect_related(old);
3296 +               ret = -EPERM;
3297 +       } else if (LIST_FIND(&ip_conntrack_expect_list, expect_clash,
3298 +                            struct ip_conntrack_expect *, &expect->tuple, 
3299 +                            &expect->mask)) {
3300 +               WRITE_UNLOCK(&ip_conntrack_lock);
3301 +               DEBUGP("expect_related: busy!\n");
3302 +               return -EBUSY;
3303 +       }
3304 +       
3305 +       new = (struct ip_conntrack_expect *) 
3306 +             kmalloc(sizeof(struct ip_conntrack_expect), GFP_ATOMIC);
3307 +       if (!new) {
3308 +               WRITE_UNLOCK(&ip_conntrack_lock);
3309 +               DEBUGP("expect_relaed: OOM allocating expect\n");
3310 +               return -ENOMEM;
3311 +       }
3312 +       
3313 +       DEBUGP("new expectation %p of conntrack %p\n", new, related_to);
3314 +       memcpy(new, expect, sizeof(*expect));
3315 +       new->expectant = related_to;
3316 +       new->sibling = NULL;
3317 +       atomic_set(&new->use, 1);
3318 +       
3319 +       /* add to expected list for this connection */  
3320 +       list_add(&new->expected_list, &related_to->sibling_list);
3321 +       /* add to global list of expectations */
3322 +       list_prepend(&ip_conntrack_expect_list, &new->list);
3323 +       /* add and start timer if required */
3324 +       if (related_to->helper->timeout) {
3325 +               init_timer(&new->timeout);
3326 +               new->timeout.data = (unsigned long)new;
3327 +               new->timeout.function = expectation_timed_out;
3328 +               new->timeout.expires = jiffies + 
3329 +                                       related_to->helper->timeout * HZ;
3330 +               add_timer(&new->timeout);
3331 +       }
3332 +       related_to->expecting++;
3333 +
3334 +       WRITE_UNLOCK(&ip_conntrack_lock);
3335 +
3336 +       return ret;
3337 +}
3338 +
3339 +/**
3340 + * ip_conntrack_change_expect - Change tuple in existing expectation
3341 + * @expect: expectation which is to be changed
3342 + * @newtuple: new tuple for expect
3343 + *
3344 + * This function is mostly called by NAT application helpers, who want to
3345 + * change an expectation issued by their respective conntrack application
3346 + * helper counterpart.
3347 + */
3348 +int ip_conntrack_change_expect(struct ip_conntrack_expect *expect,
3349 +                              struct ip_conntrack_tuple *newtuple)
3350 +{
3351 +       int ret;
3352 +
3353 +       MUST_BE_READ_LOCKED(&ip_conntrack_lock);
3354 +       WRITE_LOCK(&ip_conntrack_expect_tuple_lock);
3355 +
3356 +       DEBUGP("change_expect:\n");
3357 +       DEBUGP("exp tuple: "); DUMP_TUPLE(&expect->tuple);
3358 +       DEBUGP("exp mask:  "); DUMP_TUPLE(&expect->mask);
3359 +       DEBUGP("newtuple:  "); DUMP_TUPLE(newtuple);
3360 +       if (expect->ct_tuple.dst.protonum == 0) {
3361 +               /* Never seen before */
3362 +               DEBUGP("change expect: never seen before\n");
3363 +               if (!ip_ct_tuple_equal(&expect->tuple, newtuple) 
3364 +                   && LIST_FIND(&ip_conntrack_expect_list, expect_clash,
3365 +                                struct ip_conntrack_expect *, newtuple, &expect->mask)) {
3366 +                       /* Force NAT to find an unused tuple */
3367 +                       ret = -1;
3368 +               } else {
3369 +                       memcpy(&expect->ct_tuple, &expect->tuple, sizeof(expect->tuple));
3370 +                       memcpy(&expect->tuple, newtuple, sizeof(expect->tuple));
3371 +                       ret = 0;
3372 +               }
3373 +       } else {
3374 +               /* Resent packet */
3375 +               DEBUGP("change expect: resent packet\n");
3376 +               if (ip_ct_tuple_equal(&expect->tuple, newtuple)) {
3377 +                       ret = 0;
3378 +               } else {
3379 +                       /* Force NAT to choose again the same port */
3380 +                       ret = -1;
3381 +               }
3382 +       }
3383 +       WRITE_UNLOCK(&ip_conntrack_expect_tuple_lock);
3384 +       
3385 +       return ret;
3386 +}
3387 +
3388 +/**
3389 + * ip_conntrack_alter_reply - Alter reply tuple of conntrack
3390 + * @conntrack: conntrack whose reply tuple we want to alter
3391 + * @newreply: designated reply tuple for this conntrack
3392 + *
3393 + * This function alters the reply tuple of a conntrack to the given
3394 + * newreply tuple.  If this newreply tuple is already taken, return 0
3395 + * and don't do alteration
3396 + */
3397 +int ip_conntrack_alter_reply(struct ip_conntrack *conntrack,
3398 +                            const struct ip_conntrack_tuple *newreply)
3399 +{
3400 +       WRITE_LOCK(&ip_conntrack_lock);
3401 +       if (__ip_conntrack_find(newreply, conntrack)) {
3402 +               WRITE_UNLOCK(&ip_conntrack_lock);
3403 +               return 0;
3404 +       }
3405 +       /* Should be unconfirmed, so not in hash table yet */
3406 +       IP_NF_ASSERT(!is_confirmed(conntrack));
3407 +
3408 +       DEBUGP("Altering reply tuple of %p to ", conntrack);
3409 +       DUMP_TUPLE(newreply);
3410 +
3411 +       conntrack->tuplehash[IP_CT_DIR_REPLY].tuple = *newreply;
3412 +       if (!conntrack->master)
3413 +               conntrack->helper = LIST_FIND(&helpers, helper_cmp,
3414 +                                             struct ip_conntrack_helper *,
3415 +                                             newreply);
3416 +       WRITE_UNLOCK(&ip_conntrack_lock);
3417 +
3418 +       return 1;
3419 +}
3420 +
3421 +/**
3422 + * ip_conntrack_helper_register - Register a conntrack application helper
3423 + * @me: structure describing the helper
3424 + *
3425 + * This function is called by conntrack application helpers to register
3426 + * themselves with the conntrack core.
3427 + */
3428 +int ip_conntrack_helper_register(struct ip_conntrack_helper *me)
3429 +{
3430 +       WRITE_LOCK(&ip_conntrack_lock);
3431 +       list_prepend(&helpers, me);
3432 +       WRITE_UNLOCK(&ip_conntrack_lock);
3433 +
3434 +       return 0;
3435 +}
3436 +
3437 +static inline int unhelp(struct ip_conntrack_tuple_hash *i,
3438 +                        const struct ip_conntrack_helper *me)
3439 +{
3440 +       if (i->ctrack->helper == me) {
3441 +               /* Get rid of any expected. */
3442 +               remove_expectations(i->ctrack, 0);
3443 +               /* And *then* set helper to NULL */
3444 +               i->ctrack->helper = NULL;
3445 +       }
3446 +       return 0;
3447 +}
3448 +
3449 +/**
3450 + * ip_conntrack_helper_unregister - Unregister a conntrack application helper
3451 + * @me: structure describing the helper
3452 + *
3453 + * This function is called by conntrack application helpers to unregister
3454 + * themselvers from the conntrack core.
3455 + */
3456 +void ip_conntrack_helper_unregister(struct ip_conntrack_helper *me)
3457 +{
3458 +       unsigned int i;
3459 +
3460 +       /* Need write lock here, to delete helper. */
3461 +       WRITE_LOCK(&ip_conntrack_lock);
3462 +       LIST_DELETE(&helpers, me);
3463 +
3464 +       /* Get rid of expecteds, set helpers to NULL. */
3465 +       for (i = 0; i < ip_conntrack_htable_size; i++)
3466 +               LIST_FIND_W(&ip_conntrack_hash[i], unhelp,
3467 +                           struct ip_conntrack_tuple_hash *, me);
3468 +       WRITE_UNLOCK(&ip_conntrack_lock);
3469 +
3470 +       /* Someone could be still looking at the helper in a bh. */
3471 +       synchronize_net();
3472 +}
3473 +
3474 +/**
3475 + * ip_ct_refresh - Refresh conntrack timer for given conntrack
3476 + * @ct: conntrack which we want to refresh
3477 + * @extra_jiffies: number of jiffies to add
3478 + *
3479 + * This function is called by protocol helpers and application helpers in
3480 + * order to change the expiration timer of a conntrack entry.
3481 + */
3482 +void ip_ct_refresh(struct ip_conntrack *ct, unsigned long extra_jiffies)
3483 +{
3484 +       IP_NF_ASSERT(ct->timeout.data == (unsigned long)ct);
3485 +
3486 +       WRITE_LOCK(&ip_conntrack_lock);
3487 +       /* If not in hash table, timer will not be active yet */
3488 +       if (!is_confirmed(ct))
3489 +               ct->timeout.expires = extra_jiffies;
3490 +       else {
3491 +               /* Need del_timer for race avoidance (may already be dying). */
3492 +               if (del_timer(&ct->timeout)) {
3493 +                       ct->timeout.expires = jiffies + extra_jiffies;
3494 +                       add_timer(&ct->timeout);
3495 +               }
3496 +       }
3497 +       WRITE_UNLOCK(&ip_conntrack_lock);
3498 +}
3499 +
3500 +
3501 +/**
3502 + * ip_ct_gather_frags - Gather fragments of a particular skb
3503 + * @skb: pointer to sk_buff of fragmented IP packet
3504 + *
3505 + * This code is just a wrapper around the defragmentation code in the core IPv4
3506 + * stack.  It also takes care of nonlinear skb's.
3507 + *
3508 + * Returns new sk_buff, or NULL
3509 + */
3510 +struct sk_buff *
3511 +ip_ct_gather_frags(struct sk_buff *skb)
3512 +{
3513 +       struct sock *sk = skb->sk;
3514 +#ifdef CONFIG_NETFILTER_DEBUG
3515 +       unsigned int olddebug = skb->nf_debug;
3516 +#endif
3517 +       if (sk) {
3518 +               sock_hold(sk);
3519 +               skb_orphan(skb);
3520 +       }
3521 +
3522 +       local_bh_disable(); 
3523 +       skb = ip_defrag(skb);
3524 +       local_bh_enable();
3525 +
3526 +       if (!skb) {
3527 +               if (sk)
3528 +                       sock_put(sk);
3529 +               return skb;
3530 +       }
3531 +
3532 +       if (sk) {
3533 +               skb_set_owner_w(skb, sk);
3534 +               sock_put(sk);
3535 +       }
3536 +
3537 +       ip_send_check(skb->nh.iph);
3538 +       skb->nfcache |= NFC_ALTERED;
3539 +#ifdef CONFIG_NETFILTER_DEBUG
3540 +       /* Packet path as if nothing had happened. */
3541 +       skb->nf_debug = olddebug;
3542 +#endif
3543 +       return skb;
3544 +}
3545 +
3546 +/* Used by ipt_REJECT. */
3547 +static void ip_conntrack_attach(struct sk_buff *nskb, struct nf_ct_info *nfct)
3548 +{
3549 +       struct ip_conntrack *ct;
3550 +       enum ip_conntrack_info ctinfo;
3551 +
3552 +       ct = __ip_conntrack_get(nfct, &ctinfo);
3553 +
3554 +       /* This ICMP is in reverse direction to the packet which
3555 +           caused it */
3556 +       if (CTINFO2DIR(ctinfo) == IP_CT_DIR_ORIGINAL)
3557 +               ctinfo = IP_CT_RELATED + IP_CT_IS_REPLY;
3558 +       else
3559 +               ctinfo = IP_CT_RELATED;
3560 +
3561 +       /* Attach new skbuff, and increment count */
3562 +       nskb->nfct = &ct->infos[ctinfo];
3563 +       atomic_inc(&ct->ct_general.use);
3564 +}
3565 +
3566 +static inline int
3567 +do_kill(const struct ip_conntrack_tuple_hash *i,
3568 +       int (*kill)(const struct ip_conntrack *i, void *data),
3569 +       void *data)
3570 +{
3571 +       return kill(i->ctrack, data);
3572 +}
3573 +
3574 +/* Bring out ya dead! */
3575 +static struct ip_conntrack_tuple_hash *
3576 +get_next_corpse(int (*kill)(const struct ip_conntrack *i, void *data),
3577 +               void *data, unsigned int *bucket)
3578 +{
3579 +       struct ip_conntrack_tuple_hash *h = NULL;
3580 +
3581 +       READ_LOCK(&ip_conntrack_lock);
3582 +       for (; !h && *bucket < ip_conntrack_htable_size; (*bucket)++) {
3583 +               h = LIST_FIND(&ip_conntrack_hash[*bucket], do_kill,
3584 +                             struct ip_conntrack_tuple_hash *, kill, data);
3585 +       }
3586 +       if (h)
3587 +               atomic_inc(&h->ctrack->ct_general.use);
3588 +       READ_UNLOCK(&ip_conntrack_lock);
3589 +
3590 +       return h;
3591 +}
3592 +
3593 +/**
3594 + * ip_ct_selective_cleanup - Selectively delete a set of conntrack entries
3595 + * @kill: callback function selecting which entries to delete
3596 + * @data: opaque data pointer, becomes 2nd argument for kill function
3597 + *
3598 + * This function can be used to selectively delete elements of the conntrack
3599 + * hashtable.  The function iterates over the list of conntrack entries and
3600 + * calls the 'kill' function for every entry.  If the return value is true,
3601 + * the connection is deleted (death_by_timeout).
3602 + */
3603 +void
3604 +ip_ct_selective_cleanup(int (*kill)(const struct ip_conntrack *i, void *data),
3605 +                       void *data)
3606 +{
3607 +       struct ip_conntrack_tuple_hash *h;
3608 +       unsigned int bucket = 0;
3609 +
3610 +       while ((h = get_next_corpse(kill, data, &bucket)) != NULL) {
3611 +               /* Time to push up daises... */
3612 +               if (del_timer(&h->ctrack->timeout))
3613 +                       death_by_timeout((unsigned long)h->ctrack);
3614 +               /* ... else the timer will get him soon. */
3615 +
3616 +               ip_conntrack_put(h->ctrack);
3617 +       }
3618 +}
3619 +
3620 +/* Fast function for those who don't want to parse /proc (and I don't
3621 +   blame them). */
3622 +/* Reversing the socket's dst/src point of view gives us the reply
3623 +   mapping. */
3624 +static int
3625 +getorigdst(struct sock *sk, int optval, void *user, int *len)
3626 +{
3627 +       struct inet_opt *inet = inet_sk(sk);
3628 +       struct ip_conntrack_tuple_hash *h;
3629 +       struct ip_conntrack_tuple tuple;
3630 +       
3631 +       IP_CT_TUPLE_U_BLANK(&tuple);
3632 +       tuple.src.ip = inet->rcv_saddr;
3633 +       tuple.src.u.tcp.port = inet->sport;
3634 +       tuple.dst.ip = inet->daddr;
3635 +       tuple.dst.u.tcp.port = inet->dport;
3636 +       tuple.dst.protonum = IPPROTO_TCP;
3637 +
3638 +       /* We only do TCP at the moment: is there a better way? */
3639 +       if (strcmp(sk->sk_prot->name, "TCP")) {
3640 +               DEBUGP("SO_ORIGINAL_DST: Not a TCP socket\n");
3641 +               return -ENOPROTOOPT;
3642 +       }
3643 +
3644 +       if ((unsigned int) *len < sizeof(struct sockaddr_in)) {
3645 +               DEBUGP("SO_ORIGINAL_DST: len %u not %u\n",
3646 +                      *len, sizeof(struct sockaddr_in));
3647 +               return -EINVAL;
3648 +       }
3649 +
3650 +       h = ip_conntrack_find_get(&tuple, NULL);
3651 +       if (h) {
3652 +               struct sockaddr_in sin;
3653 +
3654 +               sin.sin_family = AF_INET;
3655 +               sin.sin_port = h->ctrack->tuplehash[IP_CT_DIR_ORIGINAL]
3656 +                       .tuple.dst.u.tcp.port;
3657 +               sin.sin_addr.s_addr = h->ctrack->tuplehash[IP_CT_DIR_ORIGINAL]
3658 +                       .tuple.dst.ip;
3659 +
3660 +               DEBUGP("SO_ORIGINAL_DST: %u.%u.%u.%u %u\n",
3661 +                      NIPQUAD(sin.sin_addr.s_addr), ntohs(sin.sin_port));
3662 +               ip_conntrack_put(h->ctrack);
3663 +               if (copy_to_user(user, &sin, sizeof(sin)) != 0)
3664 +                       return -EFAULT;
3665 +               else
3666 +                       return 0;
3667 +       }
3668 +       DEBUGP("SO_ORIGINAL_DST: Can't find %u.%u.%u.%u/%u-%u.%u.%u.%u/%u.\n",
3669 +              NIPQUAD(tuple.src.ip), ntohs(tuple.src.u.tcp.port),
3670 +              NIPQUAD(tuple.dst.ip), ntohs(tuple.dst.u.tcp.port));
3671 +       return -ENOENT;
3672 +}
3673 +
3674 +static struct nf_sockopt_ops so_getorigdst = {
3675 +       .pf             = PF_INET,
3676 +       .get_optmin     = SO_ORIGINAL_DST,
3677 +       .get_optmax     = SO_ORIGINAL_DST+1,
3678 +       .get            = &getorigdst,
3679 +};
3680 +
3681 +static int kill_all(const struct ip_conntrack *i, void *data)
3682 +{
3683 +       return 1;
3684 +}
3685 +
3686 +/* Mishearing the voices in his head, our hero wonders how he's
3687 +   supposed to kill the mall. */
3688 +void ip_conntrack_cleanup(void)
3689 +{
3690 +       ip_ct_attach = NULL;
3691 +       /* This makes sure all current packets have passed through
3692 +           netfilter framework.  Roll on, two-stage module
3693 +           delete... */
3694 +       synchronize_net();
3695
3696 + i_see_dead_people:
3697 +       ip_ct_selective_cleanup(kill_all, NULL);
3698 +       if (atomic_read(&ip_conntrack_count) != 0) {
3699 +               schedule();
3700 +               goto i_see_dead_people;
3701 +       }
3702 +
3703 +       kmem_cache_destroy(ip_conntrack_cachep);
3704 +       vfree(ip_conntrack_hash);
3705 +       nf_unregister_sockopt(&so_getorigdst);
3706 +}
3707 +
3708 +static int hashsize;
3709 +MODULE_PARM(hashsize, "i");
3710 +
3711 +int __init ip_conntrack_init(void)
3712 +{
3713 +       unsigned int i;
3714 +       int ret;
3715 +
3716 +       /* Idea from tcp.c: use 1/16384 of memory.  On i386: 32MB
3717 +        * machine has 256 buckets.  >= 1GB machines have 8192 buckets. */
3718 +       if (hashsize) {
3719 +               ip_conntrack_htable_size = hashsize;
3720 +       } else {
3721 +               ip_conntrack_htable_size
3722 +                       = (((num_physpages << PAGE_SHIFT) / 16384)
3723 +                          / sizeof(struct list_head));
3724 +               if (num_physpages > (1024 * 1024 * 1024 / PAGE_SIZE))
3725 +                       ip_conntrack_htable_size = 8192;
3726 +               if (ip_conntrack_htable_size < 16)
3727 +                       ip_conntrack_htable_size = 16;
3728 +       }
3729 +       ip_conntrack_max = 8 * ip_conntrack_htable_size;
3730 +
3731 +       printk("ip_conntrack version %s (%u buckets, %d max)"
3732 +              " - %Zd bytes per conntrack\n", IP_CONNTRACK_VERSION,
3733 +              ip_conntrack_htable_size, ip_conntrack_max,
3734 +              sizeof(struct ip_conntrack));
3735 +
3736 +       ret = nf_register_sockopt(&so_getorigdst);
3737 +       if (ret != 0) {
3738 +               printk(KERN_ERR "Unable to register netfilter socket option\n");
3739 +               return ret;
3740 +       }
3741 +
3742 +       ip_conntrack_hash = vmalloc(sizeof(struct list_head)
3743 +                                   * ip_conntrack_htable_size);
3744 +       if (!ip_conntrack_hash) {
3745 +               printk(KERN_ERR "Unable to create ip_conntrack_hash\n");
3746 +               goto err_unreg_sockopt;
3747 +       }
3748 +
3749 +       ip_conntrack_cachep = kmem_cache_create("ip_conntrack",
3750 +                                               sizeof(struct ip_conntrack), 0,
3751 +                                               SLAB_HWCACHE_ALIGN, NULL, NULL);
3752 +       if (!ip_conntrack_cachep) {
3753 +               printk(KERN_ERR "Unable to create ip_conntrack slab cache\n");
3754 +               goto err_free_hash;
3755 +       }
3756 +       /* Don't NEED lock here, but good form anyway. */
3757 +       WRITE_LOCK(&ip_conntrack_lock);
3758 +       /* Sew in builtin protocols. */
3759 +       list_append(&protocol_list, &ip_conntrack_protocol_tcp);
3760 +       list_append(&protocol_list, &ip_conntrack_protocol_udp);
3761 +       list_append(&protocol_list, &ip_conntrack_protocol_icmp);
3762 +       WRITE_UNLOCK(&ip_conntrack_lock);
3763 +
3764 +       for (i = 0; i < ip_conntrack_htable_size; i++)
3765 +               INIT_LIST_HEAD(&ip_conntrack_hash[i]);
3766 +
3767 +       /* For use by ipt_REJECT */
3768 +       ip_ct_attach = ip_conntrack_attach;
3769 +       return ret;
3770 +
3771 +err_free_hash:
3772 +       vfree(ip_conntrack_hash);
3773 +err_unreg_sockopt:
3774 +       nf_unregister_sockopt(&so_getorigdst);
3775 +
3776 +       return -ENOMEM;
3777 +}
3778 diff -Nur linux-2.6.4-rc2.org/net/ipv4/netfilter/ip_conntrack_standalone.c linux-2.6.4-rc2/net/ipv4/netfilter/ip_conntrack_standalone.c
3779 --- linux-2.6.4-rc2.org/net/ipv4/netfilter/ip_conntrack_standalone.c    2004-03-04 06:16:44.000000000 +0000
3780 +++ linux-2.6.4-rc2/net/ipv4/netfilter/ip_conntrack_standalone.c        2004-03-05 09:55:23.000000000 +0000
3781 @@ -194,6 +194,26 @@
3782         return ip_conntrack_confirm(*pskb);
3783  }
3784  
3785 +static unsigned int ip_conntrack_defrag(unsigned int hooknum,
3786 +                                       struct sk_buff **pskb,
3787 +                                       const struct net_device *in,
3788 +                                       const struct net_device *out,
3789 +                                       int (*okfn)(struct sk_buff *))
3790 +{
3791 +       /* Previously seen (loopback)?  Ignore.  Do this before
3792 +           fragment check. */
3793 +       if ((*pskb)->nfct)
3794 +               return NF_ACCEPT;
3795 +
3796 +       /* Gather fragments. */
3797 +       if ((*pskb)->nh.iph->frag_off & htons(IP_MF|IP_OFFSET)) {
3798 +               *pskb = ip_ct_gather_frags(*pskb);
3799 +               if (!*pskb)
3800 +                       return NF_STOLEN;
3801 +       }
3802 +       return NF_ACCEPT;
3803 +}
3804 +
3805  static unsigned int ip_refrag(unsigned int hooknum,
3806                               struct sk_buff **pskb,
3807                               const struct net_device *in,
3808 @@ -236,6 +256,14 @@
3809  
3810  /* Connection tracking may drop packets, but never alters them, so
3811     make it the first hook. */
3812 +static struct nf_hook_ops ip_conntrack_defrag_ops = {
3813 +       .hook           = ip_conntrack_defrag,
3814 +       .owner          = THIS_MODULE,
3815 +       .pf             = PF_INET,
3816 +       .hooknum        = NF_IP_PRE_ROUTING,
3817 +       .priority       = NF_IP_PRI_CONNTRACK_DEFRAG,
3818 +};
3819 +
3820  static struct nf_hook_ops ip_conntrack_in_ops = {
3821         .hook           = ip_conntrack_in,
3822         .owner          = THIS_MODULE,
3823 @@ -244,6 +272,14 @@
3824         .priority       = NF_IP_PRI_CONNTRACK,
3825  };
3826  
3827 +static struct nf_hook_ops ip_conntrack_defrag_local_out_ops = {
3828 +       .hook           = ip_conntrack_defrag,
3829 +       .owner          = THIS_MODULE,
3830 +       .pf             = PF_INET,
3831 +       .hooknum        = NF_IP_LOCAL_OUT,
3832 +       .priority       = NF_IP_PRI_CONNTRACK_DEFRAG,
3833 +};
3834 +
3835  static struct nf_hook_ops ip_conntrack_local_out_ops = {
3836         .hook           = ip_conntrack_local,
3837         .owner          = THIS_MODULE,
3838 @@ -470,10 +506,20 @@
3839         if (!proc) goto cleanup_init;
3840         proc->owner = THIS_MODULE;
3841  
3842 +       ret = nf_register_hook(&ip_conntrack_defrag_ops);
3843 +       if (ret < 0) {
3844 +               printk("ip_conntrack: can't register pre-routing defrag hook.\n");
3845 +               goto cleanup_proc;
3846 +       }
3847 +       ret = nf_register_hook(&ip_conntrack_defrag_local_out_ops);
3848 +       if (ret < 0) {
3849 +               printk("ip_conntrack: can't register local_out defrag hook.\n");
3850 +               goto cleanup_defragops;
3851 +       }
3852         ret = nf_register_hook(&ip_conntrack_in_ops);
3853         if (ret < 0) {
3854                 printk("ip_conntrack: can't register pre-routing hook.\n");
3855 -               goto cleanup_proc;
3856 +               goto cleanup_defraglocalops;
3857         }
3858         ret = nf_register_hook(&ip_conntrack_local_out_ops);
3859         if (ret < 0) {
3860 @@ -511,6 +557,10 @@
3861         nf_unregister_hook(&ip_conntrack_local_out_ops);
3862   cleanup_inops:
3863         nf_unregister_hook(&ip_conntrack_in_ops);
3864 + cleanup_defraglocalops:
3865 +       nf_unregister_hook(&ip_conntrack_defrag_local_out_ops);
3866 + cleanup_defragops:
3867 +       nf_unregister_hook(&ip_conntrack_defrag_ops);
3868   cleanup_proc:
3869         proc_net_remove("ip_conntrack");
3870   cleanup_init:
3871 @@ -519,13 +569,20 @@
3872         return ret;
3873  }
3874  
3875 -/* FIXME: Allow NULL functions and sub in pointers to generic for
3876 -   them. --RR */
3877 +/**
3878 + * ip_conntrack_protocol_register - Register layer 4 protocol helper
3879 + * @proto: structure describing this layer 4 protocol helper
3880 + *
3881 + * This function is called by layer 4 protocol helpers to register 
3882 + * themselves with the conntrack core.
3883 + */
3884  int ip_conntrack_protocol_register(struct ip_conntrack_protocol *proto)
3885  {
3886         int ret = 0;
3887         struct list_head *i;
3888  
3889 +       /* FIXME: Allow NULL functions and sub in pointers to generic for
3890 +          them. --RR */
3891         WRITE_LOCK(&ip_conntrack_lock);
3892         list_for_each(i, &protocol_list) {
3893                 if (((struct ip_conntrack_protocol *)i)->proto
3894 @@ -542,12 +599,20 @@
3895         return ret;
3896  }
3897  
3898 +/**
3899 + * ip_conntrack_protocol_unregister - Unregister layer 4 protocol helper
3900 + * @proto: structure describing this layer 4 protocol helper
3901 + *
3902 + * This function is called byh layer 4 protocol helpers to unregister
3903 + * themselvers from the conntrack core.  Please note that all conntrack
3904 + * entries for this protocol are deleted from the conntrack hash table.
3905 + */
3906  void ip_conntrack_protocol_unregister(struct ip_conntrack_protocol *proto)
3907  {
3908         WRITE_LOCK(&ip_conntrack_lock);
3909  
3910 -       /* ip_ct_find_proto() returns proto_generic in case there is no protocol 
3911 -        * helper. So this should be enough - HW */
3912 +       /* ip_ct_find_proto() returns proto_generic in case there is no
3913 +        * protocol helper. So this should be enough - HW */
3914         LIST_DELETE(&protocol_list, proto);
3915         WRITE_UNLOCK(&ip_conntrack_lock);
3916         
3917 @@ -602,5 +667,6 @@
3918  EXPORT_SYMBOL(ip_conntrack_expect_list);
3919  EXPORT_SYMBOL(ip_conntrack_lock);
3920  EXPORT_SYMBOL(ip_conntrack_hash);
3921 +EXPORT_SYMBOL(ip_conntrack_untracked);
3922  EXPORT_SYMBOL_GPL(ip_conntrack_find_get);
3923  EXPORT_SYMBOL_GPL(ip_conntrack_put);
3924 diff -Nur linux-2.6.4-rc2.org/net/ipv4/netfilter/ip_conntrack_standalone.c.orig linux-2.6.4-rc2/net/ipv4/netfilter/ip_conntrack_standalone.c.orig
3925 --- linux-2.6.4-rc2.org/net/ipv4/netfilter/ip_conntrack_standalone.c.orig       1970-01-01 00:00:00.000000000 +0000
3926 +++ linux-2.6.4-rc2/net/ipv4/netfilter/ip_conntrack_standalone.c.orig   2004-03-05 09:55:06.000000000 +0000
3927 @@ -0,0 +1,621 @@
3928 +/* This file contains all the functions required for the standalone
3929 +   ip_conntrack module.
3930 +
3931 +   These are not required by the compatibility layer.
3932 +*/
3933 +
3934 +/* (C) 1999-2001 Paul `Rusty' Russell
3935 + * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org>
3936 + *
3937 + * This program is free software; you can redistribute it and/or modify
3938 + * it under the terms of the GNU General Public License version 2 as
3939 + * published by the Free Software Foundation.
3940 + */
3941 +
3942 +#include <linux/config.h>
3943 +#include <linux/types.h>
3944 +#include <linux/ip.h>
3945 +#include <linux/netfilter.h>
3946 +#include <linux/netfilter_ipv4.h>
3947 +#include <linux/module.h>
3948 +#include <linux/skbuff.h>
3949 +#include <linux/proc_fs.h>
3950 +#ifdef CONFIG_SYSCTL
3951 +#include <linux/sysctl.h>
3952 +#endif
3953 +#include <net/checksum.h>
3954 +
3955 +#define ASSERT_READ_LOCK(x) MUST_BE_READ_LOCKED(&ip_conntrack_lock)
3956 +#define ASSERT_WRITE_LOCK(x) MUST_BE_WRITE_LOCKED(&ip_conntrack_lock)
3957 +
3958 +#include <linux/netfilter_ipv4/ip_conntrack.h>
3959 +#include <linux/netfilter_ipv4/ip_conntrack_protocol.h>
3960 +#include <linux/netfilter_ipv4/ip_conntrack_core.h>
3961 +#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
3962 +#include <linux/netfilter_ipv4/listhelp.h>
3963 +
3964 +#if 0
3965 +#define DEBUGP printk
3966 +#else
3967 +#define DEBUGP(format, args...)
3968 +#endif
3969 +
3970 +MODULE_LICENSE("GPL");
3971 +
3972 +static int kill_proto(const struct ip_conntrack *i, void *data)
3973 +{
3974 +       return (i->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum == 
3975 +                       *((u_int8_t *) data));
3976 +}
3977 +
3978 +static unsigned int
3979 +print_tuple(char *buffer, const struct ip_conntrack_tuple *tuple,
3980 +           struct ip_conntrack_protocol *proto)
3981 +{
3982 +       int len;
3983 +
3984 +       len = sprintf(buffer, "src=%u.%u.%u.%u dst=%u.%u.%u.%u ",
3985 +                     NIPQUAD(tuple->src.ip), NIPQUAD(tuple->dst.ip));
3986 +
3987 +       len += proto->print_tuple(buffer + len, tuple);
3988 +
3989 +       return len;
3990 +}
3991 +
3992 +/* FIXME: Don't print source proto part. --RR */
3993 +static unsigned int
3994 +print_expect(char *buffer, const struct ip_conntrack_expect *expect)
3995 +{
3996 +       unsigned int len;
3997 +
3998 +       if (expect->expectant->helper->timeout)
3999 +               len = sprintf(buffer, "EXPECTING: %lu ",
4000 +                             timer_pending(&expect->timeout)
4001 +                             ? (expect->timeout.expires - jiffies)/HZ : 0);
4002 +       else
4003 +               len = sprintf(buffer, "EXPECTING: - ");
4004 +       len += sprintf(buffer + len, "use=%u proto=%u ",
4005 +                     atomic_read(&expect->use), expect->tuple.dst.protonum);
4006 +       len += print_tuple(buffer + len, &expect->tuple,
4007 +                          __ip_ct_find_proto(expect->tuple.dst.protonum));
4008 +       len += sprintf(buffer + len, "\n");
4009 +       return len;
4010 +}
4011 +
4012 +static unsigned int
4013 +print_conntrack(char *buffer, struct ip_conntrack *conntrack)
4014 +{
4015 +       unsigned int len;
4016 +       struct ip_conntrack_protocol *proto
4017 +               = __ip_ct_find_proto(conntrack->tuplehash[IP_CT_DIR_ORIGINAL]
4018 +                              .tuple.dst.protonum);
4019 +
4020 +       len = sprintf(buffer, "%-8s %u %lu ",
4021 +                     proto->name,
4022 +                     conntrack->tuplehash[IP_CT_DIR_ORIGINAL]
4023 +                     .tuple.dst.protonum,
4024 +                     timer_pending(&conntrack->timeout)
4025 +                     ? (conntrack->timeout.expires - jiffies)/HZ : 0);
4026 +
4027 +       len += proto->print_conntrack(buffer + len, conntrack);
4028 +       len += print_tuple(buffer + len,
4029 +                          &conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple,
4030 +                          proto);
4031 +       if (!(test_bit(IPS_SEEN_REPLY_BIT, &conntrack->status)))
4032 +               len += sprintf(buffer + len, "[UNREPLIED] ");
4033 +       len += print_tuple(buffer + len,
4034 +                          &conntrack->tuplehash[IP_CT_DIR_REPLY].tuple,
4035 +                          proto);
4036 +       if (test_bit(IPS_ASSURED_BIT, &conntrack->status))
4037 +               len += sprintf(buffer + len, "[ASSURED] ");
4038 +       len += sprintf(buffer + len, "use=%u ",
4039 +                      atomic_read(&conntrack->ct_general.use));
4040 +       len += sprintf(buffer + len, "\n");
4041 +
4042 +       return len;
4043 +}
4044 +
4045 +/* Returns true when finished. */
4046 +static inline int
4047 +conntrack_iterate(const struct ip_conntrack_tuple_hash *hash,
4048 +                 char *buffer, off_t offset, off_t *upto,
4049 +                 unsigned int *len, unsigned int maxlen)
4050 +{
4051 +       unsigned int newlen;
4052 +       IP_NF_ASSERT(hash->ctrack);
4053 +
4054 +       MUST_BE_READ_LOCKED(&ip_conntrack_lock);
4055 +
4056 +       /* Only count originals */
4057 +       if (DIRECTION(hash))
4058 +               return 0;
4059 +
4060 +       if ((*upto)++ < offset)
4061 +               return 0;
4062 +
4063 +       newlen = print_conntrack(buffer + *len, hash->ctrack);
4064 +       if (*len + newlen > maxlen)
4065 +               return 1;
4066 +       else *len += newlen;
4067 +
4068 +       return 0;
4069 +}
4070 +
4071 +static int
4072 +list_conntracks(char *buffer, char **start, off_t offset, int length)
4073 +{
4074 +       unsigned int i;
4075 +       unsigned int len = 0;
4076 +       off_t upto = 0;
4077 +       struct list_head *e;
4078 +
4079 +       READ_LOCK(&ip_conntrack_lock);
4080 +       /* Traverse hash; print originals then reply. */
4081 +       for (i = 0; i < ip_conntrack_htable_size; i++) {
4082 +               if (LIST_FIND(&ip_conntrack_hash[i], conntrack_iterate,
4083 +                             struct ip_conntrack_tuple_hash *,
4084 +                             buffer, offset, &upto, &len, length))
4085 +                       goto finished;
4086 +       }
4087 +
4088 +       /* Now iterate through expecteds. */
4089 +       READ_LOCK(&ip_conntrack_expect_tuple_lock);
4090 +       list_for_each(e, &ip_conntrack_expect_list) {
4091 +               unsigned int last_len;
4092 +               struct ip_conntrack_expect *expect
4093 +                       = (struct ip_conntrack_expect *)e;
4094 +               if (upto++ < offset) continue;
4095 +
4096 +               last_len = len;
4097 +               len += print_expect(buffer + len, expect);
4098 +               if (len > length) {
4099 +                       len = last_len;
4100 +                       goto finished_expects;
4101 +               }
4102 +       }
4103 +
4104 + finished_expects:
4105 +       READ_UNLOCK(&ip_conntrack_expect_tuple_lock);
4106 + finished:
4107 +       READ_UNLOCK(&ip_conntrack_lock);
4108 +
4109 +       /* `start' hack - see fs/proc/generic.c line ~165 */
4110 +       *start = (char *)((unsigned int)upto - offset);
4111 +       return len;
4112 +}
4113 +
4114 +static unsigned int ip_confirm(unsigned int hooknum,
4115 +                              struct sk_buff **pskb,
4116 +                              const struct net_device *in,
4117 +                              const struct net_device *out,
4118 +                              int (*okfn)(struct sk_buff *))
4119 +{
4120 +       /* We've seen it coming out the other side: confirm it */
4121 +       return ip_conntrack_confirm(*pskb);
4122 +}
4123 +
4124 +static unsigned int ip_refrag(unsigned int hooknum,
4125 +                             struct sk_buff **pskb,
4126 +                             const struct net_device *in,
4127 +                             const struct net_device *out,
4128 +                             int (*okfn)(struct sk_buff *))
4129 +{
4130 +       struct rtable *rt = (struct rtable *)(*pskb)->dst;
4131 +
4132 +       /* We've seen it coming out the other side: confirm */
4133 +       if (ip_confirm(hooknum, pskb, in, out, okfn) != NF_ACCEPT)
4134 +               return NF_DROP;
4135 +
4136 +       /* Local packets are never produced too large for their
4137 +          interface.  We degfragment them at LOCAL_OUT, however,
4138 +          so we have to refragment them here. */
4139 +       if ((*pskb)->len > dst_pmtu(&rt->u.dst) &&
4140 +           !skb_shinfo(*pskb)->tso_size) {
4141 +               /* No hook can be after us, so this should be OK. */
4142 +               ip_fragment(*pskb, okfn);
4143 +               return NF_STOLEN;
4144 +       }
4145 +       return NF_ACCEPT;
4146 +}
4147 +
4148 +static unsigned int ip_conntrack_local(unsigned int hooknum,
4149 +                                      struct sk_buff **pskb,
4150 +                                      const struct net_device *in,
4151 +                                      const struct net_device *out,
4152 +                                      int (*okfn)(struct sk_buff *))
4153 +{
4154 +       /* root is playing with raw sockets. */
4155 +       if ((*pskb)->len < sizeof(struct iphdr)
4156 +           || (*pskb)->nh.iph->ihl * 4 < sizeof(struct iphdr)) {
4157 +               if (net_ratelimit())
4158 +                       printk("ipt_hook: happy cracking.\n");
4159 +               return NF_ACCEPT;
4160 +       }
4161 +       return ip_conntrack_in(hooknum, pskb, in, out, okfn);
4162 +}
4163 +
4164 +/* Connection tracking may drop packets, but never alters them, so
4165 +   make it the first hook. */
4166 +static struct nf_hook_ops ip_conntrack_in_ops = {
4167 +       .hook           = ip_conntrack_in,
4168 +       .owner          = THIS_MODULE,
4169 +       .pf             = PF_INET,
4170 +       .hooknum        = NF_IP_PRE_ROUTING,
4171 +       .priority       = NF_IP_PRI_CONNTRACK,
4172 +};
4173 +
4174 +static struct nf_hook_ops ip_conntrack_local_out_ops = {
4175 +       .hook           = ip_conntrack_local,
4176 +       .owner          = THIS_MODULE,
4177 +       .pf             = PF_INET,
4178 +       .hooknum        = NF_IP_LOCAL_OUT,
4179 +       .priority       = NF_IP_PRI_CONNTRACK,
4180 +};
4181 +
4182 +/* Refragmenter; last chance. */
4183 +static struct nf_hook_ops ip_conntrack_out_ops = {
4184 +       .hook           = ip_refrag,
4185 +       .owner          = THIS_MODULE,
4186 +       .pf             = PF_INET,
4187 +       .hooknum        = NF_IP_POST_ROUTING,
4188 +       .priority       = NF_IP_PRI_LAST,
4189 +};
4190 +
4191 +static struct nf_hook_ops ip_conntrack_local_in_ops = {
4192 +       .hook           = ip_confirm,
4193 +       .owner          = THIS_MODULE,
4194 +       .pf             = PF_INET,
4195 +       .hooknum        = NF_IP_LOCAL_IN,
4196 +       .priority       = NF_IP_PRI_LAST-1,
4197 +};
4198 +
4199 +/* Sysctl support */
4200 +
4201 +#ifdef CONFIG_SYSCTL
4202 +
4203 +/* From ip_conntrack_core.c */
4204 +extern int ip_conntrack_max;
4205 +extern unsigned int ip_conntrack_htable_size;
4206 +
4207 +/* From ip_conntrack_proto_tcp.c */
4208 +extern unsigned long ip_ct_tcp_timeout_syn_sent;
4209 +extern unsigned long ip_ct_tcp_timeout_syn_recv;
4210 +extern unsigned long ip_ct_tcp_timeout_established;
4211 +extern unsigned long ip_ct_tcp_timeout_fin_wait;
4212 +extern unsigned long ip_ct_tcp_timeout_close_wait;
4213 +extern unsigned long ip_ct_tcp_timeout_last_ack;
4214 +extern unsigned long ip_ct_tcp_timeout_time_wait;
4215 +extern unsigned long ip_ct_tcp_timeout_close;
4216 +
4217 +/* From ip_conntrack_proto_udp.c */
4218 +extern unsigned long ip_ct_udp_timeout;
4219 +extern unsigned long ip_ct_udp_timeout_stream;
4220 +
4221 +/* From ip_conntrack_proto_icmp.c */
4222 +extern unsigned long ip_ct_icmp_timeout;
4223 +
4224 +/* From ip_conntrack_proto_icmp.c */
4225 +extern unsigned long ip_ct_generic_timeout;
4226 +
4227 +static struct ctl_table_header *ip_ct_sysctl_header;
4228 +
4229 +static ctl_table ip_ct_sysctl_table[] = {
4230 +       {
4231 +               .ctl_name       = NET_IPV4_NF_CONNTRACK_MAX,
4232 +               .procname       = "ip_conntrack_max",
4233 +               .data           = &ip_conntrack_max,
4234 +               .maxlen         = sizeof(int),
4235 +               .mode           = 0644,
4236 +               .proc_handler   = &proc_dointvec,
4237 +       },
4238 +       {
4239 +               .ctl_name       = NET_IPV4_NF_CONNTRACK_BUCKETS,
4240 +               .procname       = "ip_conntrack_buckets",
4241 +               .data           = &ip_conntrack_htable_size,
4242 +               .maxlen         = sizeof(unsigned int),
4243 +               .mode           = 0444,
4244 +               .proc_handler   = &proc_dointvec,
4245 +       },
4246 +       {
4247 +               .ctl_name       = NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_SYN_SENT,
4248 +               .procname       = "ip_conntrack_tcp_timeout_syn_sent",
4249 +               .data           = &ip_ct_tcp_timeout_syn_sent,
4250 +               .maxlen         = sizeof(unsigned int),
4251 +               .mode           = 0644,
4252 +               .proc_handler   = &proc_dointvec_jiffies,
4253 +       },
4254 +       {
4255 +               .ctl_name       = NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_SYN_RECV,
4256 +               .procname       = "ip_conntrack_tcp_timeout_syn_recv",
4257 +               .data           = &ip_ct_tcp_timeout_syn_recv,
4258 +               .maxlen         = sizeof(unsigned int),
4259 +               .mode           = 0644,
4260 +               .proc_handler   = &proc_dointvec_jiffies,
4261 +       },
4262 +       {
4263 +               .ctl_name       = NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_ESTABLISHED,
4264 +               .procname       = "ip_conntrack_tcp_timeout_established",
4265 +               .data           = &ip_ct_tcp_timeout_established,
4266 +               .maxlen         = sizeof(unsigned int),
4267 +               .mode           = 0644,
4268 +               .proc_handler   = &proc_dointvec_jiffies,
4269 +       },
4270 +       {
4271 +               .ctl_name       = NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_FIN_WAIT,
4272 +               .procname       = "ip_conntrack_tcp_timeout_fin_wait",
4273 +               .data           = &ip_ct_tcp_timeout_fin_wait,
4274 +               .maxlen         = sizeof(unsigned int),
4275 +               .mode           = 0644,
4276 +               .proc_handler   = &proc_dointvec_jiffies,
4277 +       },
4278 +       {
4279 +               .ctl_name       = NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_CLOSE_WAIT,
4280 +               .procname       = "ip_conntrack_tcp_timeout_close_wait",
4281 +               .data           = &ip_ct_tcp_timeout_close_wait,
4282 +               .maxlen         = sizeof(unsigned int),
4283 +               .mode           = 0644,
4284 +               .proc_handler   = &proc_dointvec_jiffies,
4285 +       },
4286 +       {
4287 +               .ctl_name       = NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_LAST_ACK,
4288 +               .procname       = "ip_conntrack_tcp_timeout_last_ack",
4289 +               .data           = &ip_ct_tcp_timeout_last_ack,
4290 +               .maxlen         = sizeof(unsigned int),
4291 +               .mode           = 0644,
4292 +               .proc_handler   = &proc_dointvec_jiffies,
4293 +       },
4294 +       {
4295 +               .ctl_name       = NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_TIME_WAIT,
4296 +               .procname       = "ip_conntrack_tcp_timeout_time_wait",
4297 +               .data           = &ip_ct_tcp_timeout_time_wait,
4298 +               .maxlen         = sizeof(unsigned int),
4299 +               .mode           = 0644,
4300 +               .proc_handler   = &proc_dointvec_jiffies,
4301 +       },
4302 +       {
4303 +               .ctl_name       = NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_CLOSE,
4304 +               .procname       = "ip_conntrack_tcp_timeout_close",
4305 +               .data           = &ip_ct_tcp_timeout_close,
4306 +               .maxlen         = sizeof(unsigned int),
4307 +               .mode           = 0644,
4308 +               .proc_handler   = &proc_dointvec_jiffies,
4309 +       },
4310 +       {
4311 +               .ctl_name       = NET_IPV4_NF_CONNTRACK_UDP_TIMEOUT,
4312 +               .procname       = "ip_conntrack_udp_timeout",
4313 +               .data           = &ip_ct_udp_timeout,
4314 +               .maxlen         = sizeof(unsigned int),
4315 +               .mode           = 0644,
4316 +               .proc_handler   = &proc_dointvec_jiffies,
4317 +       },
4318 +       {
4319 +               .ctl_name       = NET_IPV4_NF_CONNTRACK_UDP_TIMEOUT_STREAM,
4320 +               .procname       = "ip_conntrack_udp_timeout_stream",
4321 +               .data           = &ip_ct_udp_timeout_stream,
4322 +               .maxlen         = sizeof(unsigned int),
4323 +               .mode           = 0644,
4324 +               .proc_handler   = &proc_dointvec_jiffies,
4325 +       },
4326 +       {
4327 +               .ctl_name       = NET_IPV4_NF_CONNTRACK_ICMP_TIMEOUT,
4328 +               .procname       = "ip_conntrack_icmp_timeout",
4329 +               .data           = &ip_ct_icmp_timeout,
4330 +               .maxlen         = sizeof(unsigned int),
4331 +               .mode           = 0644,
4332 +               .proc_handler   = &proc_dointvec_jiffies,
4333 +       },
4334 +       {
4335 +               .ctl_name       = NET_IPV4_NF_CONNTRACK_GENERIC_TIMEOUT,
4336 +               .procname       = "ip_conntrack_generic_timeout",
4337 +               .data           = &ip_ct_generic_timeout,
4338 +               .maxlen         = sizeof(unsigned int),
4339 +               .mode           = 0644,
4340 +               .proc_handler   = &proc_dointvec_jiffies,
4341 +       },
4342 +       { .ctl_name = 0 }
4343 +};
4344 +
4345 +#define NET_IP_CONNTRACK_MAX 2089
4346 +
4347 +static ctl_table ip_ct_netfilter_table[] = {
4348 +       {
4349 +               .ctl_name       = NET_IPV4_NETFILTER,
4350 +               .procname       = "netfilter",
4351 +               .mode           = 0555,
4352 +               .child          = ip_ct_sysctl_table,
4353 +       },
4354 +       {
4355 +               .ctl_name       = NET_IP_CONNTRACK_MAX,
4356 +               .procname       = "ip_conntrack_max",
4357 +               .data           = &ip_conntrack_max,
4358 +               .maxlen         = sizeof(int),
4359 +               .mode           = 0644,
4360 +               .proc_handler   = &proc_dointvec
4361 +       },
4362 +       { .ctl_name = 0 }
4363 +};
4364 +
4365 +static ctl_table ip_ct_ipv4_table[] = {
4366 +       {
4367 +               .ctl_name       = NET_IPV4,
4368 +               .procname       = "ipv4",
4369 +               .mode           = 0555,
4370 +               .child          = ip_ct_netfilter_table,
4371 +       },
4372 +       { .ctl_name = 0 }
4373 +};
4374 +
4375 +static ctl_table ip_ct_net_table[] = {
4376 +       {
4377 +               .ctl_name       = CTL_NET,
4378 +               .procname       = "net",
4379 +               .mode           = 0555, 
4380 +               .child          = ip_ct_ipv4_table,
4381 +       },
4382 +       { .ctl_name = 0 }
4383 +};
4384 +#endif
4385 +static int init_or_cleanup(int init)
4386 +{
4387 +       struct proc_dir_entry *proc;
4388 +       int ret = 0;
4389 +
4390 +       if (!init) goto cleanup;
4391 +
4392 +       ret = ip_conntrack_init();
4393 +       if (ret < 0)
4394 +               goto cleanup_nothing;
4395 +
4396 +       proc = proc_net_create("ip_conntrack",0,list_conntracks);
4397 +       if (!proc) goto cleanup_init;
4398 +       proc->owner = THIS_MODULE;
4399 +
4400 +       ret = nf_register_hook(&ip_conntrack_in_ops);
4401 +       if (ret < 0) {
4402 +               printk("ip_conntrack: can't register pre-routing hook.\n");
4403 +               goto cleanup_proc;
4404 +       }
4405 +       ret = nf_register_hook(&ip_conntrack_local_out_ops);
4406 +       if (ret < 0) {
4407 +               printk("ip_conntrack: can't register local out hook.\n");
4408 +               goto cleanup_inops;
4409 +       }
4410 +       ret = nf_register_hook(&ip_conntrack_out_ops);
4411 +       if (ret < 0) {
4412 +               printk("ip_conntrack: can't register post-routing hook.\n");
4413 +               goto cleanup_inandlocalops;
4414 +       }
4415 +       ret = nf_register_hook(&ip_conntrack_local_in_ops);
4416 +       if (ret < 0) {
4417 +               printk("ip_conntrack: can't register local in hook.\n");
4418 +               goto cleanup_inoutandlocalops;
4419 +       }
4420 +#ifdef CONFIG_SYSCTL
4421 +       ip_ct_sysctl_header = register_sysctl_table(ip_ct_net_table, 0);
4422 +       if (ip_ct_sysctl_header == NULL) {
4423 +               printk("ip_conntrack: can't register to sysctl.\n");
4424 +               goto cleanup;
4425 +       }
4426 +#endif
4427 +
4428 +       return ret;
4429 +
4430 + cleanup:
4431 +#ifdef CONFIG_SYSCTL
4432 +       unregister_sysctl_table(ip_ct_sysctl_header);
4433 +#endif
4434 +       nf_unregister_hook(&ip_conntrack_local_in_ops);
4435 + cleanup_inoutandlocalops:
4436 +       nf_unregister_hook(&ip_conntrack_out_ops);
4437 + cleanup_inandlocalops:
4438 +       nf_unregister_hook(&ip_conntrack_local_out_ops);
4439 + cleanup_inops:
4440 +       nf_unregister_hook(&ip_conntrack_in_ops);
4441 + cleanup_proc:
4442 +       proc_net_remove("ip_conntrack");
4443 + cleanup_init:
4444 +       ip_conntrack_cleanup();
4445 + cleanup_nothing:
4446 +       return ret;
4447 +}
4448 +
4449 +/**
4450 + * ip_conntrack_protocol_register - Register layer 4 protocol helper
4451 + * @proto: structure describing this layer 4 protocol helper
4452 + *
4453 + * This function is called by layer 4 protocol helpers to register 
4454 + * themselves with the conntrack core.
4455 + */
4456 +int ip_conntrack_protocol_register(struct ip_conntrack_protocol *proto)
4457 +{
4458 +       int ret = 0;
4459 +       struct list_head *i;
4460 +
4461 +       /* FIXME: Allow NULL functions and sub in pointers to generic for
4462 +          them. --RR */
4463 +       WRITE_LOCK(&ip_conntrack_lock);
4464 +       list_for_each(i, &protocol_list) {
4465 +               if (((struct ip_conntrack_protocol *)i)->proto
4466 +                   == proto->proto) {
4467 +                       ret = -EBUSY;
4468 +                       goto out;
4469 +               }
4470 +       }
4471 +
4472 +       list_prepend(&protocol_list, proto);
4473 +
4474 + out:
4475 +       WRITE_UNLOCK(&ip_conntrack_lock);
4476 +       return ret;
4477 +}
4478 +
4479 +/**
4480 + * ip_conntrack_protocol_unregister - Unregister layer 4 protocol helper
4481 + * @proto: structure describing this layer 4 protocol helper
4482 + *
4483 + * This function is called byh layer 4 protocol helpers to unregister
4484 + * themselvers from the conntrack core.  Please note that all conntrack
4485 + * entries for this protocol are deleted from the conntrack hash table.
4486 + */
4487 +void ip_conntrack_protocol_unregister(struct ip_conntrack_protocol *proto)
4488 +{
4489 +       WRITE_LOCK(&ip_conntrack_lock);
4490 +
4491 +       /* ip_ct_find_proto() returns proto_generic in case there is no
4492 +        * protocol helper. So this should be enough - HW */
4493 +       LIST_DELETE(&protocol_list, proto);
4494 +       WRITE_UNLOCK(&ip_conntrack_lock);
4495 +       
4496 +       /* Somebody could be still looking at the proto in bh. */
4497 +       synchronize_net();
4498 +
4499 +       /* Remove all contrack entries for this protocol */
4500 +       ip_ct_selective_cleanup(kill_proto, &proto->proto);
4501 +}
4502 +
4503 +static int __init init(void)
4504 +{
4505 +       return init_or_cleanup(1);
4506 +}
4507 +
4508 +static void __exit fini(void)
4509 +{
4510 +       init_or_cleanup(0);
4511 +}
4512 +
4513 +module_init(init);
4514 +module_exit(fini);
4515 +
4516 +/* Some modules need us, but don't depend directly on any symbol.
4517 +   They should call this. */
4518 +void need_ip_conntrack(void)
4519 +{
4520 +}
4521 +
4522 +EXPORT_SYMBOL(ip_conntrack_protocol_register);
4523 +EXPORT_SYMBOL(ip_conntrack_protocol_unregister);
4524 +EXPORT_SYMBOL(invert_tuplepr);
4525 +EXPORT_SYMBOL(ip_conntrack_alter_reply);
4526 +EXPORT_SYMBOL(ip_conntrack_destroyed);
4527 +EXPORT_SYMBOL(ip_conntrack_get);
4528 +EXPORT_SYMBOL(need_ip_conntrack);
4529 +EXPORT_SYMBOL(ip_conntrack_helper_register);
4530 +EXPORT_SYMBOL(ip_conntrack_helper_unregister);
4531 +EXPORT_SYMBOL(ip_ct_selective_cleanup);
4532 +EXPORT_SYMBOL(ip_ct_refresh);
4533 +EXPORT_SYMBOL(ip_ct_find_proto);
4534 +EXPORT_SYMBOL(__ip_ct_find_proto);
4535 +EXPORT_SYMBOL(ip_ct_find_helper);
4536 +EXPORT_SYMBOL(ip_conntrack_expect_related);
4537 +EXPORT_SYMBOL(ip_conntrack_change_expect);
4538 +EXPORT_SYMBOL(ip_conntrack_unexpect_related);
4539 +EXPORT_SYMBOL_GPL(ip_conntrack_expect_find_get);
4540 +EXPORT_SYMBOL_GPL(ip_conntrack_expect_put);
4541 +EXPORT_SYMBOL(ip_conntrack_tuple_taken);
4542 +EXPORT_SYMBOL(ip_ct_gather_frags);
4543 +EXPORT_SYMBOL(ip_conntrack_htable_size);
4544 +EXPORT_SYMBOL(ip_conntrack_expect_list);
4545 +EXPORT_SYMBOL(ip_conntrack_lock);
4546 +EXPORT_SYMBOL(ip_conntrack_hash);
4547 +EXPORT_SYMBOL_GPL(ip_conntrack_find_get);
4548 +EXPORT_SYMBOL_GPL(ip_conntrack_put);
4549 diff -Nur linux-2.6.4-rc2.org/net/ipv4/netfilter/ip_nat_core.c linux-2.6.4-rc2/net/ipv4/netfilter/ip_nat_core.c
4550 --- linux-2.6.4-rc2.org/net/ipv4/netfilter/ip_nat_core.c        2004-03-04 06:16:37.000000000 +0000
4551 +++ linux-2.6.4-rc2/net/ipv4/netfilter/ip_nat_core.c    2004-03-05 09:55:23.000000000 +0000
4552 @@ -96,9 +96,16 @@
4553         WRITE_UNLOCK(&ip_nat_lock);
4554  }
4555  
4556 -/* We do checksum mangling, so if they were wrong before they're still
4557 - * wrong.  Also works for incomplete packets (eg. ICMP dest
4558 - * unreachables.) */
4559 +/**
4560 + * ip_nat_cheat_check - Incremental checksum change for IP/TCP checksum
4561 + * @oldvalinv: bit-inverted old value of 32bit word
4562 + * @newval: new value of 32bit word
4563 + * @oldcheck: old checksum value
4564 + *
4565 + * This function implements incremental checksum mangling, so if a checksum
4566 + * was wrong it will still be wrong after mangling.  Also works for incomplete
4567 + * packets (eg. ICMP dest unreachables).  Return value is the new checksum.
4568 + */
4569  u_int16_t
4570  ip_nat_cheat_check(u_int32_t oldvalinv, u_int32_t newval, u_int16_t oldcheck)
4571  {
4572 @@ -124,7 +131,14 @@
4573         return i;
4574  }
4575  
4576 -/* Is this tuple already taken? (not by us) */
4577 +/**
4578 + * ip_nat_used_tuple - Is this tuple already in use?
4579 + * @tuple: tuple to be used for this check
4580 + * @ignored_conntrack: conntrack excluded from this check
4581 + *
4582 + * This function checks for the reply (inverted) tuple in the conntrack
4583 + * hash.  This is necessarry with NAT, since there is no fixed mapping.
4584 + */
4585  int
4586  ip_nat_used_tuple(const struct ip_conntrack_tuple *tuple,
4587                   const struct ip_conntrack *ignored_conntrack)
4588 @@ -515,6 +529,19 @@
4589  #endif
4590  };
4591  
4592 +/**
4593 + * ip_nat_setup_info - Set up NAT mappings for NEW packet
4594 + * @conntrack: conntrack on which we operate
4595 + * @mr: address/port range which is valid for this NAT mapping
4596 + * @hooknum: hook at which this NAT mapping applies
4597 + *
4598 + * This function is called by NAT targets (SNAT,DNAT,...) and by
4599 + * the NAT application helper modules.  It is called for the NEW packet
4600 + * of a connection in order to specify which NAT mappings shall apply to
4601 + * this connection at a given hook.
4602 + *
4603 + * Note: The reply mappings are created automagically by this function. 
4604 + */
4605  unsigned int
4606  ip_nat_setup_info(struct ip_conntrack *conntrack,
4607                   const struct ip_nat_multi_range *mr,
4608 @@ -1016,6 +1043,10 @@
4609         /* FIXME: Man, this is a hack.  <SIGH> */
4610         IP_NF_ASSERT(ip_conntrack_destroyed == NULL);
4611         ip_conntrack_destroyed = &ip_nat_cleanup_conntrack;
4612 +       
4613 +       /* Initialize fake conntrack so that NAT will skip it */
4614 +       ip_conntrack_untracked.nat.info.initialized |= 
4615 +               (1 << IP_NAT_MANIP_SRC) | (1 << IP_NAT_MANIP_DST);
4616  
4617         return 0;
4618  }
4619 diff -Nur linux-2.6.4-rc2.org/net/ipv4/netfilter/ip_nat_core.c.orig linux-2.6.4-rc2/net/ipv4/netfilter/ip_nat_core.c.orig
4620 --- linux-2.6.4-rc2.org/net/ipv4/netfilter/ip_nat_core.c.orig   1970-01-01 00:00:00.000000000 +0000
4621 +++ linux-2.6.4-rc2/net/ipv4/netfilter/ip_nat_core.c.orig       2004-03-05 09:55:06.000000000 +0000
4622 @@ -0,0 +1,1063 @@
4623 +/* NAT for netfilter; shared with compatibility layer. */
4624 +
4625 +/* (C) 1999-2001 Paul `Rusty' Russell
4626 + * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org>
4627 + *
4628 + * This program is free software; you can redistribute it and/or modify
4629 + * it under the terms of the GNU General Public License version 2 as
4630 + * published by the Free Software Foundation.
4631 + */
4632 +
4633 +#include <linux/module.h>
4634 +#include <linux/types.h>
4635 +#include <linux/timer.h>
4636 +#include <linux/skbuff.h>
4637 +#include <linux/netfilter_ipv4.h>
4638 +#include <linux/vmalloc.h>
4639 +#include <net/checksum.h>
4640 +#include <net/icmp.h>
4641 +#include <net/ip.h>
4642 +#include <net/tcp.h>  /* For tcp_prot in getorigdst */
4643 +#include <linux/icmp.h>
4644 +#include <linux/udp.h>
4645 +
4646 +#define ASSERT_READ_LOCK(x) MUST_BE_READ_LOCKED(&ip_nat_lock)
4647 +#define ASSERT_WRITE_LOCK(x) MUST_BE_WRITE_LOCKED(&ip_nat_lock)
4648 +
4649 +#include <linux/netfilter_ipv4/ip_conntrack.h>
4650 +#include <linux/netfilter_ipv4/ip_conntrack_core.h>
4651 +#include <linux/netfilter_ipv4/ip_conntrack_protocol.h>
4652 +#include <linux/netfilter_ipv4/ip_nat.h>
4653 +#include <linux/netfilter_ipv4/ip_nat_protocol.h>
4654 +#include <linux/netfilter_ipv4/ip_nat_core.h>
4655 +#include <linux/netfilter_ipv4/ip_nat_helper.h>
4656 +#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
4657 +#include <linux/netfilter_ipv4/listhelp.h>
4658 +
4659 +#if 0
4660 +#define DEBUGP printk
4661 +#else
4662 +#define DEBUGP(format, args...)
4663 +#endif
4664 +
4665 +DECLARE_RWLOCK(ip_nat_lock);
4666 +DECLARE_RWLOCK_EXTERN(ip_conntrack_lock);
4667 +
4668 +/* Calculated at init based on memory size */
4669 +static unsigned int ip_nat_htable_size;
4670 +
4671 +static struct list_head *bysource;
4672 +static struct list_head *byipsproto;
4673 +LIST_HEAD(protos);
4674 +LIST_HEAD(helpers);
4675 +
4676 +extern struct ip_nat_protocol unknown_nat_protocol;
4677 +
4678 +/* We keep extra hashes for each conntrack, for fast searching. */
4679 +static inline size_t
4680 +hash_by_ipsproto(u_int32_t src, u_int32_t dst, u_int16_t proto)
4681 +{
4682 +       /* Modified src and dst, to ensure we don't create two
4683 +           identical streams. */
4684 +       return (src + dst + proto) % ip_nat_htable_size;
4685 +}
4686 +
4687 +static inline size_t
4688 +hash_by_src(const struct ip_conntrack_manip *manip, u_int16_t proto)
4689 +{
4690 +       /* Original src, to ensure we map it consistently if poss. */
4691 +       return (manip->ip + manip->u.all + proto) % ip_nat_htable_size;
4692 +}
4693 +
4694 +/* Noone using conntrack by the time this called. */
4695 +static void ip_nat_cleanup_conntrack(struct ip_conntrack *conn)
4696 +{
4697 +       struct ip_nat_info *info = &conn->nat.info;
4698 +       unsigned int hs, hp;
4699 +
4700 +       if (!info->initialized)
4701 +               return;
4702 +
4703 +       IP_NF_ASSERT(info->bysource.conntrack);
4704 +       IP_NF_ASSERT(info->byipsproto.conntrack);
4705 +
4706 +       hs = hash_by_src(&conn->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src,
4707 +                        conn->tuplehash[IP_CT_DIR_ORIGINAL]
4708 +                        .tuple.dst.protonum);
4709 +
4710 +       hp = hash_by_ipsproto(conn->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip,
4711 +                             conn->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip,
4712 +                             conn->tuplehash[IP_CT_DIR_REPLY]
4713 +                             .tuple.dst.protonum);
4714 +
4715 +       WRITE_LOCK(&ip_nat_lock);
4716 +       LIST_DELETE(&bysource[hs], &info->bysource);
4717 +       LIST_DELETE(&byipsproto[hp], &info->byipsproto);
4718 +       WRITE_UNLOCK(&ip_nat_lock);
4719 +}
4720 +
4721 +/**
4722 + * ip_nat_cheat_check - Incremental checksum change for IP/TCP checksum
4723 + * @oldvalinv: bit-inverted old value of 32bit word
4724 + * @newval: new value of 32bit word
4725 + * @oldcheck: old checksum value
4726 + *
4727 + * This function implements incremental checksum mangling, so if a checksum
4728 + * was wrong it will still be wrong after mangling.  Also works for incomplete
4729 + * packets (eg. ICMP dest unreachables).  Return value is the new checksum.
4730 + */
4731 +u_int16_t
4732 +ip_nat_cheat_check(u_int32_t oldvalinv, u_int32_t newval, u_int16_t oldcheck)
4733 +{
4734 +       u_int32_t diffs[] = { oldvalinv, newval };
4735 +       return csum_fold(csum_partial((char *)diffs, sizeof(diffs),
4736 +                                     oldcheck^0xFFFF));
4737 +}
4738 +
4739 +static inline int cmp_proto(const struct ip_nat_protocol *i, int proto)
4740 +{
4741 +       return i->protonum == proto;
4742 +}
4743 +
4744 +struct ip_nat_protocol *
4745 +find_nat_proto(u_int16_t protonum)
4746 +{
4747 +       struct ip_nat_protocol *i;
4748 +
4749 +       MUST_BE_READ_LOCKED(&ip_nat_lock);
4750 +       i = LIST_FIND(&protos, cmp_proto, struct ip_nat_protocol *, protonum);
4751 +       if (!i)
4752 +               i = &unknown_nat_protocol;
4753 +       return i;
4754 +}
4755 +
4756 +/**
4757 + * ip_nat_used_tuple - Is this tuple already in use?
4758 + * @tuple: tuple to be used for this check
4759 + * @ignored_conntrack: conntrack excluded from this check
4760 + *
4761 + * This function checks for the reply (inverted) tuple in the conntrack
4762 + * hash.  This is necessarry with NAT, since there is no fixed mapping.
4763 + */
4764 +int
4765 +ip_nat_used_tuple(const struct ip_conntrack_tuple *tuple,
4766 +                 const struct ip_conntrack *ignored_conntrack)
4767 +{
4768 +       /* Conntrack tracking doesn't keep track of outgoing tuples; only
4769 +          incoming ones.  NAT means they don't have a fixed mapping,
4770 +          so we invert the tuple and look for the incoming reply.
4771 +
4772 +          We could keep a separate hash if this proves too slow. */
4773 +       struct ip_conntrack_tuple reply;
4774 +
4775 +       invert_tuplepr(&reply, tuple);
4776 +       return ip_conntrack_tuple_taken(&reply, ignored_conntrack);
4777 +}
4778 +
4779 +/* Does tuple + the source manip come within the range mr */
4780 +static int
4781 +in_range(const struct ip_conntrack_tuple *tuple,
4782 +        const struct ip_conntrack_manip *manip,
4783 +        const struct ip_nat_multi_range *mr)
4784 +{
4785 +       struct ip_nat_protocol *proto = find_nat_proto(tuple->dst.protonum);
4786 +       unsigned int i;
4787 +       struct ip_conntrack_tuple newtuple = { *manip, tuple->dst };
4788 +
4789 +       for (i = 0; i < mr->rangesize; i++) {
4790 +               /* If we are allowed to map IPs, then we must be in the
4791 +                  range specified, otherwise we must be unchanged. */
4792 +               if (mr->range[i].flags & IP_NAT_RANGE_MAP_IPS) {
4793 +                       if (ntohl(newtuple.src.ip) < ntohl(mr->range[i].min_ip)
4794 +                           || (ntohl(newtuple.src.ip)
4795 +                               > ntohl(mr->range[i].max_ip)))
4796 +                               continue;
4797 +               } else {
4798 +                       if (newtuple.src.ip != tuple->src.ip)
4799 +                               continue;
4800 +               }
4801 +
4802 +               if (!(mr->range[i].flags & IP_NAT_RANGE_PROTO_SPECIFIED)
4803 +                   || proto->in_range(&newtuple, IP_NAT_MANIP_SRC,
4804 +                                      &mr->range[i].min, &mr->range[i].max))
4805 +                       return 1;
4806 +       }
4807 +       return 0;
4808 +}
4809 +
4810 +static inline int
4811 +src_cmp(const struct ip_nat_hash *i,
4812 +       const struct ip_conntrack_tuple *tuple,
4813 +       const struct ip_nat_multi_range *mr)
4814 +{
4815 +       return (i->conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum
4816 +               == tuple->dst.protonum
4817 +               && i->conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip
4818 +               == tuple->src.ip
4819 +               && i->conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.all
4820 +               == tuple->src.u.all
4821 +               && in_range(tuple,
4822 +                           &i->conntrack->tuplehash[IP_CT_DIR_ORIGINAL]
4823 +                           .tuple.src,
4824 +                           mr));
4825 +}
4826 +
4827 +/* Only called for SRC manip */
4828 +static struct ip_conntrack_manip *
4829 +find_appropriate_src(const struct ip_conntrack_tuple *tuple,
4830 +                    const struct ip_nat_multi_range *mr)
4831 +{
4832 +       unsigned int h = hash_by_src(&tuple->src, tuple->dst.protonum);
4833 +       struct ip_nat_hash *i;
4834 +
4835 +       MUST_BE_READ_LOCKED(&ip_nat_lock);
4836 +       i = LIST_FIND(&bysource[h], src_cmp, struct ip_nat_hash *, tuple, mr);
4837 +       if (i)
4838 +               return &i->conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src;
4839 +       else
4840 +               return NULL;
4841 +}
4842 +
4843 +#ifdef CONFIG_IP_NF_NAT_LOCAL
4844 +/* If it's really a local destination manip, it may need to do a
4845 +   source manip too. */
4846 +static int
4847 +do_extra_mangle(u_int32_t var_ip, u_int32_t *other_ipp)
4848 +{
4849 +       struct flowi fl = { .nl_u = { .ip4_u = { .daddr = var_ip } } };
4850 +       struct rtable *rt;
4851 +
4852 +       /* FIXME: IPTOS_TOS(iph->tos) --RR */
4853 +       if (ip_route_output_key(&rt, &fl) != 0) {
4854 +               DEBUGP("do_extra_mangle: Can't get route to %u.%u.%u.%u\n",
4855 +                      NIPQUAD(var_ip));
4856 +               return 0;
4857 +       }
4858 +
4859 +       *other_ipp = rt->rt_src;
4860 +       ip_rt_put(rt);
4861 +       return 1;
4862 +}
4863 +#endif
4864 +
4865 +/* Simple way to iterate through all. */
4866 +static inline int fake_cmp(const struct ip_nat_hash *i,
4867 +                          u_int32_t src, u_int32_t dst, u_int16_t protonum,
4868 +                          unsigned int *score,
4869 +                          const struct ip_conntrack *conntrack)
4870 +{
4871 +       /* Compare backwards: we're dealing with OUTGOING tuples, and
4872 +           inside the conntrack is the REPLY tuple.  Don't count this
4873 +           conntrack. */
4874 +       if (i->conntrack != conntrack
4875 +           && i->conntrack->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip == dst
4876 +           && i->conntrack->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip == src
4877 +           && (i->conntrack->tuplehash[IP_CT_DIR_REPLY].tuple.dst.protonum
4878 +               == protonum))
4879 +               (*score)++;
4880 +       return 0;
4881 +}
4882 +
4883 +static inline unsigned int
4884 +count_maps(u_int32_t src, u_int32_t dst, u_int16_t protonum,
4885 +          const struct ip_conntrack *conntrack)
4886 +{
4887 +       unsigned int score = 0;
4888 +       unsigned int h;
4889 +
4890 +       MUST_BE_READ_LOCKED(&ip_nat_lock);
4891 +       h = hash_by_ipsproto(src, dst, protonum);
4892 +       LIST_FIND(&byipsproto[h], fake_cmp, struct ip_nat_hash *,
4893 +                 src, dst, protonum, &score, conntrack);
4894 +
4895 +       return score;
4896 +}
4897 +
4898 +/* For [FUTURE] fragmentation handling, we want the least-used
4899 +   src-ip/dst-ip/proto triple.  Fairness doesn't come into it.  Thus
4900 +   if the range specifies 1.2.3.4 ports 10000-10005 and 1.2.3.5 ports
4901 +   1-65535, we don't do pro-rata allocation based on ports; we choose
4902 +   the ip with the lowest src-ip/dst-ip/proto usage.
4903 +
4904 +   If an allocation then fails (eg. all 6 ports used in the 1.2.3.4
4905 +   range), we eliminate that and try again.  This is not the most
4906 +   efficient approach, but if you're worried about that, don't hand us
4907 +   ranges you don't really have.  */
4908 +static struct ip_nat_range *
4909 +find_best_ips_proto(struct ip_conntrack_tuple *tuple,
4910 +                   const struct ip_nat_multi_range *mr,
4911 +                   const struct ip_conntrack *conntrack,
4912 +                   unsigned int hooknum)
4913 +{
4914 +       unsigned int i;
4915 +       struct {
4916 +               const struct ip_nat_range *range;
4917 +               unsigned int score;
4918 +               struct ip_conntrack_tuple tuple;
4919 +       } best = { NULL,  0xFFFFFFFF };
4920 +       u_int32_t *var_ipp, *other_ipp, saved_ip, orig_dstip;
4921 +       static unsigned int randomness;
4922 +
4923 +       if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC) {
4924 +               var_ipp = &tuple->src.ip;
4925 +               saved_ip = tuple->dst.ip;
4926 +               other_ipp = &tuple->dst.ip;
4927 +       } else {
4928 +               var_ipp = &tuple->dst.ip;
4929 +               saved_ip = tuple->src.ip;
4930 +               other_ipp = &tuple->src.ip;
4931 +       }
4932 +       /* Don't do do_extra_mangle unless necessary (overrides
4933 +           explicit socket bindings, for example) */
4934 +       orig_dstip = tuple->dst.ip;
4935 +
4936 +       IP_NF_ASSERT(mr->rangesize >= 1);
4937 +       for (i = 0; i < mr->rangesize; i++) {
4938 +               /* Host order */
4939 +               u_int32_t minip, maxip, j;
4940 +
4941 +               /* Don't do ranges which are already eliminated. */
4942 +               if (mr->range[i].flags & IP_NAT_RANGE_FULL) {
4943 +                       continue;
4944 +               }
4945 +
4946 +               if (mr->range[i].flags & IP_NAT_RANGE_MAP_IPS) {
4947 +                       minip = ntohl(mr->range[i].min_ip);
4948 +                       maxip = ntohl(mr->range[i].max_ip);
4949 +               } else
4950 +                       minip = maxip = ntohl(*var_ipp);
4951 +
4952 +               randomness++;
4953 +               for (j = 0; j < maxip - minip + 1; j++) {
4954 +                       unsigned int score;
4955 +
4956 +                       *var_ipp = htonl(minip + (randomness + j) 
4957 +                                        % (maxip - minip + 1));
4958 +
4959 +                       /* Reset the other ip in case it was mangled by
4960 +                        * do_extra_mangle last time. */
4961 +                       *other_ipp = saved_ip;
4962 +
4963 +#ifdef CONFIG_IP_NF_NAT_LOCAL
4964 +                       if (hooknum == NF_IP_LOCAL_OUT
4965 +                           && *var_ipp != orig_dstip
4966 +                           && !do_extra_mangle(*var_ipp, other_ipp)) {
4967 +                               DEBUGP("Range %u %u.%u.%u.%u rt failed!\n",
4968 +                                      i, NIPQUAD(*var_ipp));
4969 +                               /* Can't route?  This whole range part is
4970 +                                * probably screwed, but keep trying
4971 +                                * anyway. */
4972 +                               continue;
4973 +                       }
4974 +#endif
4975 +
4976 +                       /* Count how many others map onto this. */
4977 +                       score = count_maps(tuple->src.ip, tuple->dst.ip,
4978 +                                          tuple->dst.protonum, conntrack);
4979 +                       if (score < best.score) {
4980 +                               /* Optimization: doesn't get any better than
4981 +                                  this. */
4982 +                               if (score == 0)
4983 +                                       return (struct ip_nat_range *)
4984 +                                               &mr->range[i];
4985 +
4986 +                               best.score = score;
4987 +                               best.tuple = *tuple;
4988 +                               best.range = &mr->range[i];
4989 +                       }
4990 +               }
4991 +       }
4992 +       *tuple = best.tuple;
4993 +
4994 +       /* Discard const. */
4995 +       return (struct ip_nat_range *)best.range;
4996 +}
4997 +
4998 +/* Fast version doesn't iterate through hash chains, but only handles
4999 +   common case of single IP address (null NAT, masquerade) */
5000 +static struct ip_nat_range *
5001 +find_best_ips_proto_fast(struct ip_conntrack_tuple *tuple,
5002 +                        const struct ip_nat_multi_range *mr,
5003 +                        const struct ip_conntrack *conntrack,
5004 +                        unsigned int hooknum)
5005 +{
5006 +       if (mr->rangesize != 1
5007 +           || (mr->range[0].flags & IP_NAT_RANGE_FULL)
5008 +           || ((mr->range[0].flags & IP_NAT_RANGE_MAP_IPS)
5009 +               && mr->range[0].min_ip != mr->range[0].max_ip))
5010 +               return find_best_ips_proto(tuple, mr, conntrack, hooknum);
5011 +
5012 +       if (mr->range[0].flags & IP_NAT_RANGE_MAP_IPS) {
5013 +               if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC)
5014 +                       tuple->src.ip = mr->range[0].min_ip;
5015 +               else {
5016 +                       /* Only do extra mangle when required (breaks
5017 +                           socket binding) */
5018 +#ifdef CONFIG_IP_NF_NAT_LOCAL
5019 +                       if (tuple->dst.ip != mr->range[0].min_ip
5020 +                           && hooknum == NF_IP_LOCAL_OUT
5021 +                           && !do_extra_mangle(mr->range[0].min_ip,
5022 +                                               &tuple->src.ip))
5023 +                               return NULL;
5024 +#endif
5025 +                       tuple->dst.ip = mr->range[0].min_ip;
5026 +               }
5027 +       }
5028 +
5029 +       /* Discard const. */
5030 +       return (struct ip_nat_range *)&mr->range[0];
5031 +}
5032 +
5033 +static int
5034 +get_unique_tuple(struct ip_conntrack_tuple *tuple,
5035 +                const struct ip_conntrack_tuple *orig_tuple,
5036 +                const struct ip_nat_multi_range *mrr,
5037 +                struct ip_conntrack *conntrack,
5038 +                unsigned int hooknum)
5039 +{
5040 +       struct ip_nat_protocol *proto
5041 +               = find_nat_proto(orig_tuple->dst.protonum);
5042 +       struct ip_nat_range *rptr;
5043 +       unsigned int i;
5044 +       int ret;
5045 +
5046 +       /* We temporarily use flags for marking full parts, but we
5047 +          always clean up afterwards */
5048 +       struct ip_nat_multi_range *mr = (void *)mrr;
5049 +
5050 +       /* 1) If this srcip/proto/src-proto-part is currently mapped,
5051 +          and that same mapping gives a unique tuple within the given
5052 +          range, use that.
5053 +
5054 +          This is only required for source (ie. NAT/masq) mappings.
5055 +          So far, we don't do local source mappings, so multiple
5056 +          manips not an issue.  */
5057 +       if (hooknum == NF_IP_POST_ROUTING) {
5058 +               struct ip_conntrack_manip *manip;
5059 +
5060 +               manip = find_appropriate_src(orig_tuple, mr);
5061 +               if (manip) {
5062 +                       /* Apply same source manipulation. */
5063 +                       *tuple = ((struct ip_conntrack_tuple)
5064 +                                 { *manip, orig_tuple->dst });
5065 +                       DEBUGP("get_unique_tuple: Found current src map\n");
5066 +                       if (!ip_nat_used_tuple(tuple, conntrack))
5067 +                               return 1;
5068 +               }
5069 +       }
5070 +
5071 +       /* 2) Select the least-used IP/proto combination in the given
5072 +          range.
5073 +       */
5074 +       *tuple = *orig_tuple;
5075 +       while ((rptr = find_best_ips_proto_fast(tuple, mr, conntrack, hooknum))
5076 +              != NULL) {
5077 +               DEBUGP("Found best for "); DUMP_TUPLE(tuple);
5078 +               /* 3) The per-protocol part of the manip is made to
5079 +                  map into the range to make a unique tuple. */
5080 +
5081 +               /* Only bother mapping if it's not already in range
5082 +                  and unique */
5083 +               if ((!(rptr->flags & IP_NAT_RANGE_PROTO_SPECIFIED)
5084 +                    || proto->in_range(tuple, HOOK2MANIP(hooknum),
5085 +                                       &rptr->min, &rptr->max))
5086 +                   && !ip_nat_used_tuple(tuple, conntrack)) {
5087 +                       ret = 1;
5088 +                       goto clear_fulls;
5089 +               } else {
5090 +                       if (proto->unique_tuple(tuple, rptr,
5091 +                                               HOOK2MANIP(hooknum),
5092 +                                               conntrack)) {
5093 +                               /* Must be unique. */
5094 +                               IP_NF_ASSERT(!ip_nat_used_tuple(tuple,
5095 +                                                               conntrack));
5096 +                               ret = 1;
5097 +                               goto clear_fulls;
5098 +                       } else if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_DST) {
5099 +                               /* Try implicit source NAT; protocol
5100 +                                   may be able to play with ports to
5101 +                                   make it unique. */
5102 +                               struct ip_nat_range r
5103 +                                       = { IP_NAT_RANGE_MAP_IPS, 
5104 +                                           tuple->src.ip, tuple->src.ip,
5105 +                                           { 0 }, { 0 } };
5106 +                               DEBUGP("Trying implicit mapping\n");
5107 +                               if (proto->unique_tuple(tuple, &r,
5108 +                                                       IP_NAT_MANIP_SRC,
5109 +                                                       conntrack)) {
5110 +                                       /* Must be unique. */
5111 +                                       IP_NF_ASSERT(!ip_nat_used_tuple
5112 +                                                    (tuple, conntrack));
5113 +                                       ret = 1;
5114 +                                       goto clear_fulls;
5115 +                               }
5116 +                       }
5117 +                       DEBUGP("Protocol can't get unique tuple %u.\n",
5118 +                              hooknum);
5119 +               }
5120 +
5121 +               /* Eliminate that from range, and try again. */
5122 +               rptr->flags |= IP_NAT_RANGE_FULL;
5123 +               *tuple = *orig_tuple;
5124 +       }
5125 +
5126 +       ret = 0;
5127 +
5128 + clear_fulls:
5129 +       /* Clear full flags. */
5130 +       IP_NF_ASSERT(mr->rangesize >= 1);
5131 +       for (i = 0; i < mr->rangesize; i++)
5132 +               mr->range[i].flags &= ~IP_NAT_RANGE_FULL;
5133 +
5134 +       return ret;
5135 +}
5136 +
5137 +static inline int
5138 +helper_cmp(const struct ip_nat_helper *helper,
5139 +          const struct ip_conntrack_tuple *tuple)
5140 +{
5141 +       return ip_ct_tuple_mask_cmp(tuple, &helper->tuple, &helper->mask);
5142 +}
5143 +
5144 +/* Where to manip the reply packets (will be reverse manip). */
5145 +static unsigned int opposite_hook[NF_IP_NUMHOOKS]
5146 += { [NF_IP_PRE_ROUTING] = NF_IP_POST_ROUTING,
5147 +    [NF_IP_POST_ROUTING] = NF_IP_PRE_ROUTING,
5148 +#ifdef CONFIG_IP_NF_NAT_LOCAL
5149 +    [NF_IP_LOCAL_OUT] = NF_IP_LOCAL_IN,
5150 +    [NF_IP_LOCAL_IN] = NF_IP_LOCAL_OUT,
5151 +#endif
5152 +};
5153 +
5154 +/**
5155 + * ip_nat_setup_info - Set up NAT mappings for NEW packet
5156 + * @conntrack: conntrack on which we operate
5157 + * @mr: address/port range which is valid for this NAT mapping
5158 + * @hooknum: hook at which this NAT mapping applies
5159 + *
5160 + * This function is called by NAT targets (SNAT,DNAT,...) and by
5161 + * the NAT application helper modules.  It is called for the NEW packet
5162 + * of a connection in order to specify which NAT mappings shall apply to
5163 + * this connection at a given hook.
5164 + *
5165 + * Note: The reply mappings are created automagically by this function. 
5166 + */
5167 +unsigned int
5168 +ip_nat_setup_info(struct ip_conntrack *conntrack,
5169 +                 const struct ip_nat_multi_range *mr,
5170 +                 unsigned int hooknum)
5171 +{
5172 +       struct ip_conntrack_tuple new_tuple, inv_tuple, reply;
5173 +       struct ip_conntrack_tuple orig_tp;
5174 +       struct ip_nat_info *info = &conntrack->nat.info;
5175 +       int in_hashes = info->initialized;
5176 +
5177 +       MUST_BE_WRITE_LOCKED(&ip_nat_lock);
5178 +       IP_NF_ASSERT(hooknum == NF_IP_PRE_ROUTING
5179 +                    || hooknum == NF_IP_POST_ROUTING
5180 +                    || hooknum == NF_IP_LOCAL_OUT);
5181 +       IP_NF_ASSERT(info->num_manips < IP_NAT_MAX_MANIPS);
5182 +       IP_NF_ASSERT(!(info->initialized & (1 << HOOK2MANIP(hooknum))));
5183 +
5184 +       /* What we've got will look like inverse of reply. Normally
5185 +          this is what is in the conntrack, except for prior
5186 +          manipulations (future optimization: if num_manips == 0,
5187 +          orig_tp =
5188 +          conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple) */
5189 +       invert_tuplepr(&orig_tp,
5190 +                      &conntrack->tuplehash[IP_CT_DIR_REPLY].tuple);
5191 +
5192 +#if 0
5193 +       {
5194 +       unsigned int i;
5195 +
5196 +       DEBUGP("Hook %u (%s), ", hooknum,
5197 +              HOOK2MANIP(hooknum)==IP_NAT_MANIP_SRC ? "SRC" : "DST");
5198 +       DUMP_TUPLE(&orig_tp);
5199 +       DEBUGP("Range %p: ", mr);
5200 +       for (i = 0; i < mr->rangesize; i++) {
5201 +               DEBUGP("%u:%s%s%s %u.%u.%u.%u - %u.%u.%u.%u %u - %u\n",
5202 +                      i,
5203 +                      (mr->range[i].flags & IP_NAT_RANGE_MAP_IPS)
5204 +                      ? " MAP_IPS" : "",
5205 +                      (mr->range[i].flags
5206 +                       & IP_NAT_RANGE_PROTO_SPECIFIED)
5207 +                      ? " PROTO_SPECIFIED" : "",
5208 +                      (mr->range[i].flags & IP_NAT_RANGE_FULL)
5209 +                      ? " FULL" : "",
5210 +                      NIPQUAD(mr->range[i].min_ip),
5211 +                      NIPQUAD(mr->range[i].max_ip),
5212 +                      mr->range[i].min.all,
5213 +                      mr->range[i].max.all);
5214 +       }
5215 +       }
5216 +#endif
5217 +
5218 +       do {
5219 +               if (!get_unique_tuple(&new_tuple, &orig_tp, mr, conntrack,
5220 +                                     hooknum)) {
5221 +                       DEBUGP("ip_nat_setup_info: Can't get unique for %p.\n",
5222 +                              conntrack);
5223 +                       return NF_DROP;
5224 +               }
5225 +
5226 +#if 0
5227 +               DEBUGP("Hook %u (%s) %p\n", hooknum,
5228 +                      HOOK2MANIP(hooknum)==IP_NAT_MANIP_SRC ? "SRC" : "DST",
5229 +                      conntrack);
5230 +               DEBUGP("Original: ");
5231 +               DUMP_TUPLE(&orig_tp);
5232 +               DEBUGP("New: ");
5233 +               DUMP_TUPLE(&new_tuple);
5234 +#endif
5235 +
5236 +               /* We now have two tuples (SRCIP/SRCPT/DSTIP/DSTPT):
5237 +                  the original (A/B/C/D') and the mangled one (E/F/G/H').
5238 +
5239 +                  We're only allowed to work with the SRC per-proto
5240 +                  part, so we create inverses of both to start, then
5241 +                  derive the other fields we need.  */
5242 +
5243 +               /* Reply connection: simply invert the new tuple
5244 +                   (G/H/E/F') */
5245 +               invert_tuplepr(&reply, &new_tuple);
5246 +
5247 +               /* Alter conntrack table so it recognizes replies.
5248 +                   If fail this race (reply tuple now used), repeat. */
5249 +       } while (!ip_conntrack_alter_reply(conntrack, &reply));
5250 +
5251 +       /* FIXME: We can simply used existing conntrack reply tuple
5252 +           here --RR */
5253 +       /* Create inverse of original: C/D/A/B' */
5254 +       invert_tuplepr(&inv_tuple, &orig_tp);
5255 +
5256 +       /* Has source changed?. */
5257 +       if (!ip_ct_tuple_src_equal(&new_tuple, &orig_tp)) {
5258 +               /* In this direction, a source manip. */
5259 +               info->manips[info->num_manips++] =
5260 +                       ((struct ip_nat_info_manip)
5261 +                        { IP_CT_DIR_ORIGINAL, hooknum,
5262 +                          IP_NAT_MANIP_SRC, new_tuple.src });
5263 +
5264 +               IP_NF_ASSERT(info->num_manips < IP_NAT_MAX_MANIPS);
5265 +
5266 +               /* In the reverse direction, a destination manip. */
5267 +               info->manips[info->num_manips++] =
5268 +                       ((struct ip_nat_info_manip)
5269 +                        { IP_CT_DIR_REPLY, opposite_hook[hooknum],
5270 +                          IP_NAT_MANIP_DST, orig_tp.src });
5271 +               IP_NF_ASSERT(info->num_manips <= IP_NAT_MAX_MANIPS);
5272 +       }
5273 +
5274 +       /* Has destination changed? */
5275 +       if (!ip_ct_tuple_dst_equal(&new_tuple, &orig_tp)) {
5276 +               /* In this direction, a destination manip */
5277 +               info->manips[info->num_manips++] =
5278 +                       ((struct ip_nat_info_manip)
5279 +                        { IP_CT_DIR_ORIGINAL, hooknum,
5280 +                          IP_NAT_MANIP_DST, reply.src });
5281 +
5282 +               IP_NF_ASSERT(info->num_manips < IP_NAT_MAX_MANIPS);
5283 +
5284 +               /* In the reverse direction, a source manip. */
5285 +               info->manips[info->num_manips++] =
5286 +                       ((struct ip_nat_info_manip)
5287 +                        { IP_CT_DIR_REPLY, opposite_hook[hooknum],
5288 +                          IP_NAT_MANIP_SRC, inv_tuple.src });
5289 +               IP_NF_ASSERT(info->num_manips <= IP_NAT_MAX_MANIPS);
5290 +       }
5291 +
5292 +       /* If there's a helper, assign it; based on new tuple. */
5293 +       if (!conntrack->master)
5294 +               info->helper = LIST_FIND(&helpers, helper_cmp, struct ip_nat_helper *,
5295 +                                        &reply);
5296 +
5297 +       /* It's done. */
5298 +       info->initialized |= (1 << HOOK2MANIP(hooknum));
5299 +
5300 +       if (in_hashes) {
5301 +               IP_NF_ASSERT(info->bysource.conntrack);
5302 +               replace_in_hashes(conntrack, info);
5303 +       } else {
5304 +               place_in_hashes(conntrack, info);
5305 +       }
5306 +
5307 +       return NF_ACCEPT;
5308 +}
5309 +
5310 +void replace_in_hashes(struct ip_conntrack *conntrack,
5311 +                      struct ip_nat_info *info)
5312 +{
5313 +       /* Source has changed, so replace in hashes. */
5314 +       unsigned int srchash
5315 +               = hash_by_src(&conntrack->tuplehash[IP_CT_DIR_ORIGINAL]
5316 +                             .tuple.src,
5317 +                             conntrack->tuplehash[IP_CT_DIR_ORIGINAL]
5318 +                             .tuple.dst.protonum);
5319 +       /* We place packet as seen OUTGOUNG in byips_proto hash
5320 +           (ie. reverse dst and src of reply packet. */
5321 +       unsigned int ipsprotohash
5322 +               = hash_by_ipsproto(conntrack->tuplehash[IP_CT_DIR_REPLY]
5323 +                                  .tuple.dst.ip,
5324 +                                  conntrack->tuplehash[IP_CT_DIR_REPLY]
5325 +                                  .tuple.src.ip,
5326 +                                  conntrack->tuplehash[IP_CT_DIR_REPLY]
5327 +                                  .tuple.dst.protonum);
5328 +
5329 +       IP_NF_ASSERT(info->bysource.conntrack == conntrack);
5330 +       MUST_BE_WRITE_LOCKED(&ip_nat_lock);
5331 +
5332 +       list_del(&info->bysource.list);
5333 +       list_del(&info->byipsproto.list);
5334 +
5335 +       list_prepend(&bysource[srchash], &info->bysource);
5336 +       list_prepend(&byipsproto[ipsprotohash], &info->byipsproto);
5337 +}
5338 +
5339 +void place_in_hashes(struct ip_conntrack *conntrack,
5340 +                    struct ip_nat_info *info)
5341 +{
5342 +       unsigned int srchash
5343 +               = hash_by_src(&conntrack->tuplehash[IP_CT_DIR_ORIGINAL]
5344 +                             .tuple.src,
5345 +                             conntrack->tuplehash[IP_CT_DIR_ORIGINAL]
5346 +                             .tuple.dst.protonum);
5347 +       /* We place packet as seen OUTGOUNG in byips_proto hash
5348 +           (ie. reverse dst and src of reply packet. */
5349 +       unsigned int ipsprotohash
5350 +               = hash_by_ipsproto(conntrack->tuplehash[IP_CT_DIR_REPLY]
5351 +                                  .tuple.dst.ip,
5352 +                                  conntrack->tuplehash[IP_CT_DIR_REPLY]
5353 +                                  .tuple.src.ip,
5354 +                                  conntrack->tuplehash[IP_CT_DIR_REPLY]
5355 +                                  .tuple.dst.protonum);
5356 +
5357 +       IP_NF_ASSERT(!info->bysource.conntrack);
5358 +
5359 +       MUST_BE_WRITE_LOCKED(&ip_nat_lock);
5360 +       info->byipsproto.conntrack = conntrack;
5361 +       info->bysource.conntrack = conntrack;
5362 +
5363 +       list_prepend(&bysource[srchash], &info->bysource);
5364 +       list_prepend(&byipsproto[ipsprotohash], &info->byipsproto);
5365 +}
5366 +
5367 +/* Returns true if succeeded. */
5368 +static int
5369 +manip_pkt(u_int16_t proto,
5370 +         struct sk_buff **pskb,
5371 +         unsigned int iphdroff,
5372 +         const struct ip_conntrack_manip *manip,
5373 +         enum ip_nat_manip_type maniptype)
5374 +{
5375 +       struct iphdr *iph;
5376 +
5377 +       (*pskb)->nfcache |= NFC_ALTERED;
5378 +       if (!skb_ip_make_writable(pskb, iphdroff+sizeof(iph)))
5379 +               return 0;
5380 +
5381 +       iph = (void *)(*pskb)->data + iphdroff;
5382 +
5383 +       /* Manipulate protcol part. */
5384 +       if (!find_nat_proto(proto)->manip_pkt(pskb,
5385 +                                             iphdroff + iph->ihl*4,
5386 +                                             manip, maniptype))
5387 +               return 0;
5388 +
5389 +       iph = (void *)(*pskb)->data + iphdroff;
5390 +
5391 +       if (maniptype == IP_NAT_MANIP_SRC) {
5392 +               iph->check = ip_nat_cheat_check(~iph->saddr, manip->ip,
5393 +                                               iph->check);
5394 +               iph->saddr = manip->ip;
5395 +       } else {
5396 +               iph->check = ip_nat_cheat_check(~iph->daddr, manip->ip,
5397 +                                               iph->check);
5398 +               iph->daddr = manip->ip;
5399 +       }
5400 +       return 1;
5401 +}
5402 +
5403 +static inline int exp_for_packet(struct ip_conntrack_expect *exp,
5404 +                                struct sk_buff *skb)
5405 +{
5406 +       struct ip_conntrack_protocol *proto;
5407 +       int ret = 1;
5408 +
5409 +       MUST_BE_READ_LOCKED(&ip_conntrack_lock);
5410 +       proto = __ip_ct_find_proto(skb->nh.iph->protocol);
5411 +       if (proto->exp_matches_pkt)
5412 +               ret = proto->exp_matches_pkt(exp, skb);
5413 +
5414 +       return ret;
5415 +}
5416 +
5417 +/* Do packet manipulations according to binding. */
5418 +unsigned int
5419 +do_bindings(struct ip_conntrack *ct,
5420 +           enum ip_conntrack_info ctinfo,
5421 +           struct ip_nat_info *info,
5422 +           unsigned int hooknum,
5423 +           struct sk_buff **pskb)
5424 +{
5425 +       unsigned int i;
5426 +       struct ip_nat_helper *helper;
5427 +       enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
5428 +       int proto = (*pskb)->nh.iph->protocol;
5429 +
5430 +       /* Need nat lock to protect against modification, but neither
5431 +          conntrack (referenced) and helper (deleted with
5432 +          synchronize_bh()) can vanish. */
5433 +       READ_LOCK(&ip_nat_lock);
5434 +       for (i = 0; i < info->num_manips; i++) {
5435 +               if (info->manips[i].direction == dir
5436 +                   && info->manips[i].hooknum == hooknum) {
5437 +                       DEBUGP("Mangling %p: %s to %u.%u.%u.%u %u\n",
5438 +                              *pskb,
5439 +                              info->manips[i].maniptype == IP_NAT_MANIP_SRC
5440 +                              ? "SRC" : "DST",
5441 +                              NIPQUAD(info->manips[i].manip.ip),
5442 +                              htons(info->manips[i].manip.u.all));
5443 +                       if (!manip_pkt(proto, pskb, 0,
5444 +                                      &info->manips[i].manip,
5445 +                                      info->manips[i].maniptype)) {
5446 +                               READ_UNLOCK(&ip_nat_lock);
5447 +                               return NF_DROP;
5448 +                       }
5449 +               }
5450 +       }
5451 +       helper = info->helper;
5452 +       READ_UNLOCK(&ip_nat_lock);
5453 +
5454 +       if (helper) {
5455 +               struct ip_conntrack_expect *exp = NULL;
5456 +               struct list_head *cur_item;
5457 +               int ret = NF_ACCEPT;
5458 +               int helper_called = 0;
5459 +
5460 +               DEBUGP("do_bindings: helper existing for (%p)\n", ct);
5461 +
5462 +               /* Always defragged for helpers */
5463 +               IP_NF_ASSERT(!((*pskb)->nh.iph->frag_off
5464 +                              & htons(IP_MF|IP_OFFSET)));
5465 +
5466 +               /* Have to grab read lock before sibling_list traversal */
5467 +               READ_LOCK(&ip_conntrack_lock);
5468 +               list_for_each(cur_item, &ct->sibling_list) { 
5469 +                       exp = list_entry(cur_item, struct ip_conntrack_expect, 
5470 +                                        expected_list);
5471 +                                        
5472 +                       /* if this expectation is already established, skip */
5473 +                       if (exp->sibling)
5474 +                               continue;
5475 +
5476 +                       if (exp_for_packet(exp, *pskb)) {
5477 +                               /* FIXME: May be true multiple times in the
5478 +                                * case of UDP!! */
5479 +                               DEBUGP("calling nat helper (exp=%p) for packet\n", exp);
5480 +                               ret = helper->help(ct, exp, info, ctinfo, 
5481 +                                                  hooknum, pskb);
5482 +                               if (ret != NF_ACCEPT) {
5483 +                                       READ_UNLOCK(&ip_conntrack_lock);
5484 +                                       return ret;
5485 +                               }
5486 +                               helper_called = 1;
5487 +                       }
5488 +               }
5489 +               /* Helper might want to manip the packet even when there is no
5490 +                * matching expectation for this packet */
5491 +               if (!helper_called && helper->flags & IP_NAT_HELPER_F_ALWAYS) {
5492 +                       DEBUGP("calling nat helper for packet without expectation\n");
5493 +                       ret = helper->help(ct, NULL, info, ctinfo, 
5494 +                                          hooknum, pskb);
5495 +                       if (ret != NF_ACCEPT) {
5496 +                               READ_UNLOCK(&ip_conntrack_lock);
5497 +                               return ret;
5498 +                       }
5499 +               }
5500 +               READ_UNLOCK(&ip_conntrack_lock);
5501 +               
5502 +               /* Adjust sequence number only once per packet 
5503 +                * (helper is called at all hooks) */
5504 +               if (proto == IPPROTO_TCP
5505 +                   && (hooknum == NF_IP_POST_ROUTING
5506 +                       || hooknum == NF_IP_LOCAL_IN)) {
5507 +                       DEBUGP("ip_nat_core: adjusting sequence number\n");
5508 +                       /* future: put this in a l4-proto specific function,
5509 +                        * and call this function here. */
5510 +                       if (!ip_nat_seq_adjust(pskb, ct, ctinfo))
5511 +                               ret = NF_DROP;
5512 +               }
5513 +
5514 +               return ret;
5515 +
5516 +       } else 
5517 +               return NF_ACCEPT;
5518 +
5519 +       /* not reached */
5520 +}
5521 +
5522 +int
5523 +icmp_reply_translation(struct sk_buff **pskb,
5524 +                      struct ip_conntrack *conntrack,
5525 +                      unsigned int hooknum,
5526 +                      int dir)
5527 +{
5528 +       struct {
5529 +               struct icmphdr icmp;
5530 +               struct iphdr ip;
5531 +       } *inside;
5532 +       unsigned int i;
5533 +       struct ip_nat_info *info = &conntrack->nat.info;
5534 +       int hdrlen;
5535 +
5536 +       if (!skb_ip_make_writable(pskb,(*pskb)->nh.iph->ihl*4+sizeof(*inside)))
5537 +               return 0;
5538 +       inside = (void *)(*pskb)->data + (*pskb)->nh.iph->ihl*4;
5539 +
5540 +       /* We're actually going to mangle it beyond trivial checksum
5541 +          adjustment, so make sure the current checksum is correct. */
5542 +       if ((*pskb)->ip_summed != CHECKSUM_UNNECESSARY) {
5543 +               hdrlen = (*pskb)->nh.iph->ihl * 4;
5544 +               if ((u16)csum_fold(skb_checksum(*pskb, hdrlen,
5545 +                                               (*pskb)->len - hdrlen, 0)))
5546 +                       return 0;
5547 +       }
5548 +
5549 +       /* Must be RELATED */
5550 +       IP_NF_ASSERT((*pskb)->nfct
5551 +                    - (struct ip_conntrack *)(*pskb)->nfct->master
5552 +                    == IP_CT_RELATED
5553 +                    || (*pskb)->nfct
5554 +                    - (struct ip_conntrack *)(*pskb)->nfct->master
5555 +                    == IP_CT_RELATED+IP_CT_IS_REPLY);
5556 +
5557 +       /* Redirects on non-null nats must be dropped, else they'll
5558 +           start talking to each other without our translation, and be
5559 +           confused... --RR */
5560 +       if (inside->icmp.type == ICMP_REDIRECT) {
5561 +               /* Don't care about races here. */
5562 +               if (info->initialized
5563 +                   != ((1 << IP_NAT_MANIP_SRC) | (1 << IP_NAT_MANIP_DST))
5564 +                   || info->num_manips != 0)
5565 +                       return 0;
5566 +       }
5567 +
5568 +       DEBUGP("icmp_reply_translation: translating error %p hook %u dir %s\n",
5569 +              *pskb, hooknum, dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY");
5570 +       /* Note: May not be from a NAT'd host, but probably safest to
5571 +          do translation always as if it came from the host itself
5572 +          (even though a "host unreachable" coming from the host
5573 +          itself is a bit weird).
5574 +
5575 +          More explanation: some people use NAT for anonymizing.
5576 +          Also, CERT recommends dropping all packets from private IP
5577 +          addresses (although ICMP errors from internal links with
5578 +          such addresses are not too uncommon, as Alan Cox points
5579 +          out) */
5580 +
5581 +       READ_LOCK(&ip_nat_lock);
5582 +       for (i = 0; i < info->num_manips; i++) {
5583 +               DEBUGP("icmp_reply: manip %u dir %s hook %u\n",
5584 +                      i, info->manips[i].direction == IP_CT_DIR_ORIGINAL ?
5585 +                      "ORIG" : "REPLY", info->manips[i].hooknum);
5586 +
5587 +               if (info->manips[i].direction != dir)
5588 +                       continue;
5589 +
5590 +               /* Mapping the inner packet is just like a normal
5591 +                  packet, except it was never src/dst reversed, so
5592 +                  where we would normally apply a dst manip, we apply
5593 +                  a src, and vice versa. */
5594 +               if (info->manips[i].hooknum == hooknum) {
5595 +                       DEBUGP("icmp_reply: inner %s -> %u.%u.%u.%u %u\n",
5596 +                              info->manips[i].maniptype == IP_NAT_MANIP_SRC
5597 +                              ? "DST" : "SRC",
5598 +                              NIPQUAD(info->manips[i].manip.ip),
5599 +                              ntohs(info->manips[i].manip.u.udp.port));
5600 +                       if (!manip_pkt(inside->ip.protocol, pskb,
5601 +                                      (*pskb)->nh.iph->ihl*4
5602 +                                      + sizeof(inside->icmp),
5603 +                                      &info->manips[i].manip,
5604 +                                      !info->manips[i].maniptype))
5605 +                               goto unlock_fail;
5606 +
5607 +                       /* Outer packet needs to have IP header NATed like
5608 +                          it's a reply. */
5609 +
5610 +                       /* Use mapping to map outer packet: 0 give no
5611 +                           per-proto mapping */
5612 +                       DEBUGP("icmp_reply: outer %s -> %u.%u.%u.%u\n",
5613 +                              info->manips[i].maniptype == IP_NAT_MANIP_SRC
5614 +                              ? "SRC" : "DST",
5615 +                              NIPQUAD(info->manips[i].manip.ip));
5616 +                       if (!manip_pkt(0, pskb, 0,
5617 +                                      &info->manips[i].manip,
5618 +                                      info->manips[i].maniptype))
5619 +                               goto unlock_fail;
5620 +               }
5621 +       }
5622 +       READ_UNLOCK(&ip_nat_lock);
5623 +
5624 +       hdrlen = (*pskb)->nh.iph->ihl * 4;
5625 +
5626 +       inside = (void *)(*pskb)->data + (*pskb)->nh.iph->ihl*4;
5627 +
5628 +       inside->icmp.checksum = 0;
5629 +       inside->icmp.checksum = csum_fold(skb_checksum(*pskb, hdrlen,
5630 +                                                      (*pskb)->len - hdrlen,
5631 +                                                      0));
5632 +       return 1;
5633 +
5634 + unlock_fail:
5635 +       READ_UNLOCK(&ip_nat_lock);
5636 +       return 0;
5637 +}
5638 +
5639 +int __init ip_nat_init(void)
5640 +{
5641 +       size_t i;
5642 +
5643 +       /* Leave them the same for the moment. */
5644 +       ip_nat_htable_size = ip_conntrack_htable_size;
5645 +
5646 +       /* One vmalloc for both hash tables */
5647 +       bysource = vmalloc(sizeof(struct list_head) * ip_nat_htable_size*2);
5648 +       if (!bysource) {
5649 +               return -ENOMEM;
5650 +       }
5651 +       byipsproto = bysource + ip_nat_htable_size;
5652 +
5653 +       /* Sew in builtin protocols. */
5654 +       WRITE_LOCK(&ip_nat_lock);
5655 +       list_append(&protos, &ip_nat_protocol_tcp);
5656 +       list_append(&protos, &ip_nat_protocol_udp);
5657 +       list_append(&protos, &ip_nat_protocol_icmp);
5658 +       WRITE_UNLOCK(&ip_nat_lock);
5659 +
5660 +       for (i = 0; i < ip_nat_htable_size; i++) {
5661 +               INIT_LIST_HEAD(&bysource[i]);
5662 +               INIT_LIST_HEAD(&byipsproto[i]);
5663 +       }
5664 +
5665 +       /* FIXME: Man, this is a hack.  <SIGH> */
5666 +       IP_NF_ASSERT(ip_conntrack_destroyed == NULL);
5667 +       ip_conntrack_destroyed = &ip_nat_cleanup_conntrack;
5668 +
5669 +       return 0;
5670 +}
5671 +
5672 +/* Clear NAT section of all conntracks, in case we're loaded again. */
5673 +static int clean_nat(const struct ip_conntrack *i, void *data)
5674 +{
5675 +       memset((void *)&i->nat, 0, sizeof(i->nat));
5676 +       return 0;
5677 +}
5678 +
5679 +/* Not __exit: called from ip_nat_standalone.c:init_or_cleanup() --RR */
5680 +void ip_nat_cleanup(void)
5681 +{
5682 +       ip_ct_selective_cleanup(&clean_nat, NULL);
5683 +       ip_conntrack_destroyed = NULL;
5684 +       vfree(bysource);
5685 +}
5686 diff -Nur linux-2.6.4-rc2.org/net/ipv4/netfilter/ip_nat_helper.c linux-2.6.4-rc2/net/ipv4/netfilter/ip_nat_helper.c
5687 --- linux-2.6.4-rc2.org/net/ipv4/netfilter/ip_nat_helper.c      2004-03-04 06:16:38.000000000 +0000
5688 +++ linux-2.6.4-rc2/net/ipv4/netfilter/ip_nat_helper.c  2004-03-05 09:55:06.000000000 +0000
5689 @@ -150,9 +150,19 @@
5690         return 1;
5691  }
5692  
5693 -/* Generic function for mangling variable-length address changes inside
5694 - * NATed TCP connections (like the PORT XXX,XXX,XXX,XXX,XXX,XXX
5695 - * command in FTP).
5696 +/**
5697 + * ip_nat_mangle_tcp_packet - Mangle and potentially resize payload packet
5698 + * @skb: pointer to skb of packet on which we operate
5699 + * @ct: conntrack of the connection to which this packet belongs
5700 + * @ctinfo: conntrack_info of the connection to which this packet belongs
5701 + * @match_offset: offset in bytes where to-be-manipulated part starts
5702 + * @match_len: lenght of the to-be-manipulated part
5703 + * @rep_buffer: pointer to buffer containing replacement
5704 + * @rep_len: length of replacement
5705 + *
5706 + * Generic function for mangling fixed and variable-length changes inside
5707 + * NATed TCP connections (like the PORT XXX,XXX,XXX,XXX,XXX,XXX command 
5708 + * in FTP).
5709   *
5710   * Takes care about all the nasty sequence number changes, checksumming,
5711   * skb enlargement, ...
5712 @@ -198,16 +208,27 @@
5713         return 1;
5714  }
5715                         
5716 -/* Generic function for mangling variable-length address changes inside
5717 - * NATed UDP connections (like the CONNECT DATA XXXXX MESG XXXXX INDEX XXXXX
5718 - * command in the Amanda protocol)
5719 +/**
5720 + * ip_nat_mangle_udp_packet - Mangle and potentially resize payload packet
5721 + * @skb: pointer to skb of packet on which we operate
5722 + * @ct: conntrack of the connection to which this packet belongs
5723 + * @ctinfo: conntrack_info of the connection to which this packet belongs
5724 + * @match_offset: offset in bytes where to-be-manipulated part starts
5725 + * @match_len: lenght of the to-be-manipulated part
5726 + * @rep_buffer: pointer to buffer containing replacement
5727 + * @rep_len: length of replacement
5728 + *
5729 + * Generic function for mangling fixed and variable-length changes inside
5730 + * NATed TCP connections (like the CONNECT DATA XXXXX MESG XXXXX INDEX XXXXX
5731 + * commad in the Amanda protocol)
5732   *
5733   * Takes care about all the nasty sequence number changes, checksumming,
5734   * skb enlargement, ...
5735   *
5736 - * XXX - This function could be merged with ip_nat_mangle_tcp_packet which
5737 - *       should be fairly easy to do.
5738 - */
5739 + * FIXME: should be unified with ip_nat_mangle_tcp_packet!!
5740 + *
5741 + * */
5742 +
5743  int 
5744  ip_nat_mangle_udp_packet(struct sk_buff **pskb,
5745                          struct ip_conntrack *ct,
5746 @@ -405,6 +426,13 @@
5747         return ip_ct_tuple_mask_cmp(tuple, &helper->tuple, &helper->mask);
5748  }
5749  
5750 +/**
5751 + * ip_nat_helper_register - Register NAT application helper
5752 + * @me: structure describing the helper
5753 + *
5754 + * This function is called by NAT application helpers to register
5755 + * themselves with the NAT core.
5756 + */
5757  int ip_nat_helper_register(struct ip_nat_helper *me)
5758  {
5759         int ret = 0;
5760 @@ -431,6 +459,13 @@
5761         return ret;
5762  }
5763  
5764 +/**
5765 + * ip_nat_helper_unregister - Unregister NAT application helper
5766 + * @me: structure describing the helper
5767 + *
5768 + * This function is called by NAT application helpers to unregister
5769 + * themselves from the NAT core.
5770 + */
5771  void ip_nat_helper_unregister(struct ip_nat_helper *me)
5772  {
5773         WRITE_LOCK(&ip_nat_lock);
5774 diff -Nur linux-2.6.4-rc2.org/net/ipv4/netfilter/ip_nat_standalone.c linux-2.6.4-rc2/net/ipv4/netfilter/ip_nat_standalone.c
5775 --- linux-2.6.4-rc2.org/net/ipv4/netfilter/ip_nat_standalone.c  2004-03-04 06:16:55.000000000 +0000
5776 +++ linux-2.6.4-rc2/net/ipv4/netfilter/ip_nat_standalone.c      2004-03-05 09:55:06.000000000 +0000
5777 @@ -266,7 +266,13 @@
5778  };
5779  #endif
5780  
5781 -/* Protocol registration. */
5782 +/**
5783 + * ip_nat_protocol_register - Register a layer 4 protocol helper
5784 + * @proto: structure describing this helper
5785 + * 
5786 + * This function is called by NAT layer 4 protocol helpers to register
5787 + * themselvers with the NAT core.
5788 + */
5789  int ip_nat_protocol_register(struct ip_nat_protocol *proto)
5790  {
5791         int ret = 0;
5792 @@ -287,9 +293,16 @@
5793         return ret;
5794  }
5795  
5796 -/* Noone stores the protocol anywhere; simply delete it. */
5797 +/**
5798 + * ip_nat_protocol_unregister - Unregister a layer 4 protocol helper
5799 + * @proto: structure describing the helper
5800 + *
5801 + * This function is called by NAT layer 4 protocol helpers to
5802 + * unregister themselves from the NAT core.
5803 + */
5804  void ip_nat_protocol_unregister(struct ip_nat_protocol *proto)
5805  {
5806 +       /* Noone stores the protocol anywhere; simply delete it. */
5807         WRITE_LOCK(&ip_nat_lock);
5808         LIST_DELETE(&protos, proto);
5809         WRITE_UNLOCK(&ip_nat_lock);
5810 diff -Nur linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_IPV4OPTSSTRIP.c linux-2.6.4-rc2/net/ipv4/netfilter/ipt_IPV4OPTSSTRIP.c
5811 --- linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_IPV4OPTSSTRIP.c  1970-01-01 00:00:00.000000000 +0000
5812 +++ linux-2.6.4-rc2/net/ipv4/netfilter/ipt_IPV4OPTSSTRIP.c      2004-03-05 09:55:11.000000000 +0000
5813 @@ -0,0 +1,89 @@
5814 +/**
5815 + * Strip all IP options in the IP packet header.
5816 + *
5817 + * (C) 2001 by Fabrice MARIE <fabrice@netfilter.org>
5818 + * This software is distributed under GNU GPL v2, 1991
5819 + */
5820 +
5821 +#include <linux/module.h>
5822 +#include <linux/skbuff.h>
5823 +#include <linux/ip.h>
5824 +#include <net/checksum.h>
5825 +
5826 +#include <linux/netfilter_ipv4/ip_tables.h>
5827 +
5828 +MODULE_AUTHOR("Fabrice MARIE <fabrice@netfilter.org>");
5829 +MODULE_DESCRIPTION("Strip all options in IPv4 packets");
5830 +MODULE_LICENSE("GPL");
5831 +
5832 +static unsigned int
5833 +target(struct sk_buff **pskb,
5834 +       const struct net_device *in,
5835 +       const struct net_device *out,
5836 +       unsigned int hooknum,
5837 +       const void *targinfo,
5838 +       void *userinfo)
5839 +{
5840 +       struct iphdr *iph;
5841 +       struct sk_buff *skb;
5842 +       struct ip_options *opt;
5843 +       unsigned char *optiph;
5844 +       int l;
5845 +       
5846 +       if (!skb_ip_make_writable(pskb, (*pskb)->len))
5847 +               return NF_DROP;
5848
5849 +       skb = (*pskb);
5850 +       iph = (*pskb)->nh.iph;
5851 +       optiph = skb->nh.raw;
5852 +       l = ((struct ip_options *)(&(IPCB(skb)->opt)))->optlen;
5853 +
5854 +       /* if no options in packet then nothing to clear. */
5855 +       if (iph->ihl * 4 == sizeof(struct iphdr))
5856 +               return IPT_CONTINUE;
5857 +
5858 +       /* else clear all options */
5859 +       memset(&(IPCB(skb)->opt), 0, sizeof(struct ip_options));
5860 +       memset(optiph+sizeof(struct iphdr), IPOPT_NOOP, l);
5861 +       opt = &(IPCB(skb)->opt);
5862 +       opt->is_data = 0;
5863 +       opt->optlen = l;
5864 +
5865 +       skb->nfcache |= NFC_ALTERED;
5866 +
5867 +        return IPT_CONTINUE;
5868 +}
5869 +
5870 +static int
5871 +checkentry(const char *tablename,
5872 +          const struct ipt_entry *e,
5873 +           void *targinfo,
5874 +           unsigned int targinfosize,
5875 +           unsigned int hook_mask)
5876 +{
5877 +       if (strcmp(tablename, "mangle")) {
5878 +               printk(KERN_WARNING "IPV4OPTSSTRIP: can only be called from \"mangle\" table, not \"%s\"\n", tablename);
5879 +               return 0;
5880 +       }
5881 +       /* nothing else to check because no parameters */
5882 +       return 1;
5883 +}
5884 +
5885 +static struct ipt_target ipt_ipv4optsstrip_reg = { 
5886 +       .name = "IPV4OPTSSTRIP",
5887 +       .target = target,
5888 +       .checkentry = checkentry,
5889 +       .me = THIS_MODULE };
5890 +
5891 +static int __init init(void)
5892 +{
5893 +       return ipt_register_target(&ipt_ipv4optsstrip_reg);
5894 +}
5895 +
5896 +static void __exit fini(void)
5897 +{
5898 +       ipt_unregister_target(&ipt_ipv4optsstrip_reg);
5899 +}
5900 +
5901 +module_init(init);
5902 +module_exit(fini);
5903 diff -Nur linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_LOG.c linux-2.6.4-rc2/net/ipv4/netfilter/ipt_LOG.c
5904 --- linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_LOG.c    2004-03-04 06:17:03.000000000 +0000
5905 +++ linux-2.6.4-rc2/net/ipv4/netfilter/ipt_LOG.c        2004-03-05 09:55:08.000000000 +0000
5906 @@ -19,6 +19,7 @@
5907  #include <net/tcp.h>
5908  #include <net/route.h>
5909  
5910 +#include <linux/netfilter.h>
5911  #include <linux/netfilter_ipv4/ip_tables.h>
5912  #include <linux/netfilter_ipv4/ipt_LOG.h>
5913  
5914 @@ -26,6 +27,10 @@
5915  MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
5916  MODULE_DESCRIPTION("iptables syslog logging module");
5917  
5918 +static unsigned int nflog = 1;
5919 +MODULE_PARM(nflog, "i");
5920 +MODULE_PARM_DESC(nflog, "register as internal netfilter logging module");
5921
5922  #if 0
5923  #define DEBUGP printk
5924  #else
5925 @@ -324,28 +329,25 @@
5926         /* maxlen = 230+   91  + 230 + 252 = 803 */
5927  }
5928  
5929 -static unsigned int
5930 -ipt_log_target(struct sk_buff **pskb,
5931 +static void
5932 +ipt_log_packet(unsigned int hooknum,
5933 +              const struct sk_buff *skb,
5934                const struct net_device *in,
5935                const struct net_device *out,
5936 -              unsigned int hooknum,
5937 -              const void *targinfo,
5938 -              void *userinfo)
5939 +              const struct ipt_log_info *loginfo,
5940 +              const char *level_string,
5941 +              const char *prefix)
5942  {
5943 -       const struct ipt_log_info *loginfo = targinfo;
5944 -       char level_string[4] = "< >";
5945 -
5946 -       level_string[1] = '0' + (loginfo->level % 8);
5947         spin_lock_bh(&log_lock);
5948         printk(level_string);
5949         printk("%sIN=%s OUT=%s ",
5950 -              loginfo->prefix,
5951 +              prefix == NULL ? loginfo->prefix : prefix,
5952                in ? in->name : "",
5953                out ? out->name : "");
5954  #ifdef CONFIG_BRIDGE_NETFILTER
5955 -       if ((*pskb)->nf_bridge) {
5956 -               struct net_device *physindev = (*pskb)->nf_bridge->physindev;
5957 -               struct net_device *physoutdev = (*pskb)->nf_bridge->physoutdev;
5958 +       if (skb->nf_bridge) {
5959 +               struct net_device *physindev = skb->nf_bridge->physindev;
5960 +               struct net_device *physoutdev = skb->nf_bridge->physoutdev;
5961  
5962                 if (physindev && in != physindev)
5963                         printk("PHYSIN=%s ", physindev->name);
5964 @@ -357,25 +359,56 @@
5965         if (in && !out) {
5966                 /* MAC logging for input chain only. */
5967                 printk("MAC=");
5968 -               if ((*pskb)->dev && (*pskb)->dev->hard_header_len
5969 -                   && (*pskb)->mac.raw != (void*)(*pskb)->nh.iph) {
5970 +               if (skb->dev && skb->dev->hard_header_len
5971 +                   && skb->mac.raw != (void*)skb->nh.iph) {
5972                         int i;
5973 -                       unsigned char *p = (*pskb)->mac.raw;
5974 -                       for (i = 0; i < (*pskb)->dev->hard_header_len; i++,p++)
5975 +                       unsigned char *p = skb->mac.raw;
5976 +                       for (i = 0; i < skb->dev->hard_header_len; i++,p++)
5977                                 printk("%02x%c", *p,
5978 -                                      i==(*pskb)->dev->hard_header_len - 1
5979 +                                      i==skb->dev->hard_header_len - 1
5980                                        ? ' ':':');
5981                 } else
5982                         printk(" ");
5983         }
5984  
5985 -       dump_packet(loginfo, *pskb, 0);
5986 +       dump_packet(loginfo, skb, 0);
5987         printk("\n");
5988         spin_unlock_bh(&log_lock);
5989 +}
5990 +
5991 +static unsigned int
5992 +ipt_log_target(struct sk_buff **pskb,
5993 +              const struct net_device *in,
5994 +              const struct net_device *out,
5995 +              unsigned int hooknum,
5996 +              const void *targinfo,
5997 +              void *userinfo)
5998 +{
5999 +       const struct ipt_log_info *loginfo = targinfo;
6000 +       char level_string[4] = "< >";
6001 +
6002 +       level_string[1] = '0' + (loginfo->level % 8);
6003 +       ipt_log_packet(hooknum, *pskb, in, out, loginfo, level_string, NULL);
6004  
6005         return IPT_CONTINUE;
6006  }
6007  
6008 +static void
6009 +ipt_logfn(unsigned int hooknum,
6010 +         const struct sk_buff *skb,
6011 +         const struct net_device *in,
6012 +         const struct net_device *out,
6013 +         const char *prefix)
6014 +{
6015 +       struct ipt_log_info loginfo = { 
6016 +               .level = 0, 
6017 +               .logflags = IPT_LOG_MASK, 
6018 +               .prefix = "" 
6019 +       };
6020 +
6021 +       ipt_log_packet(hooknum, skb, in, out, &loginfo, KERN_WARNING, prefix);
6022 +}
6023 +
6024  static int ipt_log_checkentry(const char *tablename,
6025                               const struct ipt_entry *e,
6026                               void *targinfo,
6027 @@ -413,11 +446,18 @@
6028  
6029  static int __init init(void)
6030  {
6031 -       return ipt_register_target(&ipt_log_reg);
6032 +       if (ipt_register_target(&ipt_log_reg))
6033 +               return -EINVAL;
6034 +       if (nflog)
6035 +               nf_log_register(PF_INET, &ipt_logfn);
6036 +       
6037 +       return 0;
6038  }
6039  
6040  static void __exit fini(void)
6041  {
6042 +       if (nflog)
6043 +               nf_log_unregister(PF_INET, &ipt_logfn);
6044         ipt_unregister_target(&ipt_log_reg);
6045  }
6046  
6047 diff -Nur linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_NOTRACK.c linux-2.6.4-rc2/net/ipv4/netfilter/ipt_NOTRACK.c
6048 --- linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_NOTRACK.c        1970-01-01 00:00:00.000000000 +0000
6049 +++ linux-2.6.4-rc2/net/ipv4/netfilter/ipt_NOTRACK.c    2004-03-05 09:55:23.000000000 +0000
6050 @@ -0,0 +1,75 @@
6051 +/* This is a module which is used for setting up fake conntracks
6052 + * on packets so that they are not seen by the conntrack/NAT code.
6053 + */
6054 +#include <linux/module.h>
6055 +#include <linux/skbuff.h>
6056 +
6057 +#include <linux/netfilter_ipv4/ip_tables.h>
6058 +#include <linux/netfilter_ipv4/ip_conntrack.h>
6059 +
6060 +static unsigned int
6061 +target(struct sk_buff **pskb,
6062 +       const struct net_device *in,
6063 +       const struct net_device *out,
6064 +       unsigned int hooknum,
6065 +       const void *targinfo,
6066 +       void *userinfo)
6067 +{
6068 +       /* Previously seen (loopback)? Ignore. */
6069 +       if ((*pskb)->nfct != NULL)
6070 +               return IPT_CONTINUE;
6071 +
6072 +       /* Attach fake conntrack entry. 
6073 +          If there is a real ct entry correspondig to this packet, 
6074 +          it'll hang aroun till timing out. We don't deal with it
6075 +          for performance reasons. JK */
6076 +       (*pskb)->nfct = &ip_conntrack_untracked.infos[IP_CT_NEW];
6077 +       nf_conntrack_get((*pskb)->nfct);
6078 +
6079 +       return IPT_CONTINUE;
6080 +}
6081 +
6082 +static int
6083 +checkentry(const char *tablename,
6084 +          const struct ipt_entry *e,
6085 +           void *targinfo,
6086 +           unsigned int targinfosize,
6087 +           unsigned int hook_mask)
6088 +{
6089 +       if (targinfosize != 0) {
6090 +               printk(KERN_WARNING "NOTRACK: targinfosize %u != 0\n",
6091 +                      targinfosize);
6092 +               return 0;
6093 +       }
6094 +
6095 +       if (strcmp(tablename, "raw") != 0) {
6096 +               printk(KERN_WARNING "NOTRACK: can only be called from \"raw\" table, not \"%s\"\n", tablename);
6097 +               return 0;
6098 +       }
6099 +
6100 +       return 1;
6101 +}
6102 +
6103 +static struct ipt_target ipt_notrack_reg = { 
6104 +       .name = "NOTRACK", 
6105 +       .target = target, 
6106 +       .checkentry = checkentry,
6107 +       .me = THIS_MODULE 
6108 +};
6109 +
6110 +static int __init init(void)
6111 +{
6112 +       if (ipt_register_target(&ipt_notrack_reg))
6113 +               return -EINVAL;
6114 +
6115 +       return 0;
6116 +}
6117 +
6118 +static void __exit fini(void)
6119 +{
6120 +       ipt_unregister_target(&ipt_notrack_reg);
6121 +}
6122 +
6123 +module_init(init);
6124 +module_exit(fini);
6125 +MODULE_LICENSE("GPL");
6126 diff -Nur linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_TTL.c linux-2.6.4-rc2/net/ipv4/netfilter/ipt_TTL.c
6127 --- linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_TTL.c    1970-01-01 00:00:00.000000000 +0000
6128 +++ linux-2.6.4-rc2/net/ipv4/netfilter/ipt_TTL.c        2004-03-05 09:55:14.000000000 +0000
6129 @@ -0,0 +1,120 @@
6130 +/* TTL modification target for IP tables
6131 + * (C) 2000 by Harald Welte <laforge@gnumonks.org>
6132 + *
6133 + * Version: $Revision$
6134 + *
6135 + * This software is distributed under the terms of GNU GPL
6136 + */
6137 +
6138 +#include <linux/module.h>
6139 +#include <linux/skbuff.h>
6140 +#include <linux/ip.h>
6141 +#include <net/checksum.h>
6142 +
6143 +#include <linux/netfilter_ipv4/ip_tables.h>
6144 +#include <linux/netfilter_ipv4/ipt_TTL.h>
6145 +
6146 +MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
6147 +MODULE_DESCRIPTION("IP tables TTL modification module");
6148 +MODULE_LICENSE("GPL");
6149 +
6150 +static unsigned int 
6151 +ipt_ttl_target(struct sk_buff **pskb, const struct net_device *in, 
6152 +               const struct net_device *out, unsigned int hooknum, 
6153 +               const void *targinfo, void *userinfo)
6154 +{
6155 +       struct iphdr *iph;
6156 +       const struct ipt_TTL_info *info = targinfo;
6157 +       u_int16_t diffs[2];
6158 +       int new_ttl;
6159 +
6160 +       if (!skb_ip_make_writable(pskb, (*pskb)->len))
6161 +               return NF_DROP;
6162 +
6163 +       iph = (*pskb)->nh.iph;
6164 +                        
6165 +       switch (info->mode) {
6166 +               case IPT_TTL_SET:
6167 +                       new_ttl = info->ttl;
6168 +                       break;
6169 +               case IPT_TTL_INC:
6170 +                       new_ttl = iph->ttl + info->ttl;
6171 +                       if (new_ttl > 255)
6172 +                               new_ttl = 255;
6173 +                       break;
6174 +               case IPT_TTL_DEC:
6175 +                       new_ttl = iph->ttl + info->ttl;
6176 +                       if (new_ttl < 0)
6177 +                               new_ttl = 0;
6178 +                       break;
6179 +               default:
6180 +                       new_ttl = iph->ttl;
6181 +                       break;
6182 +       }
6183 +
6184 +       if (new_ttl != iph->ttl) {
6185 +               diffs[0] = htons(((unsigned)iph->ttl) << 8) ^ 0xFFFF;
6186 +               iph->ttl = new_ttl;
6187 +               diffs[1] = htons(((unsigned)iph->ttl) << 8);
6188 +               iph->check = csum_fold(csum_partial((char *)diffs,
6189 +                                                   sizeof(diffs),
6190 +                                                   iph->check^0xFFFF));
6191 +                                                                                               (*pskb)->nfcache |= NFC_ALTERED;
6192 +       }
6193 +
6194 +       return IPT_CONTINUE;
6195 +}
6196 +
6197 +static int ipt_ttl_checkentry(const char *tablename,
6198 +               const struct ipt_entry *e,
6199 +               void *targinfo,
6200 +               unsigned int targinfosize,
6201 +               unsigned int hook_mask)
6202 +{
6203 +       struct ipt_TTL_info *info = targinfo;
6204 +
6205 +       if (targinfosize != IPT_ALIGN(sizeof(struct ipt_TTL_info))) {
6206 +               printk(KERN_WARNING "TTL: targinfosize %u != %Zu\n",
6207 +                               targinfosize,
6208 +                               IPT_ALIGN(sizeof(struct ipt_TTL_info)));
6209 +               return 0;       
6210 +       }       
6211 +
6212 +       if (strcmp(tablename, "mangle")) {
6213 +               printk(KERN_WARNING "TTL: can only be called from \"mangle\" table, not \"%s\"\n", tablename);
6214 +               return 0;
6215 +       }
6216 +
6217 +       if (info->mode > IPT_TTL_MAXMODE) {
6218 +               printk(KERN_WARNING "TTL: invalid or unknown Mode %u\n", 
6219 +                       info->mode);
6220 +               return 0;
6221 +       }
6222 +
6223 +       if ((info->mode != IPT_TTL_SET) && (info->ttl == 0)) {
6224 +               printk(KERN_WARNING "TTL: increment/decrement doesn't make sense with value 0\n");
6225 +               return 0;
6226 +       }
6227 +       
6228 +       return 1;
6229 +}
6230 +
6231 +static struct ipt_target ipt_TTL = { 
6232 +       .name = "TTL",
6233 +       .target = ipt_ttl_target, 
6234 +       .checkentry = ipt_ttl_checkentry, 
6235 +       .me = THIS_MODULE 
6236 +};
6237 +
6238 +static int __init init(void)
6239 +{
6240 +       return ipt_register_target(&ipt_TTL);
6241 +}
6242 +
6243 +static void __exit fini(void)
6244 +{
6245 +       ipt_unregister_target(&ipt_TTL);
6246 +}
6247 +
6248 +module_init(init);
6249 +module_exit(fini);
6250 diff -Nur linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_ULOG.c linux-2.6.4-rc2/net/ipv4/netfilter/ipt_ULOG.c
6251 --- linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_ULOG.c   2004-03-04 06:16:42.000000000 +0000
6252 +++ linux-2.6.4-rc2/net/ipv4/netfilter/ipt_ULOG.c       2004-03-05 09:55:08.000000000 +0000
6253 @@ -50,6 +50,7 @@
6254  #include <linux/netlink.h>
6255  #include <linux/netdevice.h>
6256  #include <linux/mm.h>
6257 +#include <linux/netfilter.h>
6258  #include <linux/netfilter_ipv4/ip_tables.h>
6259  #include <linux/netfilter_ipv4/ipt_ULOG.h>
6260  #include <linux/netfilter_ipv4/lockhelp.h>
6261 @@ -80,6 +81,10 @@
6262  MODULE_PARM(flushtimeout, "i");
6263  MODULE_PARM_DESC(flushtimeout, "buffer flush timeout");
6264  
6265 +static unsigned int nflog = 1;
6266 +MODULE_PARM(nflog, "i");
6267 +MODULE_PARM_DESC(nflog, "register as internal netfilter logging module");
6268 +
6269  /* global data structures */
6270  
6271  typedef struct {
6272 @@ -157,17 +162,17 @@
6273         return skb;
6274  }
6275  
6276 -static unsigned int ipt_ulog_target(struct sk_buff **pskb,
6277 -                                   const struct net_device *in,
6278 -                                   const struct net_device *out,
6279 -                                   unsigned int hooknum,
6280 -                                   const void *targinfo, void *userinfo)
6281 +static void ipt_ulog_packet(unsigned int hooknum,
6282 +                           const struct sk_buff *skb,
6283 +                           const struct net_device *in,
6284 +                           const struct net_device *out,
6285 +                           const struct ipt_ulog_info *loginfo,
6286 +                           const char *prefix)
6287  {
6288         ulog_buff_t *ub;
6289         ulog_packet_msg_t *pm;
6290         size_t size, copy_len;
6291         struct nlmsghdr *nlh;
6292 -       struct ipt_ulog_info *loginfo = (struct ipt_ulog_info *) targinfo;
6293  
6294         /* ffs == find first bit set, necessary because userspace
6295          * is already shifting groupnumber, but we need unshifted.
6296 @@ -176,8 +181,8 @@
6297  
6298         /* calculate the size of the skb needed */
6299         if ((loginfo->copy_range == 0) ||
6300 -           (loginfo->copy_range > (*pskb)->len)) {
6301 -               copy_len = (*pskb)->len;
6302 +           (loginfo->copy_range > skb->len)) {
6303 +               copy_len = skb->len;
6304         } else {
6305                 copy_len = loginfo->copy_range;
6306         }
6307 @@ -214,19 +219,21 @@
6308  
6309         /* copy hook, prefix, timestamp, payload, etc. */
6310         pm->data_len = copy_len;
6311 -       pm->timestamp_sec = (*pskb)->stamp.tv_sec;
6312 -       pm->timestamp_usec = (*pskb)->stamp.tv_usec;
6313 -       pm->mark = (*pskb)->nfmark;
6314 +       pm->timestamp_sec = skb->stamp.tv_sec;
6315 +       pm->timestamp_usec = skb->stamp.tv_usec;
6316 +       pm->mark = skb->nfmark;
6317         pm->hook = hooknum;
6318 -       if (loginfo->prefix[0] != '\0')
6319 +       if (prefix != NULL)
6320 +               strncpy(pm->prefix, prefix, sizeof(pm->prefix));
6321 +       else if (loginfo->prefix[0] != '\0')
6322                 strncpy(pm->prefix, loginfo->prefix, sizeof(pm->prefix));
6323         else
6324                 *(pm->prefix) = '\0';
6325  
6326         if (in && in->hard_header_len > 0
6327 -           && (*pskb)->mac.raw != (void *) (*pskb)->nh.iph
6328 +           && skb->mac.raw != (void *) skb->nh.iph
6329             && in->hard_header_len <= ULOG_MAC_LEN) {
6330 -               memcpy(pm->mac, (*pskb)->mac.raw, in->hard_header_len);
6331 +               memcpy(pm->mac, skb->mac.raw, in->hard_header_len);
6332                 pm->mac_len = in->hard_header_len;
6333         } else
6334                 pm->mac_len = 0;
6335 @@ -241,8 +248,8 @@
6336         else
6337                 pm->outdev_name[0] = '\0';
6338  
6339 -       /* copy_len <= (*pskb)->len, so can't fail. */
6340 -       if (skb_copy_bits(*pskb, 0, pm->payload, copy_len) < 0)
6341 +       /* copy_len <= skb->len, so can't fail. */
6342 +       if (skb_copy_bits(skb, 0, pm->payload, copy_len) < 0)
6343                 BUG();
6344         
6345         /* check if we are building multi-part messages */
6346 @@ -266,8 +273,7 @@
6347  
6348         UNLOCK_BH(&ulog_lock);
6349  
6350 -       return IPT_CONTINUE;
6351 -
6352 +       return;
6353  
6354  nlmsg_failure:
6355         PRINTR("ipt_ULOG: error during NLMSG_PUT\n");
6356 @@ -276,8 +282,35 @@
6357         PRINTR("ipt_ULOG: Error building netlink message\n");
6358  
6359         UNLOCK_BH(&ulog_lock);
6360 +}
6361 +
6362 +static unsigned int ipt_ulog_target(struct sk_buff **pskb,
6363 +                                   const struct net_device *in,
6364 +                                   const struct net_device *out,
6365 +                                   unsigned int hooknum,
6366 +                                   const void *targinfo, void *userinfo)
6367 +{
6368 +       struct ipt_ulog_info *loginfo = (struct ipt_ulog_info *) targinfo;
6369  
6370 -       return IPT_CONTINUE;
6371 +       ipt_ulog_packet(hooknum, *pskb, in, out, loginfo, NULL);
6372
6373 +       return IPT_CONTINUE;
6374 +}
6375
6376 +static void ipt_logfn(unsigned int hooknum,
6377 +                     const struct sk_buff *skb,
6378 +                     const struct net_device *in,
6379 +                     const struct net_device *out,
6380 +                     const char *prefix)
6381 +{
6382 +       struct ipt_ulog_info loginfo = { 
6383 +               .nl_group = ULOG_DEFAULT_NLGROUP,
6384 +               .copy_range = 0,
6385 +               .qthreshold = ULOG_DEFAULT_QTHRESHOLD,
6386 +               .prefix = ""
6387 +       };
6388 +
6389 +       ipt_ulog_packet(hooknum, skb, in, out, &loginfo, prefix);
6390  }
6391  
6392  static int ipt_ulog_checkentry(const char *tablename,
6393 @@ -341,7 +374,9 @@
6394                 sock_release(nflognl->sk_socket);
6395                 return -EINVAL;
6396         }
6397 -
6398 +       if (nflog)
6399 +               nf_log_register(PF_INET, &ipt_logfn);
6400 +       
6401         return 0;
6402  }
6403  
6404 @@ -352,6 +387,8 @@
6405  
6406         DEBUGP("ipt_ULOG: cleanup_module\n");
6407  
6408 +       if (nflog)
6409 +               nf_log_unregister(PF_INET, &ipt_logfn);
6410         ipt_unregister_target(&ipt_ulog_reg);
6411         sock_release(nflognl->sk_socket);
6412  
6413 diff -Nur linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_connlimit.c linux-2.6.4-rc2/net/ipv4/netfilter/ipt_connlimit.c
6414 --- linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_connlimit.c      1970-01-01 00:00:00.000000000 +0000
6415 +++ linux-2.6.4-rc2/net/ipv4/netfilter/ipt_connlimit.c  2004-03-05 09:55:15.000000000 +0000
6416 @@ -0,0 +1,230 @@
6417 +/*
6418 + * netfilter module to limit the number of parallel tcp
6419 + * connections per IP address.
6420 + *   (c) 2000 Gerd Knorr <kraxel@bytesex.org>
6421 + *   Nov 2002: Martin Bene <martin.bene@icomedias.com>:
6422 + *             only ignore TIME_WAIT or gone connections
6423 + *
6424 + * based on ...
6425 + *
6426 + * Kernel module to match connection tracking information.
6427 + * GPL (C) 1999  Rusty Russell (rusty@rustcorp.com.au).
6428 + */
6429 +#include <linux/module.h>
6430 +#include <linux/skbuff.h>
6431 +#include <linux/list.h>
6432 +#include <linux/netfilter_ipv4/ip_conntrack.h>
6433 +#include <linux/netfilter_ipv4/ip_conntrack_core.h>
6434 +#include <linux/netfilter_ipv4/ip_conntrack_tcp.h>
6435 +#include <linux/netfilter_ipv4/ip_tables.h>
6436 +#include <linux/netfilter_ipv4/ipt_connlimit.h>
6437 +
6438 +#define DEBUG 0
6439 +
6440 +MODULE_LICENSE("GPL");
6441 +
6442 +/* we'll save the tuples of all connections we care about */
6443 +struct ipt_connlimit_conn
6444 +{
6445 +        struct list_head list;
6446 +       struct ip_conntrack_tuple tuple;
6447 +};
6448 +
6449 +struct ipt_connlimit_data {
6450 +       spinlock_t lock;
6451 +       struct list_head iphash[256];
6452 +};
6453 +
6454 +static int ipt_iphash(u_int32_t addr)
6455 +{
6456 +       int hash;
6457 +
6458 +       hash  =  addr        & 0xff;
6459 +       hash ^= (addr >>  8) & 0xff;
6460 +       hash ^= (addr >> 16) & 0xff;
6461 +       hash ^= (addr >> 24) & 0xff;
6462 +       return hash;
6463 +}
6464 +
6465 +static int count_them(struct ipt_connlimit_data *data,
6466 +                     u_int32_t addr, u_int32_t mask,
6467 +                     struct ip_conntrack *ct)
6468 +{
6469 +#if DEBUG
6470 +       const static char *tcp[] = { "none", "established", "syn_sent", "syn_recv",
6471 +                                    "fin_wait", "time_wait", "close", "close_wait",
6472 +                                    "last_ack", "listen" };
6473 +#endif
6474 +       int addit = 1, matches = 0;
6475 +       struct ip_conntrack_tuple tuple;
6476 +       struct ip_conntrack_tuple_hash *found;
6477 +       struct ipt_connlimit_conn *conn;
6478 +       struct list_head *hash,*lh;
6479 +
6480 +       spin_lock(&data->lock);
6481 +       tuple = ct->tuplehash[0].tuple;
6482 +       hash = &data->iphash[ipt_iphash(addr & mask)];
6483 +
6484 +       /* check the saved connections */
6485 +       for (lh = hash->next; lh != hash; lh = lh->next) {
6486 +               conn = list_entry(lh,struct ipt_connlimit_conn,list);
6487 +               found = ip_conntrack_find_get(&conn->tuple,ct);
6488 +               if (0 == memcmp(&conn->tuple,&tuple,sizeof(tuple)) &&
6489 +                   found != NULL &&
6490 +                   found->ctrack->proto.tcp.state != TCP_CONNTRACK_TIME_WAIT) {
6491 +                       /* Just to be sure we have it only once in the list.
6492 +                          We should'nt see tuples twice unless someone hooks this
6493 +                          into a table without "-p tcp --syn" */
6494 +                       addit = 0;
6495 +               }
6496 +#if DEBUG
6497 +               printk("ipt_connlimit [%d]: src=%u.%u.%u.%u:%d dst=%u.%u.%u.%u:%d %s\n",
6498 +                      ipt_iphash(addr & mask),
6499 +                      NIPQUAD(conn->tuple.src.ip), ntohs(conn->tuple.src.u.tcp.port),
6500 +                      NIPQUAD(conn->tuple.dst.ip), ntohs(conn->tuple.dst.u.tcp.port),
6501 +                      (NULL != found) ? tcp[found->ctrack->proto.tcp.state] : "gone");
6502 +#endif
6503 +               if (NULL == found) {
6504 +                       /* this one is gone */
6505 +                       lh = lh->prev;
6506 +                       list_del(lh->next);
6507 +                       kfree(conn);
6508 +                       continue;
6509 +               }
6510 +               if (found->ctrack->proto.tcp.state == TCP_CONNTRACK_TIME_WAIT) {
6511 +                       /* we don't care about connections which are
6512 +                          closed already -> ditch it */
6513 +                       lh = lh->prev;
6514 +                       list_del(lh->next);
6515 +                       kfree(conn);
6516 +                       nf_conntrack_put(&found->ctrack->infos[0]);
6517 +                       continue;
6518 +               }
6519 +               if ((addr & mask) == (conn->tuple.src.ip & mask)) {
6520 +                       /* same source IP address -> be counted! */
6521 +                       matches++;
6522 +               }
6523 +               nf_conntrack_put(&found->ctrack->infos[0]);
6524 +       }
6525 +       if (addit) {
6526 +               /* save the new connection in our list */
6527 +#if DEBUG
6528 +               printk("ipt_connlimit [%d]: src=%u.%u.%u.%u:%d dst=%u.%u.%u.%u:%d new\n",
6529 +                      ipt_iphash(addr & mask),
6530 +                      NIPQUAD(tuple.src.ip), ntohs(tuple.src.u.tcp.port),
6531 +                      NIPQUAD(tuple.dst.ip), ntohs(tuple.dst.u.tcp.port));
6532 +#endif
6533 +               conn = kmalloc(sizeof(*conn),GFP_ATOMIC);
6534 +               if (NULL == conn)
6535 +                       return -1;
6536 +               memset(conn,0,sizeof(*conn));
6537 +               INIT_LIST_HEAD(&conn->list);
6538 +               conn->tuple = tuple;
6539 +               list_add(&conn->list,hash);
6540 +               matches++;
6541 +       }
6542 +       spin_unlock(&data->lock);
6543 +       return matches;
6544 +}
6545 +
6546 +static int
6547 +match(const struct sk_buff *skb,
6548 +      const struct net_device *in,
6549 +      const struct net_device *out,
6550 +      const void *matchinfo,
6551 +      int offset,
6552 +      int *hotdrop)
6553 +{
6554 +       const struct ipt_connlimit_info *info = matchinfo;
6555 +       int connections, match;
6556 +       struct ip_conntrack *ct;
6557 +       enum ip_conntrack_info ctinfo;
6558 +
6559 +       ct = ip_conntrack_get((struct sk_buff *)skb, &ctinfo);
6560 +       if (NULL == ct) {
6561 +               printk("ipt_connlimit: Oops: invalid ct state ?\n");
6562 +               *hotdrop = 1;
6563 +               return 0;
6564 +       }
6565 +       connections = count_them(info->data,skb->nh.iph->saddr,info->mask,ct);
6566 +       if (-1 == connections) {
6567 +               printk("ipt_connlimit: Hmm, kmalloc failed :-(\n");
6568 +               *hotdrop = 1; /* let's free some memory :-) */
6569 +               return 0;
6570 +       }
6571 +        match = (info->inverse) ? (connections <= info->limit) : (connections > info->limit);
6572 +#if DEBUG
6573 +       printk("ipt_connlimit: src=%u.%u.%u.%u mask=%u.%u.%u.%u "
6574 +              "connections=%d limit=%d match=%s\n",
6575 +              NIPQUAD(skb->nh.iph->saddr), NIPQUAD(info->mask),
6576 +              connections, info->limit, match ? "yes" : "no");
6577 +#endif
6578 +
6579 +       return match;
6580 +}
6581 +
6582 +static int check(const char *tablename,
6583 +                const struct ipt_ip *ip,
6584 +                void *matchinfo,
6585 +                unsigned int matchsize,
6586 +                unsigned int hook_mask)
6587 +{
6588 +       struct ipt_connlimit_info *info = matchinfo;
6589 +       int i;
6590 +
6591 +       /* verify size */
6592 +       if (matchsize != IPT_ALIGN(sizeof(struct ipt_connlimit_info)))
6593 +               return 0;
6594 +
6595 +       /* refuse anything but tcp */
6596 +       if (ip->proto != IPPROTO_TCP)
6597 +               return 0;
6598 +
6599 +       /* init private data */
6600 +       info->data = kmalloc(sizeof(struct ipt_connlimit_data),GFP_KERNEL);
6601 +       spin_lock_init(&(info->data->lock));
6602 +       for (i = 0; i < 256; i++)
6603 +               INIT_LIST_HEAD(&(info->data->iphash[i]));
6604 +       
6605 +       return 1;
6606 +}
6607 +
6608 +static void destroy(void *matchinfo, unsigned int matchinfosize)
6609 +{
6610 +       struct ipt_connlimit_info *info = matchinfo;
6611 +       struct ipt_connlimit_conn *conn;
6612 +       struct list_head *hash;
6613 +       int i;
6614 +
6615 +       /* cleanup */
6616 +       for (i = 0; i < 256; i++) {
6617 +               hash = &(info->data->iphash[i]);
6618 +               while (hash != hash->next) {
6619 +                       conn = list_entry(hash->next,struct ipt_connlimit_conn,list);
6620 +                       list_del(hash->next);
6621 +                       kfree(conn);
6622 +               }
6623 +       }
6624 +       kfree(info->data);
6625 +}
6626 +
6627 +static struct ipt_match connlimit_match = { 
6628 +       .name = "connlimit",
6629 +       .match = &match,
6630 +       .checkentry = &check,
6631 +       .destroy = &destroy,
6632 +       .me = THIS_MODULE
6633 +};
6634 +
6635 +static int __init init(void)
6636 +{
6637 +       return ipt_register_match(&connlimit_match);
6638 +}
6639 +
6640 +static void __exit fini(void)
6641 +{
6642 +       ipt_unregister_match(&connlimit_match);
6643 +}
6644 +
6645 +module_init(init);
6646 +module_exit(fini);
6647 diff -Nur linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_conntrack.c linux-2.6.4-rc2/net/ipv4/netfilter/ipt_conntrack.c
6648 --- linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_conntrack.c      2004-03-04 06:17:04.000000000 +0000
6649 +++ linux-2.6.4-rc2/net/ipv4/netfilter/ipt_conntrack.c  2004-03-05 09:55:23.000000000 +0000
6650 @@ -35,11 +35,13 @@
6651  
6652  #define FWINV(bool,invflg) ((bool) ^ !!(sinfo->invflags & invflg))
6653  
6654 -       if (ct)
6655 -               statebit = IPT_CONNTRACK_STATE_BIT(ctinfo);
6656 -       else
6657 -               statebit = IPT_CONNTRACK_STATE_INVALID;
6658 -
6659 +       if (skb->nfct == &ip_conntrack_untracked.infos[IP_CT_NEW])
6660 +               statebit = IPT_CONNTRACK_STATE_UNTRACKED;
6661 +       else if (ct)
6662 +               statebit = IPT_CONNTRACK_STATE_BIT(ctinfo);
6663 +       else
6664 +               statebit = IPT_CONNTRACK_STATE_INVALID;
6665
6666         if(sinfo->flags & IPT_CONNTRACK_STATE) {
6667                 if (ct) {
6668                         if(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip !=
6669 diff -Nur linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_conntrack.c.orig linux-2.6.4-rc2/net/ipv4/netfilter/ipt_conntrack.c.orig
6670 --- linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_conntrack.c.orig 1970-01-01 00:00:00.000000000 +0000
6671 +++ linux-2.6.4-rc2/net/ipv4/netfilter/ipt_conntrack.c.orig     2004-03-04 06:17:04.000000000 +0000
6672 @@ -0,0 +1,134 @@
6673 +/* Kernel module to match connection tracking information.
6674 + * Superset of Rusty's minimalistic state match.
6675 + *
6676 + * (C) 2001  Marc Boucher (marc@mbsi.ca).
6677 + *
6678 + * This program is free software; you can redistribute it and/or modify
6679 + * it under the terms of the GNU General Public License version 2 as
6680 + * published by the Free Software Foundation.
6681 + */
6682 +
6683 +#include <linux/module.h>
6684 +#include <linux/skbuff.h>
6685 +#include <linux/netfilter_ipv4/ip_conntrack.h>
6686 +#include <linux/netfilter_ipv4/ip_tables.h>
6687 +#include <linux/netfilter_ipv4/ipt_conntrack.h>
6688 +
6689 +MODULE_LICENSE("GPL");
6690 +MODULE_AUTHOR("Marc Boucher <marc@mbsi.ca>");
6691 +MODULE_DESCRIPTION("iptables connection tracking match module");
6692 +
6693 +static int
6694 +match(const struct sk_buff *skb,
6695 +      const struct net_device *in,
6696 +      const struct net_device *out,
6697 +      const void *matchinfo,
6698 +      int offset,
6699 +      int *hotdrop)
6700 +{
6701 +       const struct ipt_conntrack_info *sinfo = matchinfo;
6702 +       struct ip_conntrack *ct;
6703 +       enum ip_conntrack_info ctinfo;
6704 +       unsigned int statebit;
6705 +
6706 +       ct = ip_conntrack_get((struct sk_buff *)skb, &ctinfo);
6707 +
6708 +#define FWINV(bool,invflg) ((bool) ^ !!(sinfo->invflags & invflg))
6709 +
6710 +       if (ct)
6711 +               statebit = IPT_CONNTRACK_STATE_BIT(ctinfo);
6712 +       else
6713 +               statebit = IPT_CONNTRACK_STATE_INVALID;
6714 +
6715 +       if(sinfo->flags & IPT_CONNTRACK_STATE) {
6716 +               if (ct) {
6717 +                       if(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip !=
6718 +                           ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip)
6719 +                               statebit |= IPT_CONNTRACK_STATE_SNAT;
6720 +
6721 +                       if(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip !=
6722 +                           ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip)
6723 +                               statebit |= IPT_CONNTRACK_STATE_DNAT;
6724 +               }
6725 +
6726 +               if (FWINV((statebit & sinfo->statemask) == 0, IPT_CONNTRACK_STATE))
6727 +                       return 0;
6728 +       }
6729 +
6730 +       if(sinfo->flags & IPT_CONNTRACK_PROTO) {
6731 +               if (!ct || FWINV(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum != sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.protonum, IPT_CONNTRACK_PROTO))
6732 +                       return 0;
6733 +       }
6734 +
6735 +       if(sinfo->flags & IPT_CONNTRACK_ORIGSRC) {
6736 +               if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip&sinfo->sipmsk[IP_CT_DIR_ORIGINAL].s_addr) != sinfo->tuple[IP_CT_DIR_ORIGINAL].src.ip, IPT_CONNTRACK_ORIGSRC))
6737 +                       return 0;
6738 +       }
6739 +
6740 +       if(sinfo->flags & IPT_CONNTRACK_ORIGDST) {
6741 +               if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip&sinfo->dipmsk[IP_CT_DIR_ORIGINAL].s_addr) != sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.ip, IPT_CONNTRACK_ORIGDST))
6742 +                       return 0;
6743 +       }
6744 +
6745 +       if(sinfo->flags & IPT_CONNTRACK_REPLSRC) {
6746 +               if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip&sinfo->sipmsk[IP_CT_DIR_REPLY].s_addr) != sinfo->tuple[IP_CT_DIR_REPLY].src.ip, IPT_CONNTRACK_REPLSRC))
6747 +                       return 0;
6748 +       }
6749 +
6750 +       if(sinfo->flags & IPT_CONNTRACK_REPLDST) {
6751 +               if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip&sinfo->dipmsk[IP_CT_DIR_REPLY].s_addr) != sinfo->tuple[IP_CT_DIR_REPLY].dst.ip, IPT_CONNTRACK_REPLDST))
6752 +                       return 0;
6753 +       }
6754 +
6755 +       if(sinfo->flags & IPT_CONNTRACK_STATUS) {
6756 +               if (!ct || FWINV((ct->status & sinfo->statusmask) == 0, IPT_CONNTRACK_STATUS))
6757 +                       return 0;
6758 +       }
6759 +
6760 +       if(sinfo->flags & IPT_CONNTRACK_EXPIRES) {
6761 +               unsigned long expires;
6762 +
6763 +               if(!ct)
6764 +                       return 0;
6765 +
6766 +               expires = timer_pending(&ct->timeout) ? (ct->timeout.expires - jiffies)/HZ : 0;
6767 +
6768 +               if (FWINV(!(expires >= sinfo->expires_min && expires <= sinfo->expires_max), IPT_CONNTRACK_EXPIRES))
6769 +                       return 0;
6770 +       }
6771 +
6772 +       return 1;
6773 +}
6774 +
6775 +static int check(const char *tablename,
6776 +                const struct ipt_ip *ip,
6777 +                void *matchinfo,
6778 +                unsigned int matchsize,
6779 +                unsigned int hook_mask)
6780 +{
6781 +       if (matchsize != IPT_ALIGN(sizeof(struct ipt_conntrack_info)))
6782 +               return 0;
6783 +
6784 +       return 1;
6785 +}
6786 +
6787 +static struct ipt_match conntrack_match = {
6788 +       .name           = "conntrack",
6789 +       .match          = &match,
6790 +       .checkentry     = &check,
6791 +       .me             = THIS_MODULE,
6792 +};
6793 +
6794 +static int __init init(void)
6795 +{
6796 +       need_ip_conntrack();
6797 +       return ipt_register_match(&conntrack_match);
6798 +}
6799 +
6800 +static void __exit fini(void)
6801 +{
6802 +       ipt_unregister_match(&conntrack_match);
6803 +}
6804 +
6805 +module_init(init);
6806 +module_exit(fini);
6807 diff -Nur linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_dstlimit.c linux-2.6.4-rc2/net/ipv4/netfilter/ipt_dstlimit.c
6808 --- linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_dstlimit.c       1970-01-01 00:00:00.000000000 +0000
6809 +++ linux-2.6.4-rc2/net/ipv4/netfilter/ipt_dstlimit.c   2004-03-05 09:55:17.000000000 +0000
6810 @@ -0,0 +1,690 @@
6811 +/* iptables match extension to limit the number of packets per second
6812 + * seperately for each destination.
6813 + *
6814 + * (C) 2003 by Harald Welte <laforge@netfilter.org>
6815 + *
6816 + * $Id$
6817 + *
6818 + * Development of this code was funded by Astaro AG, http://www.astaro.com/
6819 + *
6820 + * based on ipt_limit.c by:
6821 + * Jérôme de Vivie     <devivie@info.enserb.u-bordeaux.fr>
6822 + * Hervé Eychenne      <eychenne@info.enserb.u-bordeaux.fr>
6823 + * Rusty Russell       <rusty@rustcorp.com.au>
6824 + *
6825 + * The general idea is to create a hash table for every dstip and have a
6826 + * seperate limit counter per tuple.  This way you can do something like 'limit
6827 + * the number of syn packets for each of my internal addresses.
6828 + *
6829 + * Ideally this would just be implemented as a general 'hash' match, which would
6830 + * allow us to attach any iptables target to it's hash buckets.  But this is
6831 + * not possible in the current iptables architecture.  As always, pkttables for
6832 + * 2.7.x will help ;)
6833 + */
6834 +#include <linux/module.h>
6835 +#include <linux/skbuff.h>
6836 +#include <linux/spinlock.h>
6837 +#include <linux/random.h>
6838 +#include <linux/jhash.h>
6839 +#include <linux/slab.h>
6840 +#include <linux/vmalloc.h>
6841 +#include <linux/tcp.h>
6842 +#include <linux/udp.h>
6843 +#include <linux/proc_fs.h>
6844 +#include <linux/seq_file.h>
6845 +
6846 +#define ASSERT_READ_LOCK(x) 
6847 +#define ASSERT_WRITE_LOCK(x) 
6848 +#include <linux/netfilter_ipv4/lockhelp.h>
6849 +#include <linux/netfilter_ipv4/listhelp.h>
6850 +
6851 +#include <linux/netfilter_ipv4/ip_tables.h>
6852 +#include <linux/netfilter_ipv4/ipt_dstlimit.h>
6853 +
6854 +/* FIXME: this is just for IP_NF_ASSERRT */
6855 +#include <linux/netfilter_ipv4/ip_conntrack.h>
6856 +
6857 +#define MS2JIFFIES(x) ((x*HZ)/1000)
6858 +
6859 +MODULE_LICENSE("GPL");
6860 +MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
6861 +MODULE_DESCRIPTION("iptables match for limiting per destination");
6862 +
6863 +/* need to declare this at the top */
6864 +static struct proc_dir_entry *dstlimit_procdir;
6865 +static struct file_operations dl_file_ops;
6866 +
6867 +/* hash table crap */
6868 +
6869 +struct dsthash_dst {
6870 +       u_int32_t src_ip;
6871 +       u_int32_t dst_ip;
6872 +       u_int16_t port;
6873 +};
6874 +
6875 +struct dsthash_ent {
6876 +       /* static / read-only parts in the beginning */
6877 +       struct list_head list;
6878 +       struct dsthash_dst dst;
6879 +
6880 +       /* modified structure members in the end */
6881 +       unsigned long expires;          /* precalculated expiry time */
6882 +       struct {
6883 +               unsigned long prev;     /* last modification */
6884 +               u_int32_t credit;
6885 +               u_int32_t credit_cap, cost;
6886 +       } rateinfo;
6887 +};
6888 +
6889 +struct ipt_dstlimit_htable {
6890 +       struct list_head list;          /* global list of all htables */
6891 +       atomic_t use;
6892 +
6893 +       struct dstlimit_cfg cfg;        /* config */
6894 +
6895 +       /* used internally */
6896 +       spinlock_t lock;                /* lock for list_head */
6897 +       u_int32_t rnd;                  /* random seed for hash */
6898 +       struct timer_list timer;        /* timer for gc */
6899 +       atomic_t count;                 /* number entries in table */
6900 +
6901 +       /* seq_file stuff */
6902 +       struct proc_dir_entry *pde;
6903 +
6904 +       struct list_head hash[0];       /* hashtable itself */
6905 +};
6906 +
6907 +DECLARE_RWLOCK(dstlimit_lock);         /* protects htables list */
6908 +static LIST_HEAD(dstlimit_htables);
6909 +static kmem_cache_t *dstlimit_cachep;
6910 +
6911 +static inline int dst_cmp(const struct dsthash_ent *ent, struct dsthash_dst *b)
6912 +{
6913 +       return (ent->dst.dst_ip == b->dst_ip 
6914 +               && ent->dst.port == b->port
6915 +               && ent->dst.src_ip == b->src_ip);
6916 +}
6917 +
6918 +static inline u_int32_t
6919 +hash_dst(const struct ipt_dstlimit_htable *ht, const struct dsthash_dst *dst)
6920 +{
6921 +       return (jhash_3words(dst->dst_ip, dst->port, 
6922 +                            dst->src_ip, ht->rnd) % ht->cfg.size);
6923 +}
6924 +
6925 +static inline struct dsthash_ent *
6926 +__dsthash_find(const struct ipt_dstlimit_htable *ht, struct dsthash_dst *dst)
6927 +{
6928 +       struct dsthash_ent *ent;
6929 +       u_int32_t hash = hash_dst(ht, dst);
6930 +       MUST_BE_LOCKED(&ht->lock);
6931 +       ent = LIST_FIND(&ht->hash[hash], dst_cmp, struct dsthash_ent *, dst);
6932 +       return ent;
6933 +}
6934 +
6935 +/* allocate dsthash_ent, initialize dst, put in htable and lock it */
6936 +static struct dsthash_ent *
6937 +__dsthash_alloc_init(struct ipt_dstlimit_htable *ht, struct dsthash_dst *dst)
6938 +{
6939 +       struct dsthash_ent *ent;
6940 +
6941 +       /* initialize hash with random val at the time we allocate
6942 +        * the first hashtable entry */
6943 +       if (!ht->rnd)
6944 +               get_random_bytes(&ht->rnd, 4);
6945 +
6946 +       if (ht->cfg.max &&
6947 +           atomic_read(&ht->count) >= ht->cfg.max) {
6948 +               /* FIXME: do something. question is what.. */
6949 +               if (net_ratelimit())
6950 +                       printk(KERN_WARNING 
6951 +                               "ipt_dstlimit: max count of %u reached\n", 
6952 +                               ht->cfg.max);
6953 +               return NULL;
6954 +       }
6955 +
6956 +       ent = kmem_cache_alloc(dstlimit_cachep, GFP_ATOMIC);
6957 +       if (!ent) {
6958 +               if (net_ratelimit())
6959 +                       printk(KERN_ERR 
6960 +                               "ipt_dstlimit: can't allocate dsthash_ent\n");
6961 +               return NULL;
6962 +       }
6963 +
6964 +       atomic_inc(&ht->count);
6965 +
6966 +       ent->dst.dst_ip = dst->dst_ip;
6967 +       ent->dst.port = dst->port;
6968 +       ent->dst.src_ip = dst->src_ip;
6969 +
6970 +       list_add(&ent->list, &ht->hash[hash_dst(ht, dst)]);
6971 +
6972 +       return ent;
6973 +}
6974 +
6975 +static inline void 
6976 +__dsthash_free(struct ipt_dstlimit_htable *ht, struct dsthash_ent *ent)
6977 +{
6978 +       MUST_BE_LOCKED(&ht->lock);
6979 +
6980 +       list_del(&ent->list);
6981 +       kmem_cache_free(dstlimit_cachep, ent);
6982 +       atomic_dec(&ht->count);
6983 +}
6984 +static void htable_gc(unsigned long htlong);
6985 +
6986 +static int htable_create(struct ipt_dstlimit_info *minfo)
6987 +{
6988 +       int i;
6989 +       unsigned int size;
6990 +       struct ipt_dstlimit_htable *hinfo;
6991 +
6992 +       if (minfo->cfg.size)
6993 +               size = minfo->cfg.size;
6994 +       else {
6995 +               size = (((num_physpages << PAGE_SHIFT) / 16384)
6996 +                        / sizeof(struct list_head));
6997 +               if (num_physpages > (1024 * 1024 * 1024 / PAGE_SIZE))
6998 +                       size = 8192;
6999 +               if (size < 16)
7000 +                       size = 16;
7001 +       }
7002 +       /* FIXME: don't use vmalloc() here or anywhere else -HW */
7003 +       hinfo = vmalloc(sizeof(struct ipt_dstlimit_htable)
7004 +                       + (sizeof(struct list_head) * size));
7005 +       if (!hinfo) {
7006 +               printk(KERN_ERR "ipt_dstlimit: Unable to create hashtable\n");
7007 +               return -1;
7008 +       }
7009 +       minfo->hinfo = hinfo;
7010 +
7011 +       /* copy match config into hashtable config */
7012 +       memcpy(&hinfo->cfg, &minfo->cfg, sizeof(hinfo->cfg));
7013 +       hinfo->cfg.size = size;
7014 +       if (!hinfo->cfg.max)
7015 +               hinfo->cfg.max = 8 * hinfo->cfg.size;
7016 +       else if (hinfo->cfg.max < hinfo->cfg.size)
7017 +               hinfo->cfg.max = hinfo->cfg.size;
7018 +
7019 +       for (i = 0; i < hinfo->cfg.size; i++)
7020 +               INIT_LIST_HEAD(&hinfo->hash[i]);
7021 +
7022 +       atomic_set(&hinfo->count, 0);
7023 +       atomic_set(&hinfo->use, 1);
7024 +       hinfo->rnd = 0;
7025 +       hinfo->lock = SPIN_LOCK_UNLOCKED;
7026 +       hinfo->pde = create_proc_entry(minfo->name, 0, dstlimit_procdir);
7027 +       if (!hinfo->pde) {
7028 +               vfree(hinfo);
7029 +               return -1;
7030 +       }
7031 +       hinfo->pde->proc_fops = &dl_file_ops;
7032 +       hinfo->pde->data = hinfo;
7033 +
7034 +       init_timer(&hinfo->timer);
7035 +       hinfo->timer.expires = jiffies + MS2JIFFIES(hinfo->cfg.gc_interval);
7036 +       hinfo->timer.data = (unsigned long )hinfo;
7037 +       hinfo->timer.function = htable_gc;
7038 +       add_timer(&hinfo->timer);
7039 +
7040 +       WRITE_LOCK(&dstlimit_lock);
7041 +       list_add(&hinfo->list, &dstlimit_htables);
7042 +       WRITE_UNLOCK(&dstlimit_lock);
7043 +
7044 +       return 0;
7045 +}
7046 +
7047 +static int select_all(struct ipt_dstlimit_htable *ht, struct dsthash_ent *he)
7048 +{
7049 +       return 1;
7050 +}
7051 +
7052 +static int select_gc(struct ipt_dstlimit_htable *ht, struct dsthash_ent *he)
7053 +{
7054 +       return (jiffies >= he->expires);
7055 +}
7056 +
7057 +static void htable_selective_cleanup(struct ipt_dstlimit_htable *ht,
7058 +                               int (*select)(struct ipt_dstlimit_htable *ht, 
7059 +                                             struct dsthash_ent *he))
7060 +{
7061 +       int i;
7062 +
7063 +       IP_NF_ASSERT(ht->cfg.size && ht->cfg.max);
7064 +
7065 +       /* lock hash table and iterate over it */
7066 +       LOCK_BH(&ht->lock);
7067 +       for (i = 0; i < ht->cfg.size; i++) {
7068 +               struct dsthash_ent *dh, *n;
7069 +               list_for_each_entry_safe(dh, n, &ht->hash[i], list) {
7070 +                       if ((*select)(ht, dh))
7071 +                               __dsthash_free(ht, dh);
7072 +               }
7073 +       }
7074 +       UNLOCK_BH(&ht->lock);
7075 +}
7076 +
7077 +/* hash table garbage collector, run by timer */
7078 +static void htable_gc(unsigned long htlong)
7079 +{
7080 +       struct ipt_dstlimit_htable *ht = (struct ipt_dstlimit_htable *)htlong;
7081 +
7082 +       htable_selective_cleanup(ht, select_gc);
7083 +
7084 +       /* re-add the timer accordingly */
7085 +       ht->timer.expires = jiffies + MS2JIFFIES(ht->cfg.gc_interval);
7086 +       add_timer(&ht->timer);
7087 +}
7088 +
7089 +static void htable_destroy(struct ipt_dstlimit_htable *hinfo)
7090 +{
7091 +       /* remove timer, if it is pending */
7092 +       if (timer_pending(&hinfo->timer))
7093 +               del_timer(&hinfo->timer);
7094 +
7095 +       /* remove proc entry */
7096 +       remove_proc_entry(hinfo->pde->name, dstlimit_procdir);
7097 +
7098 +       htable_selective_cleanup(hinfo, select_all);
7099 +       vfree(hinfo);
7100 +}
7101 +
7102 +static struct ipt_dstlimit_htable *htable_find_get(char *name)
7103 +{
7104 +       struct ipt_dstlimit_htable *hinfo;
7105 +
7106 +       READ_LOCK(&dstlimit_lock);
7107 +       list_for_each_entry(hinfo, &dstlimit_htables, list) {
7108 +               if (!strcmp(name, hinfo->pde->name)) {
7109 +                       atomic_inc(&hinfo->use);
7110 +                       READ_UNLOCK(&dstlimit_lock);
7111 +                       return hinfo;
7112 +               }
7113 +       }
7114 +       READ_UNLOCK(&dstlimit_lock);
7115 +
7116 +       return NULL;
7117 +}
7118 +
7119 +static void htable_put(struct ipt_dstlimit_htable *hinfo)
7120 +{
7121 +       if (atomic_dec_and_test(&hinfo->use)) {
7122 +               WRITE_LOCK(&dstlimit_lock);
7123 +               list_del(&hinfo->list);
7124 +               WRITE_UNLOCK(&dstlimit_lock);
7125 +               htable_destroy(hinfo);
7126 +       }
7127 +}
7128 +
7129 +
7130 +/* The algorithm used is the Simple Token Bucket Filter (TBF)
7131 + * see net/sched/sch_tbf.c in the linux source tree
7132 + */
7133 +
7134 +/* Rusty: This is my (non-mathematically-inclined) understanding of
7135 +   this algorithm.  The `average rate' in jiffies becomes your initial
7136 +   amount of credit `credit' and the most credit you can ever have
7137 +   `credit_cap'.  The `peak rate' becomes the cost of passing the
7138 +   test, `cost'.
7139 +
7140 +   `prev' tracks the last packet hit: you gain one credit per jiffy.
7141 +   If you get credit balance more than this, the extra credit is
7142 +   discarded.  Every time the match passes, you lose `cost' credits;
7143 +   if you don't have that many, the test fails.
7144 +
7145 +   See Alexey's formal explanation in net/sched/sch_tbf.c.
7146 +
7147 +   To get the maximum range, we multiply by this factor (ie. you get N
7148 +   credits per jiffy).  We want to allow a rate as low as 1 per day
7149 +   (slowest userspace tool allows), which means
7150 +   CREDITS_PER_JIFFY*HZ*60*60*24 < 2^32 ie.
7151 +*/
7152 +#define MAX_CPJ (0xFFFFFFFF / (HZ*60*60*24))
7153 +
7154 +/* Repeated shift and or gives us all 1s, final shift and add 1 gives
7155 + * us the power of 2 below the theoretical max, so GCC simply does a
7156 + * shift. */
7157 +#define _POW2_BELOW2(x) ((x)|((x)>>1))
7158 +#define _POW2_BELOW4(x) (_POW2_BELOW2(x)|_POW2_BELOW2((x)>>2))
7159 +#define _POW2_BELOW8(x) (_POW2_BELOW4(x)|_POW2_BELOW4((x)>>4))
7160 +#define _POW2_BELOW16(x) (_POW2_BELOW8(x)|_POW2_BELOW8((x)>>8))
7161 +#define _POW2_BELOW32(x) (_POW2_BELOW16(x)|_POW2_BELOW16((x)>>16))
7162 +#define POW2_BELOW32(x) ((_POW2_BELOW32(x)>>1) + 1)
7163 +
7164 +#define CREDITS_PER_JIFFY POW2_BELOW32(MAX_CPJ)
7165 +
7166 +/* Precision saver. */
7167 +static inline u_int32_t
7168 +user2credits(u_int32_t user)
7169 +{
7170 +       /* If multiplying would overflow... */
7171 +       if (user > 0xFFFFFFFF / (HZ*CREDITS_PER_JIFFY))
7172 +               /* Divide first. */
7173 +               return (user / IPT_DSTLIMIT_SCALE) * HZ * CREDITS_PER_JIFFY;
7174 +
7175 +       return (user * HZ * CREDITS_PER_JIFFY) / IPT_DSTLIMIT_SCALE;
7176 +}
7177 +
7178 +static inline void rateinfo_recalc(struct dsthash_ent *dh, unsigned long now)
7179 +{
7180 +       dh->rateinfo.credit += (now - xchg(&dh->rateinfo.prev, now)) 
7181 +                                       * CREDITS_PER_JIFFY;
7182 +       if (dh->rateinfo.credit > dh->rateinfo.credit_cap)
7183 +               dh->rateinfo.credit = dh->rateinfo.credit_cap;
7184 +}
7185 +
7186 +static int
7187 +dstlimit_match(const struct sk_buff *skb,
7188 +               const struct net_device *in,
7189 +               const struct net_device *out,
7190 +               const void *matchinfo,
7191 +               int offset,
7192 +               int *hotdrop)
7193 +{
7194 +       struct ipt_dstlimit_info *r = 
7195 +               ((struct ipt_dstlimit_info *)matchinfo)->u.master;
7196 +       struct ipt_dstlimit_htable *hinfo = r->hinfo;
7197 +       unsigned long now = jiffies;
7198 +       struct dsthash_ent *dh;
7199 +       struct dsthash_dst dst;
7200 +
7201 +       memset(&dst, 0, sizeof(dst));
7202 +
7203 +       /* dest ip is always in hash */
7204 +       dst.dst_ip = skb->nh.iph->daddr;
7205 +
7206 +       /* source ip only if respective hashmode, otherwise set to
7207 +        * zero */
7208 +       if (hinfo->cfg.mode & IPT_DSTLIMIT_HASH_SIP)
7209 +               dst.src_ip = skb->nh.iph->saddr;
7210 +
7211 +       /* dest port only if respective mode */
7212 +       if (hinfo->cfg.mode & IPT_DSTLIMIT_HASH_DPT) {
7213 +               u16 ports[2];
7214 +
7215 +               /* Must not be a fragment. */
7216 +               if (offset)
7217 +                       return 0;
7218 +
7219 +               /* Must be big enough to read ports (both UDP and TCP have
7220 +                  them at the start). */
7221 +               if (skb_copy_bits(skb, skb->nh.iph->ihl*4, ports, sizeof(ports)) < 0) {
7222 +                       /* We've been asked to examine this packet, and we
7223 +                          can't.  Hence, no choice but to drop. */
7224 +                       *hotdrop = 1;
7225 +                       return 0;
7226 +               }
7227 +
7228 +               switch (skb->nh.iph->protocol) {
7229 +                       struct tcphdr *th;
7230 +                       struct udphdr *uh;
7231 +               case IPPROTO_TCP:
7232 +                       th = (void *)skb->nh.iph+skb->nh.iph->ihl*4;
7233 +                       dst.port = th->dest;
7234 +                       break;
7235 +               case IPPROTO_UDP:
7236 +                       uh = (void *)skb->nh.iph+skb->nh.iph->ihl*4;
7237 +                       dst.port = uh->dest;
7238 +                       break;
7239 +               default:
7240 +                       break;
7241 +               }
7242 +       } 
7243 +
7244 +       LOCK_BH(&hinfo->lock);
7245 +       dh = __dsthash_find(hinfo, &dst);
7246 +       if (!dh) {
7247 +               dh = __dsthash_alloc_init(hinfo, &dst);
7248 +
7249 +               if (!dh) {
7250 +                       /* enomem... don't match == DROP */
7251 +                       if (net_ratelimit())
7252 +                               printk(KERN_ERR "%s: ENOMEM\n", __FUNCTION__);
7253 +                       UNLOCK_BH(&hinfo->lock);
7254 +                       return 0;
7255 +               }
7256 +
7257 +               dh->expires = jiffies + MS2JIFFIES(hinfo->cfg.expire);
7258 +
7259 +               dh->rateinfo.prev = jiffies;
7260 +               dh->rateinfo.credit = user2credits(hinfo->cfg.avg * 
7261 +                                                       hinfo->cfg.burst);
7262 +               dh->rateinfo.credit_cap = user2credits(hinfo->cfg.avg * 
7263 +                                                       hinfo->cfg.burst);
7264 +               dh->rateinfo.cost = user2credits(hinfo->cfg.avg);
7265 +
7266 +               UNLOCK_BH(&hinfo->lock);
7267 +               return 1;
7268 +       }
7269 +
7270 +       /* update expiration timeout */
7271 +       dh->expires = now + MS2JIFFIES(hinfo->cfg.expire);
7272 +
7273 +       rateinfo_recalc(dh, now);
7274 +       if (dh->rateinfo.credit >= dh->rateinfo.cost) {
7275 +               /* We're underlimit. */
7276 +               dh->rateinfo.credit -= dh->rateinfo.cost;
7277 +               UNLOCK_BH(&hinfo->lock);
7278 +               return 1;
7279 +       }
7280 +
7281 +               UNLOCK_BH(&hinfo->lock);
7282 +
7283 +       /* default case: we're overlimit, thus don't match */
7284 +       return 0;
7285 +}
7286 +
7287 +static int
7288 +dstlimit_checkentry(const char *tablename,
7289 +                    const struct ipt_ip *ip,
7290 +                    void *matchinfo,
7291 +                    unsigned int matchsize,
7292 +                    unsigned int hook_mask)
7293 +{
7294 +       struct ipt_dstlimit_info *r = matchinfo;
7295 +
7296 +       if (matchsize != IPT_ALIGN(sizeof(struct ipt_dstlimit_info)))
7297 +               return 0;
7298 +
7299 +       /* Check for overflow. */
7300 +       if (r->cfg.burst == 0
7301 +           || user2credits(r->cfg.avg * r->cfg.burst) < 
7302 +                                       user2credits(r->cfg.avg)) {
7303 +               printk(KERN_ERR "ipt_dstlimit: Overflow, try lower: %u/%u\n",
7304 +                      r->cfg.avg, r->cfg.burst);
7305 +               return 0;
7306 +       }
7307 +
7308 +       if (r->cfg.mode == 0 
7309 +           || r->cfg.mode > (IPT_DSTLIMIT_HASH_DPT
7310 +                         |IPT_DSTLIMIT_HASH_DIP
7311 +                         |IPT_DSTLIMIT_HASH_SIP))
7312 +               return 0;
7313 +
7314 +       if (!r->cfg.gc_interval)
7315 +               return 0;
7316 +       
7317 +       if (!r->cfg.expire)
7318 +               return 0;
7319 +
7320 +       r->hinfo = htable_find_get(r->name);
7321 +       if (!r->hinfo && (htable_create(r) != 0)) {
7322 +               return 0;
7323 +       }
7324 +
7325 +       /* Ugly hack: For SMP, we only want to use one set */
7326 +       r->u.master = r;
7327 +
7328 +       return 1;
7329 +}
7330 +
7331 +static void
7332 +dstlimit_destroy(void *matchinfo, unsigned int matchsize)
7333 +{
7334 +       struct ipt_dstlimit_info *r = (struct ipt_dstlimit_info *) matchinfo;
7335 +
7336 +       htable_put(r->hinfo);
7337 +}
7338 +
7339 +static struct ipt_match ipt_dstlimit = { 
7340 +       .list = { .prev = NULL, .next = NULL }, 
7341 +       .name = "dstlimit", 
7342 +       .match = dstlimit_match, 
7343 +       .checkentry = dstlimit_checkentry, 
7344 +       .destroy = dstlimit_destroy,
7345 +       .me = THIS_MODULE 
7346 +};
7347 +
7348 +/* PROC stuff */
7349 +
7350 +static void *dl_seq_start(struct seq_file *s, loff_t *pos)
7351 +{
7352 +       struct proc_dir_entry *pde = s->private;
7353 +       struct ipt_dstlimit_htable *htable = pde->data;
7354 +       unsigned int *bucket;
7355 +
7356 +       LOCK_BH(&htable->lock);
7357 +       if (*pos >= htable->cfg.size)
7358 +               return NULL;
7359 +
7360 +       bucket = kmalloc(sizeof(unsigned int), GFP_KERNEL);
7361 +       if (!bucket)
7362 +               return ERR_PTR(-ENOMEM);
7363 +
7364 +       *bucket = *pos;
7365 +       return bucket;
7366 +}
7367 +
7368 +static void *dl_seq_next(struct seq_file *s, void *v, loff_t *pos)
7369 +{
7370 +       struct proc_dir_entry *pde = s->private;
7371 +       struct ipt_dstlimit_htable *htable = pde->data;
7372 +       unsigned int *bucket = (unsigned int *)v;
7373 +
7374 +       *pos = ++(*bucket);
7375 +       if (*pos >= htable->cfg.size) {
7376 +               kfree(v);
7377 +               return NULL;
7378 +       }
7379 +       return bucket;
7380 +}
7381 +
7382 +static void dl_seq_stop(struct seq_file *s, void *v)
7383 +{
7384 +       struct proc_dir_entry *pde = s->private;
7385 +       struct ipt_dstlimit_htable *htable = pde->data;
7386 +       unsigned int *bucket = (unsigned int *)v;
7387 +
7388 +       kfree(bucket);
7389 +
7390 +       UNLOCK_BH(&htable->lock);
7391 +}
7392 +
7393 +static inline int dl_seq_real_show(struct dsthash_ent *ent, struct seq_file *s)
7394 +{
7395 +       /* recalculate to show accurate numbers */
7396 +       rateinfo_recalc(ent, jiffies);
7397 +
7398 +       return seq_printf(s, "%ld %u.%u.%u.%u->%u.%u.%u.%u:%u %u %u %u\n",
7399 +                       (ent->expires - jiffies)/HZ,
7400 +                       NIPQUAD(ent->dst.src_ip),
7401 +                       NIPQUAD(ent->dst.dst_ip), ntohs(ent->dst.port),
7402 +                       ent->rateinfo.credit, ent->rateinfo.credit_cap,
7403 +                       ent->rateinfo.cost);
7404 +}
7405 +
7406 +static int dl_seq_show(struct seq_file *s, void *v)
7407 +{
7408 +       struct proc_dir_entry *pde = s->private;
7409 +       struct ipt_dstlimit_htable *htable = pde->data;
7410 +       unsigned int *bucket = (unsigned int *)v;
7411 +
7412 +       if (LIST_FIND_W(&htable->hash[*bucket], dl_seq_real_show,
7413 +                     struct dsthash_ent *, s)) {
7414 +               /* buffer was filled and unable to print that tuple */
7415 +               return 1;
7416 +       }
7417 +       return 0;
7418 +}
7419 +
7420 +static struct seq_operations dl_seq_ops = {
7421 +       .start = dl_seq_start,
7422 +       .next  = dl_seq_next,
7423 +       .stop  = dl_seq_stop,
7424 +       .show  = dl_seq_show
7425 +};
7426 +
7427 +static int dl_proc_open(struct inode *inode, struct file *file)
7428 +{
7429 +       int ret = seq_open(file, &dl_seq_ops);
7430 +
7431 +       if (!ret) {
7432 +               struct seq_file *sf = file->private_data;
7433 +               sf->private = PDE(inode);
7434 +       }
7435 +       return ret;
7436 +}
7437 +
7438 +static struct file_operations dl_file_ops = {
7439 +       .owner   = THIS_MODULE,
7440 +       .open    = dl_proc_open,
7441 +       .read    = seq_read,
7442 +       .llseek  = seq_lseek,
7443 +       .release = seq_release
7444 +};
7445 +
7446 +static int init_or_fini(int fini)
7447 +{
7448 +       int ret = 0;
7449 +
7450 +       if (fini)
7451 +               goto cleanup;
7452 +
7453 +       if (ipt_register_match(&ipt_dstlimit)) {
7454 +               ret = -EINVAL;
7455 +               goto cleanup_nothing;
7456 +       }
7457 +
7458 +       /* FIXME: do we really want HWCACHE_ALIGN since our objects are
7459 +        * quite small ? */
7460 +       dstlimit_cachep = kmem_cache_create("ipt_dstlimit",
7461 +                                           sizeof(struct dsthash_ent), 0,
7462 +                                           SLAB_HWCACHE_ALIGN, NULL, NULL);
7463 +       if (!dstlimit_cachep) {
7464 +               printk(KERN_ERR "Unable to create ipt_dstlimit slab cache\n");
7465 +               ret = -ENOMEM;
7466 +               goto cleanup_unreg_match;
7467 +       }
7468 +
7469 +       dstlimit_procdir = proc_mkdir("ipt_dstlimit", proc_net);
7470 +       if (!dstlimit_procdir) {
7471 +               printk(KERN_ERR "Unable to create proc dir entry\n");
7472 +               ret = -ENOMEM;
7473 +               goto cleanup_free_slab;
7474 +       }
7475 +
7476 +       return ret;
7477 +
7478 +cleanup:
7479 +       remove_proc_entry("ipt_dstlimit", proc_net);
7480 +cleanup_free_slab:
7481 +       kmem_cache_destroy(dstlimit_cachep);
7482 +cleanup_unreg_match:
7483 +       ipt_unregister_match(&ipt_dstlimit);
7484 +cleanup_nothing:
7485 +       return ret;
7486 +       
7487 +}
7488 +
7489 +static int __init init(void)
7490 +{
7491 +       return init_or_fini(0);
7492 +}
7493 +
7494 +static void __exit fini(void)
7495 +{
7496 +       init_or_fini(1);
7497 +}
7498 +
7499 +module_init(init);
7500 +module_exit(fini);
7501 diff -Nur linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_fuzzy.c linux-2.6.4-rc2/net/ipv4/netfilter/ipt_fuzzy.c
7502 --- linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_fuzzy.c  1970-01-01 00:00:00.000000000 +0000
7503 +++ linux-2.6.4-rc2/net/ipv4/netfilter/ipt_fuzzy.c      2004-03-05 09:55:18.000000000 +0000
7504 @@ -0,0 +1,185 @@
7505 +/*
7506 + *  This module implements a simple TSK FLC 
7507 + * (Takagi-Sugeno-Kang Fuzzy Logic Controller) that aims
7508 + * to limit , in an adaptive and flexible way , the packet rate crossing 
7509 + * a given stream . It serves as an initial and very simple (but effective)
7510 + * example of how Fuzzy Logic techniques can be applied to defeat DoS attacks.
7511 + *  As a matter of fact , Fuzzy Logic can help us to insert any "behavior"  
7512 + * into our code in a precise , adaptive and efficient manner. 
7513 + *  The goal is very similar to that of "limit" match , but using techniques of
7514 + * Fuzzy Control , that allow us to shape the transfer functions precisely ,
7515 + * avoiding over and undershoots - and stuff like that .
7516 + *
7517 + *
7518 + * 2002-08-10  Hime Aguiar e Oliveira Jr. <hime@engineer.com> : Initial version.
7519 + * 2002-08-17  : Changed to eliminate floating point operations .
7520 + * 2002-08-23  : Coding style changes .
7521 +*/
7522 +
7523 +#include <linux/module.h>
7524 +#include <linux/skbuff.h>
7525 +#include <linux/ip.h>
7526 +#include <linux/random.h>
7527 +#include <net/tcp.h>
7528 +#include <linux/spinlock.h>
7529 +#include <linux/netfilter_ipv4/ip_tables.h>
7530 +#include <linux/netfilter_ipv4/ipt_fuzzy.h>
7531 +
7532 +/*
7533 + Packet Acceptance Rate - LOW and Packet Acceptance Rate - HIGH
7534 + Expressed in percentage
7535 +*/
7536 +
7537 +#define PAR_LOW                1/100
7538 +#define PAR_HIGH       1
7539 +
7540 +static spinlock_t fuzzy_lock = SPIN_LOCK_UNLOCKED ;
7541 +
7542 +MODULE_AUTHOR("Hime Aguiar e Oliveira Junior <hime@engineer.com>");
7543 +MODULE_DESCRIPTION("IP tables Fuzzy Logic Controller match module");
7544 +MODULE_LICENSE("GPL");
7545 +
7546 +static  u_int8_t mf_high(u_int32_t tx,u_int32_t mini,u_int32_t maxi)
7547 +{
7548 +       if (tx >= maxi)
7549 +               return 100;
7550 +
7551 +       if (tx <= mini)
7552 +               return 0;
7553 +
7554 +       return ( (100*(tx-mini)) / (maxi-mini) );
7555 +}
7556 +
7557 +static u_int8_t mf_low(u_int32_t tx,u_int32_t mini,u_int32_t maxi)
7558 +{
7559 +       if (tx <= mini)
7560 +               return 100;
7561 +
7562 +       if (tx >= maxi)
7563 +               return 0;
7564 +
7565 +       return ( (100*( maxi - tx ))  / ( maxi - mini ) );
7566 +}
7567 +
7568 +static int
7569 +ipt_fuzzy_match(const struct sk_buff *pskb,
7570 +              const struct net_device *in,
7571 +              const struct net_device *out,
7572 +              const void *matchinfo,
7573 +              int offset,
7574 +              int *hotdrop)
7575 +{
7576 +       /* From userspace */
7577 +       
7578 +       struct ipt_fuzzy_info *info = (struct ipt_fuzzy_info *) matchinfo;
7579 +
7580 +       u_int8_t random_number;
7581 +       unsigned long amount;
7582 +       u_int8_t howhigh, howlow;
7583 +       
7584 +
7585 +       spin_lock_bh(&fuzzy_lock); /* Rise the lock */
7586 +
7587 +       info->bytes_total += pskb->len;
7588 +       info->packets_total++;
7589 +
7590 +       info->present_time = jiffies;
7591 +       
7592 +       if (info->present_time >= info->previous_time)
7593 +               amount = info->present_time - info->previous_time;
7594 +       else { 
7595 +               /* There was a transition : I choose to re-sample 
7596 +                  and keep the old acceptance rate...
7597 +               */
7598 +
7599 +               amount = 0;
7600 +               info->previous_time = info->present_time;
7601 +               info->bytes_total = info->packets_total = 0;
7602 +       };
7603 +       
7604 +       if (amount > HZ/10) /* More than 100 ms elapsed ... */
7605 +       {
7606 +
7607 +               info->mean_rate = (u_int32_t) ((HZ*info->packets_total)  \
7608 +                                       / amount );
7609 +
7610 +               info->previous_time = info->present_time;
7611 +               info->bytes_total = info->packets_total = 0;
7612 +
7613 +               howhigh = mf_high(info->mean_rate,info->minimum_rate,info->maximum_rate);
7614 +               howlow  = mf_low(info->mean_rate,info->minimum_rate,info->maximum_rate);
7615 +
7616 +               info->acceptance_rate = (u_int8_t) \
7617 +                          (howhigh*PAR_LOW + PAR_HIGH*howlow);
7618 +
7619 +               /* In fact , the above defuzzification would require a denominator
7620 +                  proportional to (howhigh+howlow) but , in this particular case ,
7621 +                  that expression is constant .
7622 +                  An imediate consequence is that it isn't necessary to call 
7623 +                  both mf_high and mf_low - but to keep things understandable ,
7624 +                  I did so .  */ 
7625 +
7626 +       }
7627 +       
7628 +       spin_unlock_bh(&fuzzy_lock); /* Release the lock */
7629 +
7630 +
7631 +       if ( info->acceptance_rate < 100 )
7632 +       {                
7633 +               get_random_bytes((void *)(&random_number), 1);
7634 +
7635 +               /*  If within the acceptance , it can pass => don't match */
7636 +               if (random_number <= (255 * info->acceptance_rate) / 100)
7637 +                       return 0;
7638 +               else
7639 +                       return 1; /* It can't pass ( It matches ) */
7640 +       } ;
7641 +
7642 +       return 0; /* acceptance_rate == 100 % => Everything passes ... */
7643 +       
7644 +}
7645 +
7646 +static int
7647 +ipt_fuzzy_checkentry(const char *tablename,
7648 +                  const struct ipt_ip *e,
7649 +                  void *matchinfo,
7650 +                  unsigned int matchsize,
7651 +                  unsigned int hook_mask)
7652 +{
7653 +       
7654 +       const struct ipt_fuzzy_info *info = matchinfo;
7655 +
7656 +       if (matchsize != IPT_ALIGN(sizeof(struct ipt_fuzzy_info))) {
7657 +               printk("ipt_fuzzy: matchsize %u != %u\n", matchsize,
7658 +                      IPT_ALIGN(sizeof(struct ipt_fuzzy_info)));
7659 +               return 0;
7660 +       }
7661 +
7662 +       if ((info->minimum_rate < MINFUZZYRATE ) || (info->maximum_rate > MAXFUZZYRATE)
7663 +           || (info->minimum_rate >= info->maximum_rate )) {
7664 +               printk("ipt_fuzzy: BAD limits , please verify !!!\n");
7665 +               return 0;
7666 +       }
7667 +
7668 +       return 1;
7669 +}
7670 +
7671 +static struct ipt_match ipt_fuzzy_reg = { 
7672 +       .name = "fuzzy",
7673 +       .match = ipt_fuzzy_match,
7674 +       .checkentry = ipt_fuzzy_checkentry,
7675 +       .me = THIS_MODULE
7676 +};
7677 +
7678 +static int __init init(void)
7679 +{
7680 +       return ipt_register_match(&ipt_fuzzy_reg);
7681 +}
7682 +
7683 +static void __exit fini(void)
7684 +{
7685 +       ipt_unregister_match(&ipt_fuzzy_reg);
7686 +}
7687 +
7688 +module_init(init);
7689 +module_exit(fini);
7690 diff -Nur linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_ipv4options.c linux-2.6.4-rc2/net/ipv4/netfilter/ipt_ipv4options.c
7691 --- linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_ipv4options.c    1970-01-01 00:00:00.000000000 +0000
7692 +++ linux-2.6.4-rc2/net/ipv4/netfilter/ipt_ipv4options.c        2004-03-05 09:55:19.000000000 +0000
7693 @@ -0,0 +1,172 @@
7694 +/*
7695 +  This is a module which is used to match ipv4 options.
7696 +  This file is distributed under the terms of the GNU General Public
7697 +  License (GPL). Copies of the GPL can be obtained from:
7698 +  ftp://prep.ai.mit.edu/pub/gnu/GPL
7699 +
7700 +  11-mars-2001 Fabrice MARIE <fabrice@netfilter.org> : initial development.
7701 +  12-july-2001 Fabrice MARIE <fabrice@netfilter.org> : added router-alert otions matching. Fixed a bug with no-srr
7702 +  12-august-2001 Imran Patel <ipatel@crosswinds.net> : optimization of the match.
7703 +  18-november-2001 Fabrice MARIE <fabrice@netfilter.org> : added [!] 'any' option match.
7704 +  19-february-2004 Harald Welte <laforge@netfilter.org> : merge with 2.6.x
7705 +*/
7706 +
7707 +#include <linux/module.h>
7708 +#include <linux/skbuff.h>
7709 +#include <net/ip.h>
7710 +
7711 +#include <linux/netfilter_ipv4/ip_tables.h>
7712 +#include <linux/netfilter_ipv4/ipt_ipv4options.h>
7713 +
7714 +MODULE_LICENSE("GPL");
7715 +MODULE_AUTHOR("Fabrice Marie <fabrice@netfilter.org>");
7716 +
7717 +static int
7718 +match(const struct sk_buff *skb,
7719 +      const struct net_device *in,
7720 +      const struct net_device *out,
7721 +      const void *matchinfo,
7722 +      int offset,
7723 +      int *hotdrop)
7724 +{
7725 +       const struct ipt_ipv4options_info *info = matchinfo;   /* match info for rule */
7726 +       const struct iphdr *iph = skb->nh.iph;
7727 +       const struct ip_options *opt;
7728 +
7729 +       if (iph->ihl * 4 == sizeof(struct iphdr)) {
7730 +               /* No options, so we match only the "DONTs" and the "IGNOREs" */
7731 +
7732 +               if (((info->options & IPT_IPV4OPTION_MATCH_ANY_OPT) == IPT_IPV4OPTION_MATCH_ANY_OPT) ||
7733 +                   ((info->options & IPT_IPV4OPTION_MATCH_SSRR) == IPT_IPV4OPTION_MATCH_SSRR) ||
7734 +                   ((info->options & IPT_IPV4OPTION_MATCH_LSRR) == IPT_IPV4OPTION_MATCH_LSRR) ||
7735 +                   ((info->options & IPT_IPV4OPTION_MATCH_RR) == IPT_IPV4OPTION_MATCH_RR) ||
7736 +                   ((info->options & IPT_IPV4OPTION_MATCH_TIMESTAMP) == IPT_IPV4OPTION_MATCH_TIMESTAMP) ||
7737 +                    ((info->options & IPT_IPV4OPTION_MATCH_ROUTER_ALERT) == IPT_IPV4OPTION_MATCH_ROUTER_ALERT))
7738 +                       return 0;
7739 +               return 1;
7740 +       }
7741 +       else {
7742 +               if ((info->options & IPT_IPV4OPTION_MATCH_ANY_OPT) == IPT_IPV4OPTION_MATCH_ANY_OPT)
7743 +                       /* there are options, and we don't need to care which one */
7744 +                       return 1;
7745 +               else {
7746 +                       if ((info->options & IPT_IPV4OPTION_DONT_MATCH_ANY_OPT) == IPT_IPV4OPTION_DONT_MATCH_ANY_OPT)
7747 +                               /* there are options but we don't want any ! */
7748 +                               return 0;
7749 +               }
7750 +       }
7751 +
7752 +       opt = &(IPCB(skb)->opt);
7753 +
7754 +       /* source routing */
7755 +       if ((info->options & IPT_IPV4OPTION_MATCH_SSRR) == IPT_IPV4OPTION_MATCH_SSRR) {
7756 +               if (!((opt->srr) & (opt->is_strictroute)))
7757 +                       return 0;
7758 +       }
7759 +       else if ((info->options & IPT_IPV4OPTION_MATCH_LSRR) == IPT_IPV4OPTION_MATCH_LSRR) {
7760 +               if (!((opt->srr) & (!opt->is_strictroute)))
7761 +                       return 0;
7762 +       }
7763 +       else if ((info->options & IPT_IPV4OPTION_DONT_MATCH_SRR) == IPT_IPV4OPTION_DONT_MATCH_SRR) {
7764 +               if (opt->srr)
7765 +                       return 0;
7766 +       }
7767 +       /* record route */
7768 +       if ((info->options & IPT_IPV4OPTION_MATCH_RR) == IPT_IPV4OPTION_MATCH_RR) {
7769 +               if (!opt->rr)
7770 +                       return 0;
7771 +       }
7772 +       else if ((info->options & IPT_IPV4OPTION_DONT_MATCH_RR) == IPT_IPV4OPTION_DONT_MATCH_RR) {
7773 +               if (opt->rr)
7774 +                       return 0;
7775 +       }
7776 +       /* timestamp */
7777 +       if ((info->options & IPT_IPV4OPTION_MATCH_TIMESTAMP) == IPT_IPV4OPTION_MATCH_TIMESTAMP) {
7778 +               if (!opt->ts)
7779 +                       return 0;
7780 +       }
7781 +       else if ((info->options & IPT_IPV4OPTION_DONT_MATCH_TIMESTAMP) == IPT_IPV4OPTION_DONT_MATCH_TIMESTAMP) {
7782 +               if (opt->ts)
7783 +                       return 0;
7784 +       }
7785 +       /* router-alert option  */
7786 +       if ((info->options & IPT_IPV4OPTION_MATCH_ROUTER_ALERT) == IPT_IPV4OPTION_MATCH_ROUTER_ALERT) {
7787 +               if (!opt->router_alert)
7788 +                       return 0;
7789 +       }
7790 +       else if ((info->options & IPT_IPV4OPTION_DONT_MATCH_ROUTER_ALERT) == IPT_IPV4OPTION_DONT_MATCH_ROUTER_ALERT) {
7791 +               if (opt->router_alert)
7792 +                       return 0;
7793 +       }
7794 +
7795 +       /* we match ! */
7796 +       return 1;
7797 +}
7798 +
7799 +static int
7800 +checkentry(const char *tablename,
7801 +          const struct ipt_ip *ip,
7802 +          void *matchinfo,
7803 +          unsigned int matchsize,
7804 +          unsigned int hook_mask)
7805 +{
7806 +       const struct ipt_ipv4options_info *info = matchinfo;   /* match info for rule */
7807 +       /* Check the size */
7808 +       if (matchsize != IPT_ALIGN(sizeof(struct ipt_ipv4options_info)))
7809 +               return 0;
7810 +       /* Now check the coherence of the data ... */
7811 +       if (((info->options & IPT_IPV4OPTION_MATCH_ANY_OPT) == IPT_IPV4OPTION_MATCH_ANY_OPT) &&
7812 +           (((info->options & IPT_IPV4OPTION_DONT_MATCH_SRR) == IPT_IPV4OPTION_DONT_MATCH_SRR) ||
7813 +            ((info->options & IPT_IPV4OPTION_DONT_MATCH_RR) == IPT_IPV4OPTION_DONT_MATCH_RR) ||
7814 +            ((info->options & IPT_IPV4OPTION_DONT_MATCH_TIMESTAMP) == IPT_IPV4OPTION_DONT_MATCH_TIMESTAMP) ||
7815 +            ((info->options & IPT_IPV4OPTION_DONT_MATCH_ROUTER_ALERT) == IPT_IPV4OPTION_DONT_MATCH_ROUTER_ALERT) ||
7816 +            ((info->options & IPT_IPV4OPTION_DONT_MATCH_ANY_OPT) == IPT_IPV4OPTION_DONT_MATCH_ANY_OPT)))
7817 +               return 0; /* opposites */
7818 +       if (((info->options & IPT_IPV4OPTION_DONT_MATCH_ANY_OPT) == IPT_IPV4OPTION_DONT_MATCH_ANY_OPT) &&
7819 +           (((info->options & IPT_IPV4OPTION_MATCH_LSRR) == IPT_IPV4OPTION_MATCH_LSRR) ||
7820 +            ((info->options & IPT_IPV4OPTION_MATCH_SSRR) == IPT_IPV4OPTION_MATCH_SSRR) ||
7821 +            ((info->options & IPT_IPV4OPTION_MATCH_RR) == IPT_IPV4OPTION_MATCH_RR) ||
7822 +            ((info->options & IPT_IPV4OPTION_MATCH_TIMESTAMP) == IPT_IPV4OPTION_MATCH_TIMESTAMP) ||
7823 +            ((info->options & IPT_IPV4OPTION_MATCH_ROUTER_ALERT) == IPT_IPV4OPTION_MATCH_ROUTER_ALERT) ||
7824 +            ((info->options & IPT_IPV4OPTION_MATCH_ANY_OPT) == IPT_IPV4OPTION_MATCH_ANY_OPT)))
7825 +               return 0; /* opposites */
7826 +       if (((info->options & IPT_IPV4OPTION_MATCH_SSRR) == IPT_IPV4OPTION_MATCH_SSRR) &&
7827 +           ((info->options & IPT_IPV4OPTION_MATCH_LSRR) == IPT_IPV4OPTION_MATCH_LSRR))
7828 +               return 0; /* cannot match in the same time loose and strict source routing */
7829 +       if ((((info->options & IPT_IPV4OPTION_MATCH_SSRR) == IPT_IPV4OPTION_MATCH_SSRR) ||
7830 +            ((info->options & IPT_IPV4OPTION_MATCH_LSRR) == IPT_IPV4OPTION_MATCH_LSRR)) &&
7831 +           ((info->options & IPT_IPV4OPTION_DONT_MATCH_SRR) == IPT_IPV4OPTION_DONT_MATCH_SRR))
7832 +               return 0; /* opposites */
7833 +       if (((info->options & IPT_IPV4OPTION_MATCH_RR) == IPT_IPV4OPTION_MATCH_RR) &&
7834 +           ((info->options & IPT_IPV4OPTION_DONT_MATCH_RR) == IPT_IPV4OPTION_DONT_MATCH_RR))
7835 +               return 0; /* opposites */
7836 +       if (((info->options & IPT_IPV4OPTION_MATCH_TIMESTAMP) == IPT_IPV4OPTION_MATCH_TIMESTAMP) &&
7837 +           ((info->options & IPT_IPV4OPTION_DONT_MATCH_TIMESTAMP) == IPT_IPV4OPTION_DONT_MATCH_TIMESTAMP))
7838 +               return 0; /* opposites */
7839 +       if (((info->options & IPT_IPV4OPTION_MATCH_ROUTER_ALERT) == IPT_IPV4OPTION_MATCH_ROUTER_ALERT) &&
7840 +           ((info->options & IPT_IPV4OPTION_DONT_MATCH_ROUTER_ALERT) == IPT_IPV4OPTION_DONT_MATCH_ROUTER_ALERT))
7841 +               return 0; /* opposites */
7842 +
7843 +       /* everything looks ok. */
7844 +       return 1;
7845 +}
7846 +
7847 +static struct ipt_match ipv4options_match = { 
7848 +       .name = "ipv4options",
7849 +       .match = match,
7850 +       .checkentry = checkentry,
7851 +       .me = THIS_MODULE
7852 +};
7853 +
7854 +static int __init init(void)
7855 +{
7856 +       return ipt_register_match(&ipv4options_match);
7857 +}
7858 +
7859 +static void __exit fini(void)
7860 +{
7861 +       ipt_unregister_match(&ipv4options_match);
7862 +}
7863 +
7864 +module_init(init);
7865 +module_exit(fini);
7866 diff -Nur linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_mport.c linux-2.6.4-rc2/net/ipv4/netfilter/ipt_mport.c
7867 --- linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_mport.c  1970-01-01 00:00:00.000000000 +0000
7868 +++ linux-2.6.4-rc2/net/ipv4/netfilter/ipt_mport.c      2004-03-05 09:55:20.000000000 +0000
7869 @@ -0,0 +1,116 @@
7870 +/* Kernel module to match one of a list of TCP/UDP ports: ports are in
7871 +   the same place so we can treat them as equal. */
7872 +#include <linux/module.h>
7873 +#include <linux/types.h>
7874 +#include <linux/udp.h>
7875 +#include <linux/skbuff.h>
7876 +
7877 +#include <linux/netfilter_ipv4/ipt_mport.h>
7878 +#include <linux/netfilter_ipv4/ip_tables.h>
7879 +
7880 +MODULE_LICENSE("GPL");
7881 +
7882 +#if 0
7883 +#define duprintf(format, args...) printk(format , ## args)
7884 +#else
7885 +#define duprintf(format, args...)
7886 +#endif
7887 +
7888 +/* Returns 1 if the port is matched by the test, 0 otherwise. */
7889 +static inline int
7890 +ports_match(const struct ipt_mport *minfo, u_int16_t src, u_int16_t dst)
7891 +{
7892 +       unsigned int i;
7893 +        unsigned int m;
7894 +        u_int16_t pflags = minfo->pflags;
7895 +       for (i=0, m=1; i<IPT_MULTI_PORTS; i++, m<<=1) {
7896 +                u_int16_t s, e;
7897 +
7898 +                if (pflags & m
7899 +                    && minfo->ports[i] == 65535)
7900 +                        return 0;
7901 +
7902 +                s = minfo->ports[i];
7903 +
7904 +                if (pflags & m) {
7905 +                        e = minfo->ports[++i];
7906 +                        m <<= 1;
7907 +                } else
7908 +                        e = s;
7909 +
7910 +                if (minfo->flags & IPT_MPORT_SOURCE
7911 +                    && src >= s && src <= e)
7912 +                        return 1;
7913 +
7914 +               if (minfo->flags & IPT_MPORT_DESTINATION
7915 +                   && dst >= s && dst <= e)
7916 +                       return 1;
7917 +       }
7918 +
7919 +       return 0;
7920 +}
7921 +
7922 +static int
7923 +match(const struct sk_buff *skb,
7924 +      const struct net_device *in,
7925 +      const struct net_device *out,
7926 +      const void *matchinfo,
7927 +      int offset,
7928 +      int *hotdrop)
7929 +{
7930 +       u16 ports[2];
7931 +       const struct ipt_mport *minfo = matchinfo;
7932 +
7933 +       if (offset)
7934 +               return 0;
7935 +
7936 +       /* Must be big enough to read ports (both UDP and TCP have
7937 +           them at the start). */
7938 +       if (skb_copy_bits(skb, skb->nh.iph->ihl*4, ports, sizeof(ports)) < 0) {
7939 +               /* We've been asked to examine this packet, and we
7940 +                  can't.  Hence, no choice but to drop. */
7941 +                       duprintf("ipt_multiport:"
7942 +                                " Dropping evil offset=0 tinygram.\n");
7943 +                       *hotdrop = 1;
7944 +                       return 0;
7945 +       }
7946 +
7947 +       return ports_match(minfo, ntohs(ports[0]), ntohs(ports[1]));
7948 +}
7949 +
7950 +/* Called when user tries to insert an entry of this type. */
7951 +static int
7952 +checkentry(const char *tablename,
7953 +          const struct ipt_ip *ip,
7954 +          void *matchinfo,
7955 +          unsigned int matchsize,
7956 +          unsigned int hook_mask)
7957 +{
7958 +       if (matchsize != IPT_ALIGN(sizeof(struct ipt_mport)))
7959 +               return 0;
7960 +
7961 +       /* Must specify proto == TCP/UDP, no unknown flags or bad count */
7962 +       return (ip->proto == IPPROTO_TCP || ip->proto == IPPROTO_UDP)
7963 +               && !(ip->invflags & IPT_INV_PROTO)
7964 +               && matchsize == IPT_ALIGN(sizeof(struct ipt_mport));
7965 +}
7966 +
7967 +static struct ipt_match mport_match = { 
7968 +       .name = "mport",
7969 +       .match = &match,
7970 +       .checkentry = &checkentry,
7971 +       .me = THIS_MODULE
7972 +};
7973 +
7974 +static int __init init(void)
7975 +{
7976 +       return ipt_register_match(&mport_match);
7977 +}
7978 +
7979 +static void __exit fini(void)
7980 +{
7981 +       ipt_unregister_match(&mport_match);
7982 +}
7983 +
7984 +module_init(init);
7985 +module_exit(fini);
7986 diff -Nur linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_nth.c linux-2.6.4-rc2/net/ipv4/netfilter/ipt_nth.c
7987 --- linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_nth.c    1970-01-01 00:00:00.000000000 +0000
7988 +++ linux-2.6.4-rc2/net/ipv4/netfilter/ipt_nth.c        2004-03-05 09:55:21.000000000 +0000
7989 @@ -0,0 +1,166 @@
7990 +/*
7991 +  This is a module which is used for match support for every Nth packet
7992 +  This file is distributed under the terms of the GNU General Public
7993 +  License (GPL). Copies of the GPL can be obtained from:
7994 +     ftp://prep.ai.mit.edu/pub/gnu/GPL
7995 +
7996 +  2001-07-18 Fabrice MARIE <fabrice@netfilter.org> : initial implementation.
7997 +  2001-09-20 Richard Wagner (rwagner@cloudnet.com)
7998 +        * added support for multiple counters
7999 +        * added support for matching on individual packets
8000 +          in the counter cycle
8001 +  2004-02-19 Harald Welte <laforge@netfilter.org>
8002 +       * port to 2.6.x
8003 +
8004 +*/
8005 +
8006 +#include <linux/module.h>
8007 +#include <linux/skbuff.h>
8008 +#include <linux/ip.h>
8009 +#include <net/tcp.h>
8010 +#include <linux/spinlock.h>
8011 +#include <linux/netfilter_ipv4/ip_tables.h>
8012 +#include <linux/netfilter_ipv4/ipt_nth.h>
8013 +
8014 +MODULE_LICENSE("GPL");
8015 +MODULE_AUTHOR("Fabrice Marie <fabrice@netfilter.org>");
8016 +
8017 +/*
8018 + * State information.
8019 + */
8020 +struct state {
8021 +       spinlock_t lock;
8022 +       u_int16_t number;
8023 +};
8024 +
8025 +static struct state states[IPT_NTH_NUM_COUNTERS];
8026 +
8027 +static int
8028 +ipt_nth_match(const struct sk_buff *pskb,
8029 +             const struct net_device *in,
8030 +             const struct net_device *out,
8031 +             const void *matchinfo,
8032 +             int offset,
8033 +             int *hotdrop)
8034 +{
8035 +       /* Parameters from userspace */
8036 +       const struct ipt_nth_info *info = matchinfo;
8037 +        unsigned counter = info->counter;
8038 +               if((counter < 0) || (counter >= IPT_NTH_NUM_COUNTERS)) 
8039 +       {
8040 +                       printk(KERN_WARNING "nth: invalid counter %u. counter between 0 and %u\n", counter, IPT_NTH_NUM_COUNTERS-1);
8041 +               return 0;
8042 +        };
8043 +
8044 +        spin_lock(&states[counter].lock);
8045 +
8046 +        /* Are we matching every nth packet?*/
8047 +        if (info->packet == 0xFF)
8048 +        {
8049 +               /* We're matching every nth packet and only every nth packet*/
8050 +               /* Do we match or invert match? */
8051 +               if (info->not == 0)
8052 +               {
8053 +                       if (states[counter].number == 0)
8054 +                       {
8055 +                               ++states[counter].number;
8056 +                               goto match;
8057 +                       }
8058 +                       if (states[counter].number >= info->every)
8059 +                               states[counter].number = 0; /* reset the counter */
8060 +                       else
8061 +                               ++states[counter].number;
8062 +                       goto dontmatch;
8063 +               }
8064 +               else
8065 +               {
8066 +                       if (states[counter].number == 0)
8067 +                       {
8068 +                               ++states[counter].number;
8069 +                               goto dontmatch;
8070 +                       }
8071 +                       if (states[counter].number >= info->every)
8072 +                               states[counter].number = 0;
8073 +                       else
8074 +                               ++states[counter].number;
8075 +                       goto match;
8076 +               }
8077 +        }
8078 +        else
8079 +        {
8080 +               /* We're using the --packet, so there must be a rule for every value */
8081 +               if (states[counter].number == info->packet)
8082 +               {
8083 +                       /* only increment the counter when a match happens */
8084 +                       if (states[counter].number >= info->every)
8085 +                               states[counter].number = 0; /* reset the counter */
8086 +                       else
8087 +                               ++states[counter].number;
8088 +                       goto match;
8089 +               }
8090 +               else
8091 +                       goto dontmatch;
8092 +       }
8093 +
8094 + dontmatch:
8095 +       /* don't match */
8096 +       spin_unlock(&states[counter].lock);
8097 +       return 0;
8098 +
8099 + match:
8100 +       spin_unlock(&states[counter].lock);
8101 +       return 1;
8102 +}
8103 +
8104 +static int
8105 +ipt_nth_checkentry(const char *tablename,
8106 +                  const struct ipt_ip *e,
8107 +                  void *matchinfo,
8108 +                  unsigned int matchsize,
8109 +                  unsigned int hook_mask)
8110 +{
8111 +       /* Parameters from userspace */
8112 +       const struct ipt_nth_info *info = matchinfo;
8113 +        unsigned counter = info->counter;
8114 +        if((counter < 0) || (counter >= IPT_NTH_NUM_COUNTERS)) 
8115 +       {
8116 +               printk(KERN_WARNING "nth: invalid counter %u. counter between 0 and %u\n", counter, IPT_NTH_NUM_COUNTERS-1);
8117 +                       return 0;
8118 +               };
8119 +
8120 +       if (matchsize != IPT_ALIGN(sizeof(struct ipt_nth_info))) {
8121 +               printk("nth: matchsize %u != %u\n", matchsize,
8122 +                      IPT_ALIGN(sizeof(struct ipt_nth_info)));
8123 +               return 0;
8124 +       }
8125 +
8126 +       states[counter].number = info->startat;
8127 +
8128 +       return 1;
8129 +}
8130 +
8131 +static struct ipt_match ipt_nth_reg = { 
8132 +       .name = "nth",
8133 +       .match = ipt_nth_match,
8134 +       .checkentry = ipt_nth_checkentry,
8135 +       .me = THIS_MODULE
8136 +};
8137 +
8138 +static int __init init(void)
8139 +{
8140 +       unsigned counter;
8141 +
8142 +       memset(&states, 0, sizeof(states));
8143 +        for (counter = 0; counter < IPT_NTH_NUM_COUNTERS; counter++) 
8144 +               spin_lock_init(&(states[counter].lock));
8145 +
8146 +       return ipt_register_match(&ipt_nth_reg);
8147 +}
8148 +
8149 +static void __exit fini(void)
8150 +{
8151 +       ipt_unregister_match(&ipt_nth_reg);
8152 +}
8153 +
8154 +module_init(init);
8155 +module_exit(fini);
8156 diff -Nur linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_quota.c linux-2.6.4-rc2/net/ipv4/netfilter/ipt_quota.c
8157 --- linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_quota.c  1970-01-01 00:00:00.000000000 +0000
8158 +++ linux-2.6.4-rc2/net/ipv4/netfilter/ipt_quota.c      2004-03-05 09:55:22.000000000 +0000
8159 @@ -0,0 +1,91 @@
8160 +/* 
8161 + * netfilter module to enforce network quotas
8162 + *
8163 + * Sam Johnston <samj@samj.net>
8164 + */
8165 +#include <linux/module.h>
8166 +#include <linux/skbuff.h>
8167 +#include <linux/spinlock.h>
8168 +#include <linux/interrupt.h>
8169 +
8170 +#include <linux/netfilter_ipv4/ip_tables.h>
8171 +#include <linux/netfilter_ipv4/ipt_quota.h>
8172 +
8173 +MODULE_LICENSE("GPL");
8174 +MODULE_AUTHOR("Sam Johnston <samj@samj.net>");
8175 +
8176 +static spinlock_t quota_lock = SPIN_LOCK_UNLOCKED;
8177 +
8178 +static int
8179 +match(const struct sk_buff *skb,
8180 +      const struct net_device *in,
8181 +      const struct net_device *out,
8182 +      const void *matchinfo,
8183 +      int offset, int *hotdrop)
8184 +{
8185 +        struct ipt_quota_info *q = (struct ipt_quota_info *) matchinfo;
8186 +       unsigned int datalen;
8187 +
8188 +       if (skb->len < sizeof(struct iphdr))
8189 +               return NF_ACCEPT;
8190 +       
8191 +       datalen = skb->len - skb->nh.iph->ihl*4;
8192 +
8193 +        spin_lock_bh(&quota_lock);
8194 +
8195 +        if (q->quota >= datalen) {
8196 +                /* we can afford this one */
8197 +                q->quota -= datalen;
8198 +                spin_unlock_bh(&quota_lock);
8199 +
8200 +#ifdef DEBUG_IPT_QUOTA
8201 +                printk("IPT Quota OK: %llu datlen %d \n", q->quota, datalen);
8202 +#endif
8203 +                return 1;
8204 +        }
8205 +
8206 +        /* so we do not allow even small packets from now on */
8207 +        q->quota = 0;
8208 +
8209 +#ifdef DEBUG_IPT_QUOTA
8210 +        printk("IPT Quota Failed: %llu datlen %d \n", q->quota, datalen);
8211 +#endif
8212 +
8213 +        spin_unlock_bh(&quota_lock);
8214 +        return 0;
8215 +}
8216 +
8217 +static int
8218 +checkentry(const char *tablename,
8219 +           const struct ipt_ip *ip,
8220 +           void *matchinfo, unsigned int matchsize, unsigned int hook_mask)
8221 +{
8222 +        /* TODO: spinlocks? sanity checks? */
8223 +        if (matchsize != IPT_ALIGN(sizeof (struct ipt_quota_info)))
8224 +                return 0;
8225 +
8226 +        return 1;
8227 +}
8228 +
8229 +static struct ipt_match quota_match = {
8230 +       .name = "quota",
8231 +       .match = match,
8232 +       .checkentry = checkentry,
8233 +       .me = THIS_MODULE
8234 +};
8235 +
8236 +static int __init
8237 +init(void)
8238 +{
8239 +        return ipt_register_match(&quota_match);
8240 +}
8241 +
8242 +static void __exit
8243 +fini(void)
8244 +{
8245 +        ipt_unregister_match(&quota_match);
8246 +}
8247 +
8248 +module_init(init);
8249 +module_exit(fini);
8250 +
8251 diff -Nur linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_realm.c linux-2.6.4-rc2/net/ipv4/netfilter/ipt_realm.c
8252 --- linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_realm.c  1970-01-01 00:00:00.000000000 +0000
8253 +++ linux-2.6.4-rc2/net/ipv4/netfilter/ipt_realm.c      2004-03-05 09:55:23.000000000 +0000
8254 @@ -0,0 +1,70 @@
8255 +/* Kernel module to match realm from routing. */
8256 +#include <linux/module.h>
8257 +#include <linux/skbuff.h>
8258 +#include <linux/netdevice.h>
8259 +#include <net/route.h>
8260 +
8261 +#include <linux/netfilter_ipv4/ipt_realm.h>
8262 +#include <linux/netfilter_ipv4/ip_tables.h>
8263 +
8264 +MODULE_AUTHOR("Sampsa Ranta <sampsa@netsonic.fi>");
8265 +MODULE_LICENSE("GPL");
8266 +
8267 +static int
8268 +match(const struct sk_buff *skb,
8269 +      const struct net_device *in,
8270 +      const struct net_device *out,
8271 +      const void *matchinfo,
8272 +      int offset,
8273 +      int *hotdrop)
8274 +{
8275 +       const struct ipt_realm_info *info = matchinfo;
8276 +       struct dst_entry *dst = skb->dst;
8277 +       u32 id;
8278 +    
8279 +       if(dst == NULL)
8280 +               return 0;
8281 +       id = dst->tclassid;
8282 +
8283 +       return (info->id == (id & info->mask)) ^ info->invert;
8284 +}
8285 +
8286 +static int check(const char *tablename,
8287 +                 const struct ipt_ip *ip,
8288 +                 void *matchinfo,
8289 +                 unsigned int matchsize,
8290 +                 unsigned int hook_mask)
8291 +{
8292 +       if (hook_mask
8293 +           & ~((1 << NF_IP_POST_ROUTING) | (1 << NF_IP_FORWARD) |
8294 +               (1 << NF_IP_LOCAL_OUT)| (1 << NF_IP_LOCAL_IN))) {
8295 +               printk("ipt_realm: only valid for POST_ROUTING, LOCAL_OUT, "
8296 +                      "LOCAL_IN or FORWARD.\n");
8297 +               return 0;
8298 +       }
8299 +
8300 +       if (matchsize != IPT_ALIGN(sizeof(struct ipt_realm_info)))
8301 +               return 0;
8302 +
8303 +       return 1;
8304 +}
8305 +
8306 +static struct ipt_match realm_match = {
8307 +       .name = "realm",
8308 +       .match = match, 
8309 +       .checkentry = check,
8310 +       .me = THIS_MODULE
8311 +};
8312 +
8313 +static int __init init(void)
8314 +{
8315 +       return ipt_register_match(&realm_match);
8316 +}
8317 +
8318 +static void __exit fini(void)
8319 +{
8320 +       ipt_unregister_match(&realm_match);
8321 +}
8322 +
8323 +module_init(init);
8324 +module_exit(fini);
8325 diff -Nur linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_sctp.c linux-2.6.4-rc2/net/ipv4/netfilter/ipt_sctp.c
8326 --- linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_sctp.c   1970-01-01 00:00:00.000000000 +0000
8327 +++ linux-2.6.4-rc2/net/ipv4/netfilter/ipt_sctp.c       2004-03-05 09:55:25.000000000 +0000
8328 @@ -0,0 +1,197 @@
8329 +#include <linux/module.h>
8330 +#include <linux/skbuff.h>
8331 +#include <net/ip.h>
8332 +#include <linux/sctp.h>
8333 +
8334 +#include <linux/netfilter_ipv4/ip_tables.h>
8335 +#include <linux/netfilter_ipv4/ipt_sctp.h>
8336 +
8337 +#if 1
8338 +#define duprintf(format, args...) printk(format , ## args)
8339 +#else
8340 +#define duprintf(format, args...)
8341 +#endif
8342 +
8343 +#define SCCHECK(cond, option, flag, invflag) (!((flag) & (option)) \
8344 +                                             || (!!((invflag) & (option)) ^ (cond)))
8345 +
8346 +static int
8347 +match_flags(const struct ipt_sctp_flag_info *flag_info,
8348 +           const int flag_count,
8349 +           u_int8_t chunktype,
8350 +           u_int8_t chunkflags)
8351 +{
8352 +       int i;
8353 +
8354 +       for (i = 0; i < flag_count; i++) {
8355 +               if (flag_info[i].chunktype == chunktype) {
8356 +                       return (chunkflags & flag_info[i].flag_mask) == flag_info[i].flag;
8357 +               }
8358 +       }
8359 +
8360 +       return 1;
8361 +}
8362 +
8363 +static int
8364 +match_packet(const struct sk_buff *skb,
8365 +            const u_int32_t *chunkmap,
8366 +            int chunk_match_type,
8367 +            const struct ipt_sctp_flag_info *flag_info,
8368 +            const int flag_count,
8369 +            int *hotdrop)
8370 +{
8371 +       int offset;
8372 +       u_int32_t chunkmapcopy[256 / sizeof (u_int32_t)];
8373 +       sctp_chunkhdr_t sch;
8374 +
8375 +       if (chunk_match_type == SCTP_CHUNK_MATCH_ALL) {
8376 +               SCTP_CHUNKMAP_COPY(chunkmapcopy, chunkmap);
8377 +       }
8378 +
8379 +       offset = skb->nh.iph->ihl * 4 + sizeof (sctp_sctphdr_t);
8380 +       do {
8381 +               if (skb_copy_bits(skb, offset, &sch, sizeof(sch)) < 0) {
8382 +                       duprintf("Dropping invalid SCTP packet.\n");
8383 +                       *hotdrop = 1;
8384 +                       return 0;
8385 +               }
8386 +
8387 +//             duprintf("Chunk num: %d\toffset: %d\ttype: %d\tlength: %d\tflags: %x\n", 
8388 +//                             ++i, offset, sch.type, htons(sch.length), sch.flags);
8389 +
8390 +               offset += (htons(sch.length) + 3) & ~3;
8391 +
8392 +               duprintf("skb->len: %d\toffset: %d\n", skb->len, offset);
8393 +
8394 +               if (SCTP_CHUNKMAP_IS_SET(chunkmap, sch.type)) {
8395 +                       switch (chunk_match_type) {
8396 +                       case SCTP_CHUNK_MATCH_ANY:
8397 +                               if (match_flags(flag_info, flag_count, 
8398 +                                       sch.type, sch.flags)) {
8399 +                                       return 1;
8400 +                               }
8401 +                               break;
8402 +
8403 +                       case SCTP_CHUNK_MATCH_ALL:
8404 +                               if (match_flags(flag_info, flag_count, 
8405 +                                       sch.type, sch.flags)) {
8406 +                                       SCTP_CHUNKMAP_CLEAR(chunkmapcopy, sch.type);
8407 +                               }
8408 +                               break;
8409 +
8410 +                       case SCTP_CHUNK_MATCH_ONLY:
8411 +                               if (!match_flags(flag_info, flag_count, 
8412 +                                       sch.type, sch.flags)) {
8413 +                                       return 0;
8414 +                               }
8415 +                               break;
8416 +                       }
8417 +               } else {
8418 +                       switch (chunk_match_type) {
8419 +                       case SCTP_CHUNK_MATCH_ONLY:
8420 +                               return 0;
8421 +                       }
8422 +               }
8423 +       } while (offset < skb->len);
8424 +
8425 +       switch (chunk_match_type) {
8426 +       case SCTP_CHUNK_MATCH_ALL:
8427 +               return SCTP_CHUNKMAP_IS_CLEAR(chunkmap);
8428 +       case SCTP_CHUNK_MATCH_ANY:
8429 +               return 0;
8430 +       case SCTP_CHUNK_MATCH_ONLY:
8431 +               return 1;
8432 +       }
8433 +
8434 +       /* This will never be reached, but required to stop compiler whine */
8435 +       return 0;
8436 +}
8437 +
8438 +static int
8439 +match(const struct sk_buff *skb,
8440 +      const struct net_device *in,
8441 +      const struct net_device *out,
8442 +      const void *matchinfo,
8443 +      int offset,
8444 +      int *hotdrop)
8445 +{
8446 +       const struct ipt_sctp_info *info;
8447 +       sctp_sctphdr_t sh;
8448 +
8449 +       info = (const struct ipt_sctp_info *)matchinfo;
8450 +
8451 +       if (offset) {
8452 +               duprintf("Dropping non-first fragment.. FIXME\n");
8453 +               return 0;
8454 +       }
8455 +       
8456 +       if (skb_copy_bits(skb, skb->nh.iph->ihl*4, &sh, sizeof(sh)) < 0) {
8457 +               duprintf("Dropping evil TCP offset=0 tinygram.\n");
8458 +               *hotdrop = 1;
8459 +               return 0;
8460 +               }
8461 +       duprintf("spt: %d\tdpt: %d\n", ntohs(sh.source), ntohs(sh.dest));
8462 +
8463 +       return  SCCHECK(((ntohs(sh.source) >= info->spts[0]) 
8464 +                       && (ntohs(sh.source) <= info->spts[1])), 
8465 +                       IPT_SCTP_SRC_PORTS, info->flags, info->invflags)
8466 +               && SCCHECK(((ntohs(sh.dest) >= info->dpts[0]) 
8467 +                       && (ntohs(sh.dest) <= info->dpts[1])), 
8468 +                       IPT_SCTP_DEST_PORTS, info->flags, info->invflags)
8469 +               && SCCHECK(match_packet(skb, info->chunkmap, info->chunk_match_type,
8470 +                                       info->flag_info, info->flag_count, 
8471 +                                       hotdrop),
8472 +                          IPT_SCTP_CHUNK_TYPES, info->flags, info->invflags);
8473 +}
8474 +
8475 +static int
8476 +checkentry(const char *tablename,
8477 +          const struct ipt_ip *ip,
8478 +          void *matchinfo,
8479 +          unsigned int matchsize,
8480 +          unsigned int hook_mask)
8481 +{
8482 +       const struct ipt_sctp_info *info;
8483 +
8484 +       info = (const struct ipt_sctp_info *)matchinfo;
8485 +
8486 +       return ip->proto == IPPROTO_SCTP
8487 +               && !(ip->invflags & IPT_INV_PROTO)
8488 +               && matchsize == IPT_ALIGN(sizeof(struct ipt_sctp_info))
8489 +               && !(info->flags & ~IPT_SCTP_VALID_FLAGS)
8490 +               && !(info->invflags & ~IPT_SCTP_VALID_FLAGS)
8491 +               && !(info->invflags & ~info->flags)
8492 +               && ((!(info->flags & IPT_SCTP_CHUNK_TYPES)) || 
8493 +                       (info->chunk_match_type &
8494 +                               (SCTP_CHUNK_MATCH_ALL 
8495 +                               | SCTP_CHUNK_MATCH_ANY
8496 +                               | SCTP_CHUNK_MATCH_ONLY)));
8497 +}
8498 +
8499 +static struct ipt_match sctp_match = 
8500 +{ 
8501 +       .list = { NULL, NULL},
8502 +       .name = "sctp",
8503 +       .match = &match,
8504 +       .checkentry = &checkentry,
8505 +       .destroy = NULL,
8506 +       .me = THIS_MODULE
8507 +};
8508 +
8509 +static int __init init(void)
8510 +{
8511 +       return ipt_register_match(&sctp_match);
8512 +}
8513 +
8514 +static void __exit fini(void)
8515 +{
8516 +       ipt_unregister_match(&sctp_match);
8517 +}
8518 +
8519 +module_init(init);
8520 +module_exit(fini);
8521 +
8522 +MODULE_LICENSE("GPL");
8523 +MODULE_AUTHOR("Kiran Kumar Immidi");
8524 +MODULE_DESCRIPTION("Match for SCTP protocol packets");
8525 +
8526 diff -Nur linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_state.c linux-2.6.4-rc2/net/ipv4/netfilter/ipt_state.c
8527 --- linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_state.c  2004-03-04 06:17:10.000000000 +0000
8528 +++ linux-2.6.4-rc2/net/ipv4/netfilter/ipt_state.c      2004-03-05 09:55:23.000000000 +0000
8529 @@ -30,7 +30,9 @@
8530         enum ip_conntrack_info ctinfo;
8531         unsigned int statebit;
8532  
8533 -       if (!ip_conntrack_get((struct sk_buff *)skb, &ctinfo))
8534 +       if (skb->nfct == &ip_conntrack_untracked.infos[IP_CT_NEW])
8535 +               statebit = IPT_STATE_UNTRACKED;
8536 +       else if (!ip_conntrack_get((struct sk_buff *)skb, &ctinfo))
8537                 statebit = IPT_STATE_INVALID;
8538         else
8539                 statebit = IPT_STATE_BIT(ctinfo);
8540 diff -Nur linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_state.c.orig linux-2.6.4-rc2/net/ipv4/netfilter/ipt_state.c.orig
8541 --- linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_state.c.orig     1970-01-01 00:00:00.000000000 +0000
8542 +++ linux-2.6.4-rc2/net/ipv4/netfilter/ipt_state.c.orig 2004-03-04 06:17:10.000000000 +0000
8543 @@ -0,0 +1,72 @@
8544 +/* Kernel module to match connection tracking information. */
8545 +
8546 +/* (C) 1999-2001 Paul `Rusty' Russell
8547 + * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org>
8548 + *
8549 + * This program is free software; you can redistribute it and/or modify
8550 + * it under the terms of the GNU General Public License version 2 as
8551 + * published by the Free Software Foundation.
8552 + */
8553 +
8554 +#include <linux/module.h>
8555 +#include <linux/skbuff.h>
8556 +#include <linux/netfilter_ipv4/ip_conntrack.h>
8557 +#include <linux/netfilter_ipv4/ip_tables.h>
8558 +#include <linux/netfilter_ipv4/ipt_state.h>
8559 +
8560 +MODULE_LICENSE("GPL");
8561 +MODULE_AUTHOR("Rusty Russell <rusty@rustcorp.com.au>");
8562 +MODULE_DESCRIPTION("iptables connection tracking state match module");
8563 +
8564 +static int
8565 +match(const struct sk_buff *skb,
8566 +      const struct net_device *in,
8567 +      const struct net_device *out,
8568 +      const void *matchinfo,
8569 +      int offset,
8570 +      int *hotdrop)
8571 +{
8572 +       const struct ipt_state_info *sinfo = matchinfo;
8573 +       enum ip_conntrack_info ctinfo;
8574 +       unsigned int statebit;
8575 +
8576 +       if (!ip_conntrack_get((struct sk_buff *)skb, &ctinfo))
8577 +               statebit = IPT_STATE_INVALID;
8578 +       else
8579 +               statebit = IPT_STATE_BIT(ctinfo);
8580 +
8581 +       return (sinfo->statemask & statebit);
8582 +}
8583 +
8584 +static int check(const char *tablename,
8585 +                const struct ipt_ip *ip,
8586 +                void *matchinfo,
8587 +                unsigned int matchsize,
8588 +                unsigned int hook_mask)
8589 +{
8590 +       if (matchsize != IPT_ALIGN(sizeof(struct ipt_state_info)))
8591 +               return 0;
8592 +
8593 +       return 1;
8594 +}
8595 +
8596 +static struct ipt_match state_match = {
8597 +       .name           = "state",
8598 +       .match          = &match,
8599 +       .checkentry     = &check,
8600 +       .me             = THIS_MODULE,
8601 +};
8602 +
8603 +static int __init init(void)
8604 +{
8605 +       need_ip_conntrack();
8606 +       return ipt_register_match(&state_match);
8607 +}
8608 +
8609 +static void __exit fini(void)
8610 +{
8611 +       ipt_unregister_match(&state_match);
8612 +}
8613 +
8614 +module_init(init);
8615 +module_exit(fini);
8616 diff -Nur linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_u32.c linux-2.6.4-rc2/net/ipv4/netfilter/ipt_u32.c
8617 --- linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_u32.c    1970-01-01 00:00:00.000000000 +0000
8618 +++ linux-2.6.4-rc2/net/ipv4/netfilter/ipt_u32.c        2004-03-05 09:56:07.000000000 +0000
8619 @@ -0,0 +1,211 @@
8620 +/* Kernel module to match u32 packet content. */
8621 +
8622 +/* 
8623 +U32 tests whether quantities of up to 4 bytes extracted from a packet 
8624 +have specified values.  The specification of what to extract is general 
8625 +enough to find data at given offsets from tcp headers or payloads.
8626 +
8627 + --u32 tests
8628 + The argument amounts to a program in a small language described below.
8629 + tests := location = value |  tests && location = value
8630 + value := range | value , range
8631 + range := number | number : number
8632 +  a single number, n, is interpreted the same as n:n
8633 +  n:m is interpreted as the range of numbers >=n and <=m
8634 + location := number | location operator number
8635 + operator := & | << | >> | @
8636 +
8637 + The operators &, <<, >>, && mean the same as in c.  The = is really a set
8638 + membership operator and the value syntax describes a set.  The @ operator
8639 + is what allows moving to the next header and is described further below.
8640 +
8641 + *** Until I can find out how to avoid it, there are some artificial limits
8642 + on the size of the tests:
8643 + - no more than 10 ='s (and 9 &&'s) in the u32 argument
8644 + - no more than 10 ranges (and 9 commas) per value
8645 + - no more than 10 numbers (and 9 operators) per location
8646 +
8647 + To describe the meaning of location, imagine the following machine that
8648 + interprets it.  There are three registers:
8649 +  A is of type char*, initially the address of the IP header
8650 +  B and C are unsigned 32 bit integers, initially zero
8651 +
8652 +  The instructions are:
8653 +   number      B = number;
8654 +               C = (*(A+B)<<24)+(*(A+B+1)<<16)+(*(A+B+2)<<8)+*(A+B+3)
8655 +   &number     C = C&number
8656 +   <<number    C = C<<number
8657 +   >>number    C = C>>number
8658 +   @number     A = A+C; then do the instruction number
8659 +  Any access of memory outside [skb->head,skb->end] causes the match to fail.
8660 +  Otherwise the result of the computation is the final value of C.
8661 +
8662 + Whitespace is allowed but not required in the tests.
8663 + However the characters that do occur there are likely to require
8664 + shell quoting, so it's a good idea to enclose the arguments in quotes.
8665 +
8666 +Example:
8667 + match IP packets with total length >= 256
8668 + The IP header contains a total length field in bytes 2-3.
8669 + --u32 "0&0xFFFF=0x100:0xFFFF" 
8670 + read bytes 0-3
8671 + AND that with FFFF (giving bytes 2-3),
8672 + and test whether that's in the range [0x100:0xFFFF]
8673 +
8674 +Example: (more realistic, hence more complicated)
8675 + match icmp packets with icmp type 0
8676 + First test that it's an icmp packet, true iff byte 9 (protocol) = 1
8677 + --u32 "6&0xFF=1 && ...
8678 + read bytes 6-9, use & to throw away bytes 6-8 and compare the result to 1
8679 + Next test that it's not a fragment.
8680 +  (If so it might be part of such a packet but we can't always tell.)
8681 +  n.b. This test is generally needed if you want to match anything
8682 +  beyond the IP header.
8683 + The last 6 bits of byte 6 and all of byte 7 are 0 iff this is a complete
8684 + packet (not a fragment).  Alternatively, you can allow first fragments
8685 + by only testing the last 5 bits of byte 6.
8686 + ... 4&0x3FFF=0 && ...
8687 + Last test: the first byte past the IP header (the type) is 0
8688 + This is where we have to use the @syntax.  The length of the IP header
8689 + (IHL) in 32 bit words is stored in the right half of byte 0 of the
8690 + IP header itself.
8691 + ... 0>>22&0x3C@0>>24=0"
8692 + The first 0 means read bytes 0-3,
8693 + >>22 means shift that 22 bits to the right.  Shifting 24 bits would give
8694 +   the first byte, so only 22 bits is four times that plus a few more bits.
8695 + &3C then eliminates the two extra bits on the right and the first four 
8696 + bits of the first byte.
8697 + For instance, if IHL=5 then the IP header is 20 (4 x 5) bytes long.
8698 + In this case bytes 0-1 are (in binary) xxxx0101 yyzzzzzz, 
8699 + >>22 gives the 10 bit value xxxx0101yy and &3C gives 010100.
8700 + @ means to use this number as a new offset into the packet, and read
8701 + four bytes starting from there.  This is the first 4 bytes of the icmp
8702 + payload, of which byte 0 is the icmp type.  Therefore we simply shift
8703 + the value 24 to the right to throw out all but the first byte and compare
8704 + the result with 0.
8705 +
8706 +Example: 
8707 + tcp payload bytes 8-12 is any of 1, 2, 5 or 8
8708 + First we test that the packet is a tcp packet (similar to icmp).
8709 + --u32 "6&0xFF=6 && ...
8710 + Next, test that it's not a fragment (same as above).
8711 + ... 0>>22&0x3C@12>>26&0x3C@8=1,2,5,8"
8712 + 0>>22&3C as above computes the number of bytes in the IP header.
8713 + @ makes this the new offset into the packet, which is the start of the
8714 + tcp header.  The length of the tcp header (again in 32 bit words) is
8715 + the left half of byte 12 of the tcp header.  The 12>>26&3C
8716 + computes this length in bytes (similar to the IP header before).
8717 + @ makes this the new offset, which is the start of the tcp payload.
8718 + Finally 8 reads bytes 8-12 of the payload and = checks whether the
8719 + result is any of 1, 2, 5 or 8
8720 +*/
8721 +
8722 +#include <linux/module.h>
8723 +#include <linux/skbuff.h>
8724 +
8725 +#include <linux/netfilter_ipv4/ipt_u32.h>
8726 +#include <linux/netfilter_ipv4/ip_tables.h>
8727 +
8728 +/* #include <asm-i386/timex.h> for timing */
8729 +
8730 +MODULE_AUTHOR("Don Cohen <don@isis.cs3-inc.com>");
8731 +MODULE_DESCRIPTION("IP tables u32 matching module");
8732 +MODULE_LICENSE("GPL");
8733 +
8734 +static int
8735 +match(const struct sk_buff *skb,
8736 +      const struct net_device *in,
8737 +      const struct net_device *out,
8738 +      const void *matchinfo,
8739 +      int offset,
8740 +      const void *hdr,
8741 +      u_int16_t datalen,
8742 +      int *hotdrop)
8743 +{
8744 +       const struct ipt_u32 *data = matchinfo;
8745 +       int testind, i;
8746 +       unsigned char* origbase = (char*)skb->nh.iph;
8747 +       unsigned char* base = origbase;
8748 +       unsigned char* head = skb->head;
8749 +       unsigned char* end = skb->end;
8750 +       int nnums, nvals;
8751 +       u_int32_t pos, val;
8752 +       /* unsigned long long cycles1, cycles2, cycles3, cycles4;
8753 +          cycles1 = get_cycles(); */
8754 +
8755 +       for (testind=0; testind < data->ntests; testind++) {
8756 +               base = origbase; /* reset for each test */
8757 +               pos = data->tests[testind].location[0].number;
8758 +               if (base+pos+3 > end || base+pos < head) 
8759 +                       return 0;
8760 +               val = (base[pos]<<24) + (base[pos+1]<<16) +
8761 +                       (base[pos+2]<<8) + base[pos+3];
8762 +               nnums = data->tests[testind].nnums;
8763 +               for (i=1; i < nnums; i++) {
8764 +                       u_int32_t number = data->tests[testind].location[i].number;
8765 +                       switch (data->tests[testind].location[i].nextop) {
8766 +                       case IPT_U32_AND: 
8767 +                               val = val & number; 
8768 +                               break;
8769 +                       case IPT_U32_LEFTSH: 
8770 +                               val = val << number;
8771 +                               break;
8772 +                       case IPT_U32_RIGHTSH: 
8773 +                               val = val >> number; 
8774 +                               break;
8775 +                       case IPT_U32_AT:
8776 +                               base = base + val;
8777 +                               pos = number;
8778 +                               if (base+pos+3 > end || base+pos < head) 
8779 +                                       return 0;
8780 +                               val = (base[pos]<<24) + (base[pos+1]<<16) +
8781 +                                       (base[pos+2]<<8) + base[pos+3];
8782 +                               break;
8783 +                       }
8784 +               }
8785 +               nvals = data->tests[testind].nvalues;
8786 +               for (i=0; i < nvals; i++) {
8787 +                       if ((data->tests[testind].value[i].min <= val) &&
8788 +                           (val <= data->tests[testind].value[i].max)) {
8789 +                               break;
8790 +                       }
8791 +               }
8792 +               if (i >= data->tests[testind].nvalues) {
8793 +                       /* cycles2 = get_cycles(); 
8794 +                          printk("failed %d in %d cycles\n", testind, 
8795 +                                 cycles2-cycles1); */
8796 +                       return 0;
8797 +               }
8798 +       }
8799 +       /* cycles2 = get_cycles();
8800 +          printk("succeeded in %d cycles\n", cycles2-cycles1); */
8801 +       return 1;
8802 +}
8803 +
8804 +static int
8805 +checkentry(const char *tablename,
8806 +           const struct ipt_ip *ip,
8807 +           void *matchinfo,
8808 +           unsigned int matchsize,
8809 +           unsigned int hook_mask)
8810 +{
8811 +       if (matchsize != IPT_ALIGN(sizeof(struct ipt_u32)))
8812 +               return 0;
8813 +       return 1;
8814 +}
8815 +
8816 +static struct ipt_match u32_match
8817 += { { NULL, NULL }, "u32", &match, &checkentry, NULL, THIS_MODULE };
8818 +
8819 +static int __init init(void)
8820 +{
8821 +       return ipt_register_match(&u32_match);
8822 +}
8823 +
8824 +static void __exit fini(void)
8825 +{
8826 +       ipt_unregister_match(&u32_match);
8827 +}
8828 +
8829 +module_init(init);
8830 +module_exit(fini);
8831 diff -Nur linux-2.6.4-rc2.org/net/ipv4/netfilter/iptable_raw.c linux-2.6.4-rc2/net/ipv4/netfilter/iptable_raw.c
8832 --- linux-2.6.4-rc2.org/net/ipv4/netfilter/iptable_raw.c        1970-01-01 00:00:00.000000000 +0000
8833 +++ linux-2.6.4-rc2/net/ipv4/netfilter/iptable_raw.c    2004-03-05 09:55:23.000000000 +0000
8834 @@ -0,0 +1,149 @@
8835 +/* 
8836 + * 'raw' table, which is the very first hooked in at PRE_ROUTING and LOCAL_OUT .
8837 + *
8838 + * Copyright (C) 2003 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
8839 + */
8840 +#include <linux/module.h>
8841 +#include <linux/netfilter_ipv4/ip_tables.h>
8842 +
8843 +#define RAW_VALID_HOOKS ((1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_LOCAL_OUT))
8844 +
8845 +/* Standard entry. */
8846 +struct ipt_standard
8847 +{
8848 +       struct ipt_entry entry;
8849 +       struct ipt_standard_target target;
8850 +};
8851 +
8852 +struct ipt_error_target
8853 +{
8854 +       struct ipt_entry_target target;
8855 +       char errorname[IPT_FUNCTION_MAXNAMELEN];
8856 +};
8857 +
8858 +struct ipt_error
8859 +{
8860 +       struct ipt_entry entry;
8861 +       struct ipt_error_target target;
8862 +};
8863 +
8864 +static struct
8865 +{
8866 +       struct ipt_replace repl;
8867 +       struct ipt_standard entries[2];
8868 +       struct ipt_error term;
8869 +} initial_table __initdata
8870 += { { "raw", RAW_VALID_HOOKS, 3,
8871 +      sizeof(struct ipt_standard) * 2 + sizeof(struct ipt_error),
8872 +      { [NF_IP_PRE_ROUTING] 0,
8873 +       [NF_IP_LOCAL_OUT] sizeof(struct ipt_standard) },
8874 +      { [NF_IP_PRE_ROUTING] 0,
8875 +       [NF_IP_LOCAL_OUT] sizeof(struct ipt_standard) },
8876 +      0, NULL, { } },
8877 +    {
8878 +           /* PRE_ROUTING */
8879 +           { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 },
8880 +               0,
8881 +               sizeof(struct ipt_entry),
8882 +               sizeof(struct ipt_standard),
8883 +               0, { 0, 0 }, { } },
8884 +             { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } },
8885 +               -NF_ACCEPT - 1 } },
8886 +           /* LOCAL_OUT */
8887 +           { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 },
8888 +               0,
8889 +               sizeof(struct ipt_entry),
8890 +               sizeof(struct ipt_standard),
8891 +               0, { 0, 0 }, { } },
8892 +             { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } },
8893 +               -NF_ACCEPT - 1 } }
8894 +    },
8895 +    /* ERROR */
8896 +    { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 },
8897 +       0,
8898 +       sizeof(struct ipt_entry),
8899 +       sizeof(struct ipt_error),
8900 +       0, { 0, 0 }, { } },
8901 +      { { { { IPT_ALIGN(sizeof(struct ipt_error_target)), IPT_ERROR_TARGET } },
8902 +         { } },
8903 +       "ERROR"
8904 +      }
8905 +    }
8906 +};
8907 +
8908 +static struct ipt_table packet_raw = { 
8909 +       .name = "raw", 
8910 +       .table = &initial_table.repl,
8911 +       .valid_hooks =  RAW_VALID_HOOKS, 
8912 +       .lock = RW_LOCK_UNLOCKED, 
8913 +       .me = THIS_MODULE
8914 +};
8915 +
8916 +/* The work comes in here from netfilter.c. */
8917 +static unsigned int
8918 +ipt_hook(unsigned int hook,
8919 +        struct sk_buff **pskb,
8920 +        const struct net_device *in,
8921 +        const struct net_device *out,
8922 +        int (*okfn)(struct sk_buff *))
8923 +{
8924 +       return ipt_do_table(pskb, hook, in, out, &packet_raw, NULL);
8925 +}
8926 +
8927 +/* 'raw' is the very first table. */
8928 +static struct nf_hook_ops ipt_ops[] = {
8929 +       {
8930 +         .hook = ipt_hook, 
8931 +         .pf = PF_INET, 
8932 +         .hooknum = NF_IP_PRE_ROUTING, 
8933 +         .priority = NF_IP_PRI_RAW
8934 +       },
8935 +       {
8936 +         .hook = ipt_hook, 
8937 +         .pf = PF_INET, 
8938 +         .hooknum = NF_IP_LOCAL_OUT, 
8939 +         .priority = NF_IP_PRI_RAW
8940 +       },
8941 +};
8942 +
8943 +static int __init init(void)
8944 +{
8945 +       int ret;
8946 +
8947 +       /* Register table */
8948 +       ret = ipt_register_table(&packet_raw);
8949 +       if (ret < 0)
8950 +               return ret;
8951 +
8952 +       /* Register hooks */
8953 +       ret = nf_register_hook(&ipt_ops[0]);
8954 +       if (ret < 0)
8955 +               goto cleanup_table;
8956 +
8957 +       ret = nf_register_hook(&ipt_ops[1]);
8958 +       if (ret < 0)
8959 +               goto cleanup_hook0;
8960 +
8961 +       return ret;
8962 +
8963 + cleanup_hook0:
8964 +       nf_unregister_hook(&ipt_ops[0]);
8965 + cleanup_table:
8966 +       ipt_unregister_table(&packet_raw);
8967 +
8968 +       return ret;
8969 +}
8970 +
8971 +static void __exit fini(void)
8972 +{
8973 +       unsigned int i;
8974 +
8975 +       for (i = 0; i < sizeof(ipt_ops)/sizeof(struct nf_hook_ops); i++)
8976 +               nf_unregister_hook(&ipt_ops[i]);
8977 +
8978 +       ipt_unregister_table(&packet_raw);
8979 +}
8980 +
8981 +module_init(init);
8982 +module_exit(fini);
8983 +MODULE_LICENSE("GPL");
8984 diff -Nur linux-2.6.4-rc2.org/net/ipv6/netfilter/Kconfig linux-2.6.4-rc2/net/ipv6/netfilter/Kconfig
8985 --- linux-2.6.4-rc2.org/net/ipv6/netfilter/Kconfig      2004-03-04 06:17:03.000000000 +0000
8986 +++ linux-2.6.4-rc2/net/ipv6/netfilter/Kconfig  2004-03-05 09:55:23.000000000 +0000
8987 @@ -218,5 +218,37 @@
8988           To compile it as a module, choose M here.  If unsure, say N.
8989  
8990  #dep_tristate '  LOG target support' CONFIG_IP6_NF_TARGET_LOG $CONFIG_IP6_NF_IPTABLES
8991 +config IP6_NF_TARGET_HL
8992 +       tristate  'HL target support'
8993 +       depends on IP6_NF_MANGLE
8994 +         help
8995 +
8996 +config IP6_NF_TARGET_REJECT
8997 +       tristate  'REJECT target support'
8998 +       depends on IP6_NF_FILTER
8999 +         help
9000 +
9001 +config IP6_NF_MATCH_FUZZY
9002 +       tristate  'Fuzzy match support'
9003 +       depends on IP6_NF_FILTER
9004 +         help
9005 +
9006 +config IP6_NF_MATCH_NTH
9007 +       tristate  'Nth match support'
9008 +       depends on IP6_NF_IPTABLES
9009 +         help
9010 +
9011 +config IP6_NF_RAW
9012 +       tristate  'raw table support (required for TRACE)'
9013 +       depends on IP6_NF_IPTABLES
9014 +       help
9015 +         This option adds a `raw' table to ip6tables. This table is the very
9016 +         first in the netfilter framework and hooks in at the PREROUTING
9017 +         and OUTPUT chains.
9018 +       
9019 +         If you want to compile it as a module, say M here and read
9020 +         <file:Documentation/modules.txt>.  If unsure, say `N'.
9021 +         help
9022 +
9023  endmenu
9024  
9025 diff -Nur linux-2.6.4-rc2.org/net/ipv6/netfilter/Makefile linux-2.6.4-rc2/net/ipv6/netfilter/Makefile
9026 --- linux-2.6.4-rc2.org/net/ipv6/netfilter/Makefile     2004-03-04 06:16:48.000000000 +0000
9027 +++ linux-2.6.4-rc2/net/ipv6/netfilter/Makefile 2004-03-05 09:55:23.000000000 +0000
9028 @@ -8,6 +8,7 @@
9029  obj-$(CONFIG_IP6_NF_MATCH_MARK) += ip6t_mark.o
9030  obj-$(CONFIG_IP6_NF_MATCH_LENGTH) += ip6t_length.o
9031  obj-$(CONFIG_IP6_NF_MATCH_MAC) += ip6t_mac.o
9032 +obj-$(CONFIG_IP6_NF_MATCH_FUZZY) += ip6t_fuzzy.o
9033  obj-$(CONFIG_IP6_NF_MATCH_RT) += ip6t_rt.o
9034  obj-$(CONFIG_IP6_NF_MATCH_OPTS) += ip6t_hbh.o ip6t_dst.o
9035  obj-$(CONFIG_IP6_NF_MATCH_IPV6HEADER) += ip6t_ipv6header.o
9036 @@ -19,6 +20,11 @@
9037  obj-$(CONFIG_IP6_NF_FILTER) += ip6table_filter.o
9038  obj-$(CONFIG_IP6_NF_MANGLE) += ip6table_mangle.o
9039  obj-$(CONFIG_IP6_NF_TARGET_MARK) += ip6t_MARK.o
9040 +obj-$(CONFIG_IP6_NF_TARGET_REJECT) += ip6t_REJECT.o
9041  obj-$(CONFIG_IP6_NF_QUEUE) += ip6_queue.o
9042  obj-$(CONFIG_IP6_NF_TARGET_LOG) += ip6t_LOG.o
9043 +obj-$(CONFIG_IP6_NF_RAW) += ip6table_raw.o
9044 +
9045 +obj-$(CONFIG_IP6_NF_MATCH_NTH) += ip6t_nth.o
9046 +obj-$(CONFIG_IP6_NF_TARGET_HL) += ip6t_HL.o
9047  obj-$(CONFIG_IP6_NF_MATCH_HL) += ip6t_hl.o
9048 diff -Nur linux-2.6.4-rc2.org/net/ipv6/netfilter/ip6t_HL.c linux-2.6.4-rc2/net/ipv6/netfilter/ip6t_HL.c
9049 --- linux-2.6.4-rc2.org/net/ipv6/netfilter/ip6t_HL.c    1970-01-01 00:00:00.000000000 +0000
9050 +++ linux-2.6.4-rc2/net/ipv6/netfilter/ip6t_HL.c        2004-03-05 09:55:10.000000000 +0000
9051 @@ -0,0 +1,105 @@
9052 +/* 
9053 + * Hop Limit modification target for ip6tables
9054 + * Maciej Soltysiak <solt@dns.toxicfilms.tv>
9055 + * Based on HW's TTL module
9056 + *
9057 + * This software is distributed under the terms of GNU GPL
9058 + */
9059 +
9060 +#include <linux/module.h>
9061 +#include <linux/skbuff.h>
9062 +#include <linux/ip.h>
9063 +
9064 +#include <linux/netfilter_ipv6/ip6_tables.h>
9065 +#include <linux/netfilter_ipv6/ip6t_HL.h>
9066 +
9067 +MODULE_AUTHOR("Maciej Soltysiak <solt@dns.toxicfilms.tv>");
9068 +MODULE_DESCRIPTION("IP tables Hop Limit modification module");
9069 +MODULE_LICENSE("GPL");
9070 +
9071 +static unsigned int ip6t_hl_target(struct sk_buff **pskb, unsigned int hooknum,
9072 +               const struct net_device *in, const struct net_device *out,
9073 +               const void *targinfo, void *userinfo)
9074 +{
9075 +       struct ipv6hdr *ip6h = (*pskb)->nh.ipv6h;
9076 +       const struct ip6t_HL_info *info = targinfo;
9077 +       u_int16_t diffs[2];
9078 +       int new_hl;
9079 +                        
9080 +       switch (info->mode) {
9081 +               case IP6T_HL_SET:
9082 +                       new_hl = info->hop_limit;
9083 +                       break;
9084 +               case IP6T_HL_INC:
9085 +                       new_hl = ip6h->hop_limit + info->hop_limit;
9086 +                       if (new_hl > 255)
9087 +                               new_hl = 255;
9088 +                       break;
9089 +               case IP6T_HL_DEC:
9090 +                       new_hl = ip6h->hop_limit + info->hop_limit;
9091 +                       if (new_hl < 0)
9092 +                               new_hl = 0;
9093 +                       break;
9094 +               default:
9095 +                       new_hl = ip6h->hop_limit;
9096 +                       break;
9097 +       }
9098 +
9099 +       if (new_hl != ip6h->hop_limit) {
9100 +               diffs[0] = htons(((unsigned)ip6h->hop_limit) << 8) ^ 0xFFFF;
9101 +               ip6h->hop_limit = new_hl;
9102 +               diffs[1] = htons(((unsigned)ip6h->hop_limit) << 8);
9103 +       }
9104 +
9105 +       return IP6T_CONTINUE;
9106 +}
9107 +
9108 +static int ip6t_hl_checkentry(const char *tablename,
9109 +               const struct ip6t_entry *e,
9110 +               void *targinfo,
9111 +               unsigned int targinfosize,
9112 +               unsigned int hook_mask)
9113 +{
9114 +       struct ip6t_HL_info *info = targinfo;
9115 +
9116 +       if (targinfosize != IP6T_ALIGN(sizeof(struct ip6t_HL_info))) {
9117 +               printk(KERN_WARNING "HL: targinfosize %u != %Zu\n",
9118 +                               targinfosize,
9119 +                               IP6T_ALIGN(sizeof(struct ip6t_HL_info)));
9120 +               return 0;       
9121 +       }       
9122 +
9123 +       if (strcmp(tablename, "mangle")) {
9124 +               printk(KERN_WARNING "HL: can only be called from \"mangle\" table, not \"%s\"\n", tablename);
9125 +               return 0;
9126 +       }
9127 +
9128 +       if (info->mode > IP6T_HL_MAXMODE) {
9129 +               printk(KERN_WARNING "HL: invalid or unknown Mode %u\n", 
9130 +                       info->mode);
9131 +               return 0;
9132 +       }
9133 +
9134 +       if ((info->mode != IP6T_HL_SET) && (info->hop_limit == 0)) {
9135 +               printk(KERN_WARNING "HL: increment/decrement doesn't make sense with value 0\n");
9136 +               return 0;
9137 +       }
9138 +       
9139 +       return 1;
9140 +}
9141 +
9142 +static struct ip6t_target ip6t_HL = { { NULL, NULL }, "HL", 
9143 +       ip6t_hl_target, ip6t_hl_checkentry, NULL, THIS_MODULE };
9144 +
9145 +static int __init init(void)
9146 +{
9147 +       return ip6t_register_target(&ip6t_HL);
9148 +}
9149 +
9150 +static void __exit fini(void)
9151 +{
9152 +       ip6t_unregister_target(&ip6t_HL);
9153 +}
9154 +
9155 +module_init(init);
9156 +module_exit(fini);
9157 diff -Nur linux-2.6.4-rc2.org/net/ipv6/netfilter/ip6t_LOG.c linux-2.6.4-rc2/net/ipv6/netfilter/ip6t_LOG.c
9158 --- linux-2.6.4-rc2.org/net/ipv6/netfilter/ip6t_LOG.c   2004-03-04 06:16:41.000000000 +0000
9159 +++ linux-2.6.4-rc2/net/ipv6/netfilter/ip6t_LOG.c       2004-03-05 09:55:08.000000000 +0000
9160 @@ -18,12 +18,17 @@
9161  #include <net/udp.h>
9162  #include <net/tcp.h>
9163  #include <net/ipv6.h>
9164 +#include <linux/netfilter.h>
9165  #include <linux/netfilter_ipv6/ip6_tables.h>
9166  
9167  MODULE_AUTHOR("Jan Rekorajski <baggins@pld.org.pl>");
9168  MODULE_DESCRIPTION("IP6 tables LOG target module");
9169  MODULE_LICENSE("GPL");
9170  
9171 +static unsigned int nflog = 1;
9172 +MODULE_PARM(nflog, "i");
9173 +MODULE_PARM_DESC(nflog, "register as internal netfilter logging module");
9174
9175  struct in_device;
9176  #include <net/route.h>
9177  #include <linux/netfilter_ipv6/ip6t_LOG.h>
9178 @@ -265,40 +270,38 @@
9179         }
9180  }
9181  
9182 -static unsigned int
9183 -ip6t_log_target(struct sk_buff **pskb,
9184 -               unsigned int hooknum,
9185 +static void
9186 +ip6t_log_packet(unsigned int hooknum,
9187 +               const struct sk_buff *skb,
9188                 const struct net_device *in,
9189                 const struct net_device *out,
9190 -               const void *targinfo,
9191 -               void *userinfo)
9192 +               const struct ip6t_log_info *loginfo,
9193 +               const char *level_string,
9194 +               const char *prefix)
9195  {
9196 -       struct ipv6hdr *ipv6h = (*pskb)->nh.ipv6h;
9197 -       const struct ip6t_log_info *loginfo = targinfo;
9198 -       char level_string[4] = "< >";
9199 +       struct ipv6hdr *ipv6h = skb->nh.ipv6h;
9200  
9201 -       level_string[1] = '0' + (loginfo->level % 8);
9202         spin_lock_bh(&log_lock);
9203         printk(level_string);
9204         printk("%sIN=%s OUT=%s ",
9205 -               loginfo->prefix,
9206 +               prefix == NULL ? loginfo->prefix : prefix,
9207                 in ? in->name : "",
9208                 out ? out->name : "");
9209         if (in && !out) {
9210                 /* MAC logging for input chain only. */
9211                 printk("MAC=");
9212 -               if ((*pskb)->dev && (*pskb)->dev->hard_header_len && (*pskb)->mac.raw != (void*)ipv6h) {
9213 -                       if ((*pskb)->dev->type != ARPHRD_SIT){
9214 +               if (skb->dev && skb->dev->hard_header_len && skb->mac.raw != (void*)ipv6h) {
9215 +                       if (skb->dev->type != ARPHRD_SIT){
9216                           int i;
9217 -                         unsigned char *p = (*pskb)->mac.raw;
9218 -                         for (i = 0; i < (*pskb)->dev->hard_header_len; i++,p++)
9219 +                         unsigned char *p = skb->mac.raw;
9220 +                         for (i = 0; i < skb->dev->hard_header_len; i++,p++)
9221                                 printk("%02x%c", *p,
9222 -                                       i==(*pskb)->dev->hard_header_len - 1
9223 +                                       i==skb->dev->hard_header_len - 1
9224                                         ? ' ':':');
9225                         } else {
9226                           int i;
9227 -                         unsigned char *p = (*pskb)->mac.raw;
9228 -                         if ( p - (ETH_ALEN*2+2) > (*pskb)->head ){
9229 +                         unsigned char *p = skb->mac.raw;
9230 +                         if ( p - (ETH_ALEN*2+2) > skb->head ){
9231                             p -= (ETH_ALEN+2);
9232                             for (i = 0; i < (ETH_ALEN); i++,p++)
9233                                 printk("%02x%s", *p,
9234 @@ -309,10 +312,10 @@
9235                                         i == ETH_ALEN-1 ? ' ' : ':');
9236                           }
9237                           
9238 -                         if (((*pskb)->dev->addr_len == 4) &&
9239 -                             (*pskb)->dev->hard_header_len > 20){
9240 +                         if ((skb->dev->addr_len == 4) &&
9241 +                             skb->dev->hard_header_len > 20){
9242                             printk("TUNNEL=");
9243 -                           p = (*pskb)->mac.raw + 12;
9244 +                           p = skb->mac.raw + 12;
9245                             for (i = 0; i < 4; i++,p++)
9246                                 printk("%3d%s", *p,
9247                                         i == 3 ? "->" : ".");
9248 @@ -328,10 +331,41 @@
9249         dump_packet(loginfo, ipv6h, 1);
9250         printk("\n");
9251         spin_unlock_bh(&log_lock);
9252 +}
9253 +
9254 +static unsigned int
9255 +ip6t_log_target(struct sk_buff **pskb,
9256 +               unsigned int hooknum,
9257 +               const struct net_device *in,
9258 +               const struct net_device *out,
9259 +               const void *targinfo,
9260 +               void *userinfo)
9261 +{
9262 +       const struct ip6t_log_info *loginfo = targinfo;
9263 +       char level_string[4] = "< >";
9264 +
9265 +       level_string[1] = '0' + (loginfo->level % 8);
9266 +       ip6t_log_packet(hooknum, *pskb, in, out, loginfo, level_string, NULL);
9267  
9268         return IP6T_CONTINUE;
9269  }
9270  
9271 +static void
9272 +ip6t_logfn(unsigned int hooknum,
9273 +          const struct sk_buff *skb,
9274 +          const struct net_device *in,
9275 +          const struct net_device *out,
9276 +          const char *prefix)
9277 +{
9278 +       struct ip6t_log_info loginfo = {
9279 +               .level = 0,
9280 +               .logflags = IP6T_LOG_MASK,
9281 +               .prefix = ""
9282 +       };
9283 +
9284 +       ip6t_log_packet(hooknum, skb, in, out, &loginfo, KERN_WARNING, prefix);
9285 +}
9286 +
9287  static int ip6t_log_checkentry(const char *tablename,
9288                                const struct ip6t_entry *e,
9289                                void *targinfo,
9290 @@ -360,20 +394,27 @@
9291         return 1;
9292  }
9293  
9294 -static struct ip6t_target ip6t_log_reg
9295 -= { { NULL, NULL }, "LOG", ip6t_log_target, ip6t_log_checkentry, NULL, 
9296 -    THIS_MODULE };
9297 +static struct ip6t_target ip6t_log_reg = {
9298 +       .name           = "LOG",
9299 +       .target         = ip6t_log_target, 
9300 +       .checkentry     = ip6t_log_checkentry, 
9301 +       .me             = THIS_MODULE,
9302 +};
9303  
9304  static int __init init(void)
9305  {
9306         if (ip6t_register_target(&ip6t_log_reg))
9307                 return -EINVAL;
9308 +       if (nflog)
9309 +               nf_log_register(PF_INET6, &ip6t_logfn);
9310  
9311         return 0;
9312  }
9313  
9314  static void __exit fini(void)
9315  {
9316 +       if (nflog)
9317 +               nf_log_unregister(PF_INET6, &ip6t_logfn);
9318         ip6t_unregister_target(&ip6t_log_reg);
9319  }
9320  
9321 diff -Nur linux-2.6.4-rc2.org/net/ipv6/netfilter/ip6t_REJECT.c linux-2.6.4-rc2/net/ipv6/netfilter/ip6t_REJECT.c
9322 --- linux-2.6.4-rc2.org/net/ipv6/netfilter/ip6t_REJECT.c        1970-01-01 00:00:00.000000000 +0000
9323 +++ linux-2.6.4-rc2/net/ipv6/netfilter/ip6t_REJECT.c    2004-03-05 09:55:13.000000000 +0000
9324 @@ -0,0 +1,274 @@
9325 +/*
9326 + * This is a module which is used for rejecting packets.
9327 + *     Added support for customized reject packets (Jozsef Kadlecsik).
9328 + * Sun 12 Nov 2000
9329 + *     Port to IPv6 / ip6tables (Harald Welte <laforge@gnumonks.org>)
9330 + */
9331 +#include <linux/config.h>
9332 +#include <linux/module.h>
9333 +#include <linux/skbuff.h>
9334 +#include <linux/icmpv6.h>
9335 +#include <net/tcp.h>
9336 +#include <linux/netfilter_ipv6/ip6_tables.h>
9337 +#include <linux/netfilter_ipv6/ip6t_REJECT.h>
9338 +
9339 +#if 1
9340 +#define DEBUGP printk
9341 +#else
9342 +#define DEBUGP(format, args...)
9343 +#endif
9344 +
9345 +#if 0
9346 +/* Send RST reply */
9347 +static void send_reset(struct sk_buff *oldskb)
9348 +{
9349 +       struct sk_buff *nskb;
9350 +       struct tcphdr *otcph, *tcph;
9351 +       struct rtable *rt;
9352 +       unsigned int otcplen;
9353 +       int needs_ack;
9354 +
9355 +       /* IP header checks: fragment, too short. */
9356 +       if (oldskb->nh.iph->frag_off & htons(IP_OFFSET)
9357 +           || oldskb->len < (oldskb->nh.iph->ihl<<2) + sizeof(struct tcphdr))
9358 +               return;
9359 +
9360 +       otcph = (struct tcphdr *)((u_int32_t*)oldskb->nh.iph + oldskb->nh.iph->ihl);
9361 +       otcplen = oldskb->len - oldskb->nh.iph->ihl*4;
9362 +
9363 +       /* No RST for RST. */
9364 +       if (otcph->rst)
9365 +               return;
9366 +
9367 +       /* Check checksum. */
9368 +       if (tcp_v4_check(otcph, otcplen, oldskb->nh.iph->saddr,
9369 +                        oldskb->nh.iph->daddr,
9370 +                        csum_partial((char *)otcph, otcplen, 0)) != 0)
9371 +               return;
9372 +
9373 +       /* Copy skb (even if skb is about to be dropped, we can't just
9374 +           clone it because there may be other things, such as tcpdump,
9375 +           interested in it) */
9376 +       nskb = skb_copy(oldskb, GFP_ATOMIC);
9377 +       if (!nskb)
9378 +               return;
9379 +
9380 +       /* This packet will not be the same as the other: clear nf fields */
9381 +       nf_conntrack_put(nskb->nfct);
9382 +       nskb->nfct = NULL;
9383 +       nskb->nfcache = 0;
9384 +#ifdef CONFIG_NETFILTER_DEBUG
9385 +       nskb->nf_debug = 0;
9386 +#endif
9387 +
9388 +       tcph = (struct tcphdr *)((u_int32_t*)nskb->nh.iph + nskb->nh.iph->ihl);
9389 +
9390 +       nskb->nh.iph->daddr = xchg(&nskb->nh.iph->saddr, nskb->nh.iph->daddr);
9391 +       tcph->source = xchg(&tcph->dest, tcph->source);
9392 +
9393 +       /* Truncate to length (no data) */
9394 +       tcph->doff = sizeof(struct tcphdr)/4;
9395 +       skb_trim(nskb, nskb->nh.iph->ihl*4 + sizeof(struct tcphdr));
9396 +       nskb->nh.iph->tot_len = htons(nskb->len);
9397 +
9398 +       if (tcph->ack) {
9399 +               needs_ack = 0;
9400 +               tcph->seq = otcph->ack_seq;
9401 +               tcph->ack_seq = 0;
9402 +       } else {
9403 +               needs_ack = 1;
9404 +               tcph->ack_seq = htonl(ntohl(otcph->seq) + otcph->syn + otcph->fin
9405 +                                     + otcplen - (otcph->doff<<2));
9406 +               tcph->seq = 0;
9407 +       }
9408 +
9409 +       /* Reset flags */
9410 +       ((u_int8_t *)tcph)[13] = 0;
9411 +       tcph->rst = 1;
9412 +       tcph->ack = needs_ack;
9413 +
9414 +       tcph->window = 0;
9415 +       tcph->urg_ptr = 0;
9416 +
9417 +       /* Adjust TCP checksum */
9418 +       tcph->check = 0;
9419 +       tcph->check = tcp_v4_check(tcph, sizeof(struct tcphdr),
9420 +                                  nskb->nh.iph->saddr,
9421 +                                  nskb->nh.iph->daddr,
9422 +                                  csum_partial((char *)tcph,
9423 +                                               sizeof(struct tcphdr), 0));
9424 +
9425 +       /* Adjust IP TTL, DF */
9426 +       nskb->nh.iph->ttl = MAXTTL;
9427 +       /* Set DF, id = 0 */
9428 +       nskb->nh.iph->frag_off = htons(IP_DF);
9429 +       nskb->nh.iph->id = 0;
9430 +
9431 +       /* Adjust IP checksum */
9432 +       nskb->nh.iph->check = 0;
9433 +       nskb->nh.iph->check = ip_fast_csum((unsigned char *)nskb->nh.iph, 
9434 +                                          nskb->nh.iph->ihl);
9435 +
9436 +       /* Routing */
9437 +       if (ip_route_output(&rt, nskb->nh.iph->daddr, nskb->nh.iph->saddr,
9438 +                           RT_TOS(nskb->nh.iph->tos) | RTO_CONN,
9439 +                           0) != 0)
9440 +               goto free_nskb;
9441 +
9442 +       dst_release(nskb->dst);
9443 +       nskb->dst = &rt->u.dst;
9444 +
9445 +       /* "Never happens" */
9446 +       if (nskb->len > nskb->dst->pmtu)
9447 +               goto free_nskb;
9448 +
9449 +       NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, nskb, NULL, nskb->dst->dev,
9450 +               ip_finish_output);
9451 +       return;
9452 +
9453 + free_nskb:
9454 +       kfree_skb(nskb);
9455 +}
9456 +#endif
9457 +
9458 +static unsigned int reject6_target(struct sk_buff **pskb,
9459 +                          unsigned int hooknum,
9460 +                          const struct net_device *in,
9461 +                          const struct net_device *out,
9462 +                          const void *targinfo,
9463 +                          void *userinfo)
9464 +{
9465 +       const struct ip6t_reject_info *reject = targinfo;
9466 +
9467 +       /* WARNING: This code causes reentry within ip6tables.
9468 +          This means that the ip6tables jump stack is now crap.  We
9469 +          must return an absolute verdict. --RR */
9470 +       DEBUGP("REJECTv6: calling icmpv6_send\n");
9471 +       switch (reject->with) {
9472 +       case IP6T_ICMP6_NO_ROUTE:
9473 +               icmpv6_send(*pskb, ICMPV6_DEST_UNREACH, ICMPV6_NOROUTE, 0, out);
9474 +               break;
9475 +       case IP6T_ICMP6_ADM_PROHIBITED:
9476 +               icmpv6_send(*pskb, ICMPV6_DEST_UNREACH, ICMPV6_ADM_PROHIBITED, 0, out);
9477 +               break;
9478 +       case IP6T_ICMP6_NOT_NEIGHBOUR:
9479 +               icmpv6_send(*pskb, ICMPV6_DEST_UNREACH, ICMPV6_NOT_NEIGHBOUR, 0, out);
9480 +               break;
9481 +       case IP6T_ICMP6_ADDR_UNREACH:
9482 +               icmpv6_send(*pskb, ICMPV6_DEST_UNREACH, ICMPV6_ADDR_UNREACH, 0, out);
9483 +               break;
9484 +       case IP6T_ICMP6_PORT_UNREACH:
9485 +               icmpv6_send(*pskb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0, out);
9486 +               break;
9487 +#if 0
9488 +       case IPT_ICMP_ECHOREPLY: {
9489 +               struct icmp6hdr *icmph  = (struct icmphdr *)
9490 +                       ((u_int32_t *)(*pskb)->nh.iph + (*pskb)->nh.iph->ihl);
9491 +               unsigned int datalen = (*pskb)->len - (*pskb)->nh.iph->ihl * 4;
9492 +
9493 +               /* Not non-head frags, or truncated */
9494 +               if (((ntohs((*pskb)->nh.iph->frag_off) & IP_OFFSET) == 0)
9495 +                   && datalen >= 4) {
9496 +                       /* Usually I don't like cut & pasting code,
9497 +                           but dammit, my party is starting in 45
9498 +                           mins! --RR */
9499 +                       struct icmp_bxm icmp_param;
9500 +
9501 +                       icmp_param.icmph=*icmph;
9502 +                       icmp_param.icmph.type=ICMP_ECHOREPLY;
9503 +                       icmp_param.data_ptr=(icmph+1);
9504 +                       icmp_param.data_len=datalen;
9505 +                       icmp_reply(&icmp_param, *pskb);
9506 +               }
9507 +       }
9508 +       break;
9509 +       case IPT_TCP_RESET:
9510 +               send_reset(*pskb);
9511 +               break;
9512 +#endif
9513 +       default:
9514 +               printk(KERN_WARNING "REJECTv6: case %u not handled yet\n", reject->with);
9515 +               break;
9516 +       }
9517 +
9518 +       return NF_DROP;
9519 +}
9520 +
9521 +static inline int find_ping_match(const struct ip6t_entry_match *m)
9522 +{
9523 +       const struct ip6t_icmp *icmpinfo = (const struct ip6t_icmp *)m->data;
9524 +
9525 +       if (strcmp(m->u.kernel.match->name, "icmp6") == 0
9526 +           && icmpinfo->type == ICMPV6_ECHO_REQUEST
9527 +           && !(icmpinfo->invflags & IP6T_ICMP_INV))
9528 +               return 1;
9529 +
9530 +       return 0;
9531 +}
9532 +
9533 +static int check(const char *tablename,
9534 +                const struct ip6t_entry *e,
9535 +                void *targinfo,
9536 +                unsigned int targinfosize,
9537 +                unsigned int hook_mask)
9538 +{
9539 +       const struct ip6t_reject_info *rejinfo = targinfo;
9540 +
9541 +       if (targinfosize != IP6T_ALIGN(sizeof(struct ip6t_reject_info))) {
9542 +               DEBUGP("REJECTv6: targinfosize %u != 0\n", targinfosize);
9543 +               return 0;
9544 +       }
9545 +
9546 +       /* Only allow these for packet filtering. */
9547 +       if (strcmp(tablename, "filter") != 0) {
9548 +               DEBUGP("REJECTv6: bad table `%s'.\n", tablename);
9549 +               return 0;
9550 +       }
9551 +       if ((hook_mask & ~((1 << NF_IP6_LOCAL_IN)
9552 +                          | (1 << NF_IP6_FORWARD)
9553 +                          | (1 << NF_IP6_LOCAL_OUT))) != 0) {
9554 +               DEBUGP("REJECTv6: bad hook mask %X\n", hook_mask);
9555 +               return 0;
9556 +       }
9557 +
9558 +       if (rejinfo->with == IP6T_ICMP6_ECHOREPLY) {
9559 +               /* Must specify that it's an ICMP ping packet. */
9560 +               if (e->ipv6.proto != IPPROTO_ICMPV6
9561 +                   || (e->ipv6.invflags & IP6T_INV_PROTO)) {
9562 +                       DEBUGP("REJECTv6: ECHOREPLY illegal for non-icmp\n");
9563 +                       return 0;
9564 +               }
9565 +               /* Must contain ICMP match. */
9566 +               if (IP6T_MATCH_ITERATE(e, find_ping_match) == 0) {
9567 +                       DEBUGP("REJECTv6: ECHOREPLY illegal for non-ping\n");
9568 +                       return 0;
9569 +               }
9570 +       } else if (rejinfo->with == IP6T_TCP_RESET) {
9571 +               /* Must specify that it's a TCP packet */
9572 +               if (e->ipv6.proto != IPPROTO_TCP
9573 +                   || (e->ipv6.invflags & IP6T_INV_PROTO)) {
9574 +                       DEBUGP("REJECTv6: TCP_RESET illegal for non-tcp\n");
9575 +                       return 0;
9576 +               }
9577 +       }
9578 +
9579 +       return 1;
9580 +}
9581 +
9582 +static struct ip6t_target ip6t_reject_reg
9583 += { { NULL, NULL }, "REJECT", reject6_target, check, NULL, THIS_MODULE };
9584 +
9585 +static int __init init(void)
9586 +{
9587 +       if (ip6t_register_target(&ip6t_reject_reg))
9588 +               return -EINVAL;
9589 +       return 0;
9590 +}
9591 +
9592 +static void __exit fini(void)
9593 +{
9594 +       ip6t_unregister_target(&ip6t_reject_reg);
9595 +}
9596 +
9597 +module_init(init);
9598 +module_exit(fini);
9599 diff -Nur linux-2.6.4-rc2.org/net/ipv6/netfilter/ip6t_fuzzy.c linux-2.6.4-rc2/net/ipv6/netfilter/ip6t_fuzzy.c
9600 --- linux-2.6.4-rc2.org/net/ipv6/netfilter/ip6t_fuzzy.c 1970-01-01 00:00:00.000000000 +0000
9601 +++ linux-2.6.4-rc2/net/ipv6/netfilter/ip6t_fuzzy.c     2004-03-05 09:55:18.000000000 +0000
9602 @@ -0,0 +1,189 @@
9603 +/*
9604 + * This module implements a simple TSK FLC
9605 + * (Takagi-Sugeno-Kang Fuzzy Logic Controller) that aims
9606 + * to limit , in an adaptive and flexible way , the packet rate crossing
9607 + * a given stream . It serves as an initial and very simple (but effective)
9608 + * example of how Fuzzy Logic techniques can be applied to defeat DoS attacks.
9609 + *  As a matter of fact , Fuzzy Logic can help us to insert any "behavior"
9610 + * into our code in a precise , adaptive and efficient manner.
9611 + *  The goal is very similar to that of "limit" match , but using techniques of
9612 + * Fuzzy Control , that allow us to shape the transfer functions precisely ,
9613 + * avoiding over and undershoots - and stuff like that .
9614 + *
9615 + *
9616 + * 2002-08-10  Hime Aguiar e Oliveira Jr. <hime@engineer.com> : Initial version.
9617 + * 2002-08-17  : Changed to eliminate floating point operations .
9618 + * 2002-08-23  : Coding style changes .
9619 + * 2003-04-08  Maciej Soltysiak <solt@dns.toxicilms.tv> : IPv6 Port
9620 + */
9621 +
9622 +#include <linux/module.h>
9623 +#include <linux/skbuff.h>
9624 +#include <linux/ipv6.h>
9625 +#include <linux/random.h>
9626 +#include <net/tcp.h>
9627 +#include <linux/spinlock.h>
9628 +#include <linux/netfilter_ipv6/ip6_tables.h>
9629 +#include <linux/netfilter_ipv6/ip6t_fuzzy.h>
9630 +
9631 +/*
9632 + Packet Acceptance Rate - LOW and Packet Acceptance Rate - HIGH
9633 + Expressed in percentage
9634 +*/
9635 +
9636 +#define PAR_LOW                1/100
9637 +#define PAR_HIGH       1
9638 +
9639 +static spinlock_t fuzzy_lock = SPIN_LOCK_UNLOCKED;
9640 +
9641 +MODULE_AUTHOR("Hime Aguiar e Oliveira Junior <hime@engineer.com>");
9642 +MODULE_DESCRIPTION("IP tables Fuzzy Logic Controller match module");
9643 +MODULE_LICENSE("GPL");
9644 +
9645 +static  u_int8_t mf_high(u_int32_t tx,u_int32_t mini,u_int32_t maxi)
9646 +{
9647 +       if (tx >= maxi) return 100;
9648 +
9649 +       if (tx <= mini) return 0;
9650 +
9651 +       return ((100 * (tx-mini)) / (maxi-mini));
9652 +}
9653 +
9654 +static u_int8_t mf_low(u_int32_t tx,u_int32_t mini,u_int32_t maxi)
9655 +{
9656 +       if (tx <= mini) return 100;
9657 +
9658 +       if (tx >= maxi) return 0;
9659 +
9660 +       return ((100 * (maxi - tx)) / (maxi - mini));
9661 +
9662 +}
9663 +
9664 +static int
9665 +ip6t_fuzzy_match(const struct sk_buff *pskb,
9666 +              const struct net_device *in,
9667 +              const struct net_device *out,
9668 +              const void *matchinfo,
9669 +              int offset,
9670 +              const void *hdr,
9671 +              u_int16_t datalen,
9672 +              int *hotdrop)
9673 +{
9674 +       /* From userspace */
9675 +
9676 +       struct ip6t_fuzzy_info *info = (struct ip6t_fuzzy_info *) matchinfo;
9677 +
9678 +       u_int8_t random_number;
9679 +       unsigned long amount;
9680 +       u_int8_t howhigh, howlow;
9681 +
9682 +
9683 +       spin_lock_bh(&fuzzy_lock); /* Rise the lock */
9684 +
9685 +       info->bytes_total += pskb->len;
9686 +       info->packets_total++;
9687 +
9688 +       info->present_time = jiffies;
9689 +
9690 +       if (info->present_time >= info->previous_time)
9691 +               amount = info->present_time - info->previous_time;
9692 +       else {
9693 +               /* There was a transition : I choose to re-sample
9694 +                  and keep the old acceptance rate...
9695 +               */
9696 +
9697 +               amount = 0;
9698 +               info->previous_time = info->present_time;
9699 +               info->bytes_total = info->packets_total = 0;
9700 +            };
9701 +
9702 +       if ( amount > HZ/10) {/* More than 100 ms elapsed ... */
9703 +
9704 +               info->mean_rate = (u_int32_t) ((HZ * info->packets_total) \
9705 +                                       / amount);
9706 +
9707 +               info->previous_time = info->present_time;
9708 +               info->bytes_total = info->packets_total = 0;
9709 +
9710 +               howhigh = mf_high(info->mean_rate,info->minimum_rate,info->maximum_rate);
9711 +               howlow  = mf_low(info->mean_rate,info->minimum_rate,info->maximum_rate);
9712 +
9713 +               info->acceptance_rate = (u_int8_t) \
9714 +                               (howhigh * PAR_LOW + PAR_HIGH * howlow);
9715 +
9716 +       /* In fact, the above defuzzification would require a denominator
9717 +        * proportional to (howhigh+howlow) but, in this particular case,
9718 +        * that expression is constant.
9719 +        * An imediate consequence is that it is not necessary to call
9720 +        * both mf_high and mf_low - but to keep things understandable,
9721 +        * I did so.
9722 +        */
9723 +
9724 +       }
9725 +
9726 +       spin_unlock_bh(&fuzzy_lock); /* Release the lock */
9727 +
9728 +
9729 +       if (info->acceptance_rate < 100)
9730 +       {
9731 +               get_random_bytes((void *)(&random_number), 1);
9732 +
9733 +               /*  If within the acceptance , it can pass => don't match */
9734 +               if (random_number <= (255 * info->acceptance_rate) / 100)
9735 +                       return 0;
9736 +               else
9737 +                       return 1; /* It can't pass (It matches) */
9738 +       };
9739 +
9740 +       return 0; /* acceptance_rate == 100 % => Everything passes ... */
9741 +
9742 +}
9743 +
9744 +static int
9745 +ip6t_fuzzy_checkentry(const char *tablename,
9746 +                  const struct ip6t_ip6 *ip,
9747 +                  void *matchinfo,
9748 +                  unsigned int matchsize,
9749 +                  unsigned int hook_mask)
9750 +{
9751 +
9752 +       const struct ip6t_fuzzy_info *info = matchinfo;
9753 +
9754 +       if (matchsize != IP6T_ALIGN(sizeof(struct ip6t_fuzzy_info))) {
9755 +               printk("ip6t_fuzzy: matchsize %u != %u\n", matchsize,
9756 +                      IP6T_ALIGN(sizeof(struct ip6t_fuzzy_info)));
9757 +               return 0;
9758 +       }
9759 +
9760 +       if ((info->minimum_rate < MINFUZZYRATE) || (info->maximum_rate > MAXFUZZYRATE)
9761 +        || (info->minimum_rate >= info->maximum_rate)) {
9762 +               printk("ip6t_fuzzy: BAD limits , please verify !!!\n");
9763 +               return 0;
9764 +       }
9765 +
9766 +       return 1;
9767 +}
9768 +
9769 +static struct ip6t_match ip6t_fuzzy_reg = {
9770 +       {NULL, NULL},
9771 +       "fuzzy",
9772 +       ip6t_fuzzy_match,
9773 +       ip6t_fuzzy_checkentry,
9774 +       NULL,
9775 +       THIS_MODULE };
9776 +
9777 +static int __init init(void)
9778 +{
9779 +       if (ip6t_register_match(&ip6t_fuzzy_reg))
9780 +               return -EINVAL;
9781 +
9782 +       return 0;
9783 +}
9784 +
9785 +static void __exit fini(void)
9786 +{
9787 +       ip6t_unregister_match(&ip6t_fuzzy_reg);
9788 +}
9789 +
9790 +module_init(init);
9791 +module_exit(fini);
9792 diff -Nur linux-2.6.4-rc2.org/net/ipv6/netfilter/ip6t_nth.c linux-2.6.4-rc2/net/ipv6/netfilter/ip6t_nth.c
9793 --- linux-2.6.4-rc2.org/net/ipv6/netfilter/ip6t_nth.c   1970-01-01 00:00:00.000000000 +0000
9794 +++ linux-2.6.4-rc2/net/ipv6/netfilter/ip6t_nth.c       2004-03-05 09:55:21.000000000 +0000
9795 @@ -0,0 +1,173 @@
9796 +/*
9797 +  This is a module which is used for match support for every Nth packet
9798 +  This file is distributed under the terms of the GNU General Public
9799 +  License (GPL). Copies of the GPL can be obtained from:
9800 +     ftp://prep.ai.mit.edu/pub/gnu/GPL
9801 +
9802 +  2001-07-18 Fabrice MARIE <fabrice@netfilter.org> : initial implementation.
9803 +  2001-09-20 Richard Wagner (rwagner@cloudnet.com)
9804 +        * added support for multiple counters
9805 +        * added support for matching on individual packets
9806 +          in the counter cycle
9807 +  2003-04-30 Maciej Soltysiak <solt@dns.toxicfilms.tv> : IPv6 Port
9808 +
9809 +*/
9810 +
9811 +#include <linux/module.h>
9812 +#include <linux/skbuff.h>
9813 +#include <linux/ip.h>
9814 +#include <net/tcp.h>
9815 +#include <linux/spinlock.h>
9816 +#include <linux/netfilter_ipv6/ip6_tables.h>
9817 +#include <linux/netfilter_ipv6/ip6t_nth.h>
9818 +
9819 +MODULE_LICENSE("GPL");
9820 +
9821 +/*
9822 + * State information.
9823 + */
9824 +struct state {
9825 +       spinlock_t lock;
9826 +       u_int16_t number;
9827 +};
9828 +
9829 +static struct state states[IP6T_NTH_NUM_COUNTERS];
9830 +
9831 +static int
9832 +ip6t_nth_match(const struct sk_buff *pskb,
9833 +             const struct net_device *in,
9834 +             const struct net_device *out,
9835 +             const void *matchinfo,
9836 +             int offset,
9837 +             const void *hdr,
9838 +             u_int16_t datalen,
9839 +             int *hotdrop)
9840 +{
9841 +       /* Parameters from userspace */
9842 +       const struct ip6t_nth_info *info = matchinfo;
9843 +        unsigned counter = info->counter;
9844 +               if((counter < 0) || (counter >= IP6T_NTH_NUM_COUNTERS)) 
9845 +       {
9846 +                       printk(KERN_WARNING "nth: invalid counter %u. counter between 0 and %u\n", counter, IP6T_NTH_NUM_COUNTERS-1);
9847 +               return 0;
9848 +        };
9849 +
9850 +        spin_lock(&states[counter].lock);
9851 +
9852 +        /* Are we matching every nth packet?*/
9853 +        if (info->packet == 0xFF)
9854 +        {
9855 +               /* We're matching every nth packet and only every nth packet*/
9856 +               /* Do we match or invert match? */
9857 +               if (info->not == 0)
9858 +               {
9859 +                       if (states[counter].number == 0)
9860 +                       {
9861 +                               ++states[counter].number;
9862 +                               goto match;
9863 +                       }
9864 +                       if (states[counter].number >= info->every)
9865 +                               states[counter].number = 0; /* reset the counter */
9866 +                       else
9867 +                               ++states[counter].number;
9868 +                       goto dontmatch;
9869 +               }
9870 +               else
9871 +               {
9872 +                       if (states[counter].number == 0)
9873 +                       {
9874 +                               ++states[counter].number;
9875 +                               goto dontmatch;
9876 +                       }
9877 +                       if (states[counter].number >= info->every)
9878 +                               states[counter].number = 0;
9879 +                       else
9880 +                               ++states[counter].number;
9881 +                       goto match;
9882 +               }
9883 +        }
9884 +        else
9885 +        {
9886 +               /* We're using the --packet, so there must be a rule for every value */
9887 +               if (states[counter].number == info->packet)
9888 +               {
9889 +                       /* only increment the counter when a match happens */
9890 +                       if (states[counter].number >= info->every)
9891 +                               states[counter].number = 0; /* reset the counter */
9892 +                       else
9893 +                               ++states[counter].number;
9894 +                       goto match;
9895 +               }
9896 +               else
9897 +                       goto dontmatch;
9898 +       }
9899 +
9900 + dontmatch:
9901 +       /* don't match */
9902 +       spin_unlock(&states[counter].lock);
9903 +       return 0;
9904 +
9905 + match:
9906 +       spin_unlock(&states[counter].lock);
9907 +       return 1;
9908 +}
9909 +
9910 +static int
9911 +ip6t_nth_checkentry(const char *tablename,
9912 +                  const struct ip6t_ip6 *e,
9913 +                  void *matchinfo,
9914 +                  unsigned int matchsize,
9915 +                  unsigned int hook_mask)
9916 +{
9917 +       /* Parameters from userspace */
9918 +       const struct ip6t_nth_info *info = matchinfo;
9919 +        unsigned counter = info->counter;
9920 +        if((counter < 0) || (counter >= IP6T_NTH_NUM_COUNTERS)) 
9921 +       {
9922 +               printk(KERN_WARNING "nth: invalid counter %u. counter between 0 and %u\n", counter, IP6T_NTH_NUM_COUNTERS-1);
9923 +                       return 0;
9924 +               };
9925 +
9926 +       if (matchsize != IP6T_ALIGN(sizeof(struct ip6t_nth_info))) {
9927 +               printk("nth: matchsize %u != %u\n", matchsize,
9928 +                      IP6T_ALIGN(sizeof(struct ip6t_nth_info)));
9929 +               return 0;
9930 +       }
9931 +
9932 +       states[counter].number = info->startat;
9933 +
9934 +       return 1;
9935 +}
9936 +
9937 +static struct ip6t_match ip6t_nth_reg = { 
9938 +       {NULL, NULL},
9939 +       "nth",
9940 +       ip6t_nth_match,
9941 +       ip6t_nth_checkentry,
9942 +       NULL,
9943 +       THIS_MODULE };
9944 +
9945 +static int __init init(void)
9946 +{
9947 +       unsigned counter;
9948 +        memset(&states, 0, sizeof(states));
9949 +       if (ip6t_register_match(&ip6t_nth_reg))
9950 +               return -EINVAL;
9951 +
9952 +        for(counter = 0; counter < IP6T_NTH_NUM_COUNTERS; counter++) 
9953 +       {
9954 +               spin_lock_init(&(states[counter].lock));
9955 +        };
9956 +
9957 +       printk("ip6t_nth match loaded\n");
9958 +       return 0;
9959 +}
9960 +
9961 +static void __exit fini(void)
9962 +{
9963 +       ip6t_unregister_match(&ip6t_nth_reg);
9964 +       printk("ip6t_nth match unloaded\n");
9965 +}
9966 +
9967 +module_init(init);
9968 +module_exit(fini);
9969 diff -Nur linux-2.6.4-rc2.org/net/ipv6/netfilter/ip6table_raw.c linux-2.6.4-rc2/net/ipv6/netfilter/ip6table_raw.c
9970 --- linux-2.6.4-rc2.org/net/ipv6/netfilter/ip6table_raw.c       1970-01-01 00:00:00.000000000 +0000
9971 +++ linux-2.6.4-rc2/net/ipv6/netfilter/ip6table_raw.c   2004-03-05 09:55:23.000000000 +0000
9972 @@ -0,0 +1,154 @@
9973 +/*
9974 + * IPv6 raw table, a port of the IPv4 raw table to IPv6
9975 + *
9976 + * Copyright (C) 2003 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
9977 + */
9978 +#include <linux/module.h>
9979 +#include <linux/netfilter_ipv6/ip6_tables.h>
9980 +
9981 +#define RAW_VALID_HOOKS ((1 << NF_IP6_PRE_ROUTING) | (1 << NF_IP6_LOCAL_OUT))
9982 +
9983 +#if 0
9984 +#define DEBUGP(x, args...)     printk(KERN_DEBUG x, ## args)
9985 +#else
9986 +#define DEBUGP(x, args...)
9987 +#endif
9988 +
9989 +/* Standard entry. */
9990 +struct ip6t_standard
9991 +{
9992 +       struct ip6t_entry entry;
9993 +       struct ip6t_standard_target target;
9994 +};
9995 +
9996 +struct ip6t_error_target
9997 +{
9998 +       struct ip6t_entry_target target;
9999 +       char errorname[IP6T_FUNCTION_MAXNAMELEN];
10000 +};
10001 +
10002 +struct ip6t_error
10003 +{
10004 +       struct ip6t_entry entry;
10005 +       struct ip6t_error_target target;
10006 +};
10007 +
10008 +static struct
10009 +{
10010 +       struct ip6t_replace repl;
10011 +       struct ip6t_standard entries[2];
10012 +       struct ip6t_error term;
10013 +} initial_table __initdata 
10014 += { { "raw", RAW_VALID_HOOKS, 3,
10015 +      sizeof(struct ip6t_standard) * 2 + sizeof(struct ip6t_error),
10016 +      { [NF_IP6_PRE_ROUTING]   0,
10017 +       [NF_IP6_LOCAL_OUT]      sizeof(struct ip6t_standard) },
10018 +      { [NF_IP6_PRE_ROUTING]   0,
10019 +       [NF_IP6_LOCAL_OUT]      sizeof(struct ip6t_standard) },
10020 +      0, NULL, { } },
10021 +    {
10022 +           /* PRE_ROUTING */
10023 +            { { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 },
10024 +               0,
10025 +               sizeof(struct ip6t_entry),
10026 +               sizeof(struct ip6t_standard),
10027 +               0, { 0, 0 }, { } },
10028 +             { { { { IP6T_ALIGN(sizeof(struct ip6t_standard_target)), "" } }, { } },
10029 +               -NF_ACCEPT - 1 } },
10030 +           /* LOCAL_OUT */
10031 +            { { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 },
10032 +               0,
10033 +               sizeof(struct ip6t_entry),
10034 +               sizeof(struct ip6t_standard),
10035 +               0, { 0, 0 }, { } },
10036 +             { { { { IP6T_ALIGN(sizeof(struct ip6t_standard_target)), "" } }, { } },
10037 +               -NF_ACCEPT - 1 } },
10038 +    },
10039 +    /* ERROR */
10040 +    { { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 },
10041 +       0,
10042 +       sizeof(struct ip6t_entry),
10043 +       sizeof(struct ip6t_error),
10044 +       0, { 0, 0 }, { } },
10045 +      { { { { IP6T_ALIGN(sizeof(struct ip6t_error_target)), IP6T_ERROR_TARGET } },
10046 +         { } },
10047 +       "ERROR"
10048 +      }
10049 +    }
10050 +};
10051 +
10052 +static struct ip6t_table packet_raw = { 
10053 +       .name = "raw", 
10054 +       .table = &initial_table.repl,
10055 +       .valid_hooks = RAW_VALID_HOOKS, 
10056 +       .lock = RW_LOCK_UNLOCKED, 
10057 +       .me = THIS_MODULE
10058 +};
10059 +
10060 +/* The work comes in here from netfilter.c. */
10061 +static unsigned int
10062 +ip6t_hook(unsigned int hook,
10063 +        struct sk_buff **pskb,
10064 +        const struct net_device *in,
10065 +        const struct net_device *out,
10066 +        int (*okfn)(struct sk_buff *))
10067 +{
10068 +       return ip6t_do_table(pskb, hook, in, out, &packet_raw, NULL);
10069 +}
10070 +
10071 +static struct nf_hook_ops ip6t_ops[] = { 
10072 +       {
10073 +         .hook = ip6t_hook, 
10074 +         .pf = PF_INET6,
10075 +         .hooknum = NF_IP6_PRE_ROUTING,
10076 +         .priority = NF_IP6_PRI_FIRST
10077 +       },
10078 +       {
10079 +         .hook = ip6t_hook, 
10080 +         .pf = PF_INET6, 
10081 +         .hooknum = NF_IP6_LOCAL_OUT,
10082 +         .priority = NF_IP6_PRI_FIRST
10083 +       },
10084 +};
10085 +
10086 +static int __init init(void)
10087 +{
10088 +       int ret;
10089 +
10090 +       /* Register table */
10091 +       ret = ip6t_register_table(&packet_raw);
10092 +       if (ret < 0)
10093 +               return ret;
10094 +
10095 +       /* Register hooks */
10096 +       ret = nf_register_hook(&ip6t_ops[0]);
10097 +       if (ret < 0)
10098 +               goto cleanup_table;
10099 +
10100 +       ret = nf_register_hook(&ip6t_ops[1]);
10101 +       if (ret < 0)
10102 +               goto cleanup_hook0;
10103 +
10104 +       return ret;
10105 +
10106 + cleanup_hook0:
10107 +       nf_unregister_hook(&ip6t_ops[0]);
10108 + cleanup_table:
10109 +       ip6t_unregister_table(&packet_raw);
10110 +
10111 +       return ret;
10112 +}
10113 +
10114 +static void __exit fini(void)
10115 +{
10116 +       unsigned int i;
10117 +
10118 +       for (i = 0; i < sizeof(ip6t_ops)/sizeof(struct nf_hook_ops); i++)
10119 +               nf_unregister_hook(&ip6t_ops[i]);
10120 +
10121 +       ip6t_unregister_table(&packet_raw);
10122 +}
10123 +
10124 +module_init(init);
10125 +module_exit(fini);
10126 +MODULE_LICENSE("GPL");
This page took 0.854927 seconds and 3 git commands to generate.