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