]>
Commit | Line | Data |
---|---|---|
d8da2194 | 1 | diff -Nur linux-2.6.4-rc2.org/include/linux/netfilter_ipv4/ipt_TTL.h linux-2.6.4-rc2/include/linux/netfilter_ipv4/ipt_TTL.h |
2 | --- linux-2.6.4-rc2.org/include/linux/netfilter_ipv4/ipt_TTL.h 1970-01-01 00:00:00.000000000 +0000 | |
3 | +++ linux-2.6.4-rc2/include/linux/netfilter_ipv4/ipt_TTL.h 2004-03-05 07:40:01.000000000 +0000 | |
4 | @@ -0,0 +1,21 @@ | |
5 | +/* TTL modification module for IP tables | |
6 | + * (C) 2000 by Harald Welte <laforge@gnumonks.org> */ | |
7 | + | |
8 | +#ifndef _IPT_TTL_H | |
9 | +#define _IPT_TTL_H | |
10 | + | |
11 | +enum { | |
12 | + IPT_TTL_SET = 0, | |
13 | + IPT_TTL_INC, | |
14 | + IPT_TTL_DEC | |
15 | +}; | |
16 | + | |
17 | +#define IPT_TTL_MAXMODE IPT_TTL_DEC | |
18 | + | |
19 | +struct ipt_TTL_info { | |
20 | + u_int8_t mode; | |
21 | + u_int8_t ttl; | |
22 | +}; | |
23 | + | |
24 | + | |
25 | +#endif | |
26 | diff -Nur linux-2.6.4-rc2.org/include/linux/netfilter_ipv4/ipt_connlimit.h linux-2.6.4-rc2/include/linux/netfilter_ipv4/ipt_connlimit.h | |
27 | --- linux-2.6.4-rc2.org/include/linux/netfilter_ipv4/ipt_connlimit.h 1970-01-01 00:00:00.000000000 +0000 | |
28 | +++ linux-2.6.4-rc2/include/linux/netfilter_ipv4/ipt_connlimit.h 2004-03-05 07:40:04.000000000 +0000 | |
29 | @@ -0,0 +1,12 @@ | |
30 | +#ifndef _IPT_CONNLIMIT_H | |
31 | +#define _IPT_CONNLIMIT_H | |
32 | + | |
33 | +struct ipt_connlimit_data; | |
34 | + | |
35 | +struct ipt_connlimit_info { | |
36 | + int limit; | |
37 | + int inverse; | |
38 | + u_int32_t mask; | |
39 | + struct ipt_connlimit_data *data; | |
40 | +}; | |
41 | +#endif /* _IPT_CONNLIMIT_H */ | |
42 | diff -Nur linux-2.6.4-rc2.org/include/linux/netfilter_ipv4/ipt_dstlimit.h linux-2.6.4-rc2/include/linux/netfilter_ipv4/ipt_dstlimit.h | |
43 | --- linux-2.6.4-rc2.org/include/linux/netfilter_ipv4/ipt_dstlimit.h 1970-01-01 00:00:00.000000000 +0000 | |
44 | +++ linux-2.6.4-rc2/include/linux/netfilter_ipv4/ipt_dstlimit.h 2004-03-05 07:40:06.000000000 +0000 | |
45 | @@ -0,0 +1,39 @@ | |
46 | +#ifndef _IPT_DSTLIMIT_H | |
47 | +#define _IPT_DSTLIMIT_H | |
48 | + | |
49 | +/* timings are in milliseconds. */ | |
50 | +#define IPT_DSTLIMIT_SCALE 10000 | |
51 | +/* 1/10,000 sec period => max of 10,000/sec. Min rate is then 429490 | |
52 | + seconds, or one every 59 hours. */ | |
53 | + | |
54 | +/* details of this structure hidden by the implementation */ | |
55 | +struct ipt_dstlimit_htable; | |
56 | + | |
57 | +#define IPT_DSTLIMIT_HASH_DIP 0x0001 | |
58 | +#define IPT_DSTLIMIT_HASH_DPT 0x0002 | |
59 | +#define IPT_DSTLIMIT_HASH_SIP 0x0004 | |
60 | + | |
61 | +struct dstlimit_cfg { | |
62 | + u_int32_t mode; /* bitmask of IPT_DSTLIMIT_HASH_* */ | |
63 | + u_int32_t avg; /* Average secs between packets * scale */ | |
64 | + u_int32_t burst; /* Period multiplier for upper limit. */ | |
65 | + | |
66 | + /* user specified */ | |
67 | + u_int32_t size; /* how many buckets */ | |
68 | + u_int32_t max; /* max number of entries */ | |
69 | + u_int32_t gc_interval; /* gc interval */ | |
70 | + u_int32_t expire; /* when do entries expire? */ | |
71 | +}; | |
72 | + | |
73 | +struct ipt_dstlimit_info { | |
74 | + char name [IFNAMSIZ]; /* name */ | |
75 | + struct dstlimit_cfg cfg; | |
76 | + struct ipt_dstlimit_htable *hinfo; | |
77 | + | |
78 | + /* Used internally by the kernel */ | |
79 | + union { | |
80 | + void *ptr; | |
81 | + struct ipt_dstlimit_info *master; | |
82 | + } u; | |
83 | +}; | |
84 | +#endif /*_IPT_DSTLIMIT_H*/ | |
85 | diff -Nur linux-2.6.4-rc2.org/include/linux/netfilter_ipv4/ipt_fuzzy.h linux-2.6.4-rc2/include/linux/netfilter_ipv4/ipt_fuzzy.h | |
86 | --- linux-2.6.4-rc2.org/include/linux/netfilter_ipv4/ipt_fuzzy.h 1970-01-01 00:00:00.000000000 +0000 | |
87 | +++ linux-2.6.4-rc2/include/linux/netfilter_ipv4/ipt_fuzzy.h 2004-03-05 07:40:08.000000000 +0000 | |
88 | @@ -0,0 +1,21 @@ | |
89 | +#ifndef _IPT_FUZZY_H | |
90 | +#define _IPT_FUZZY_H | |
91 | + | |
92 | +#include <linux/param.h> | |
93 | +#include <linux/types.h> | |
94 | + | |
95 | +#define MAXFUZZYRATE 10000000 | |
96 | +#define MINFUZZYRATE 3 | |
97 | + | |
98 | +struct ipt_fuzzy_info { | |
99 | + u_int32_t minimum_rate; | |
100 | + u_int32_t maximum_rate; | |
101 | + u_int32_t packets_total; | |
102 | + u_int32_t bytes_total; | |
103 | + u_int32_t previous_time; | |
104 | + u_int32_t present_time; | |
105 | + u_int32_t mean_rate; | |
106 | + u_int8_t acceptance_rate; | |
107 | +}; | |
108 | + | |
109 | +#endif /*_IPT_FUZZY_H*/ | |
110 | diff -Nur linux-2.6.4-rc2.org/include/linux/netfilter_ipv4/ipt_ipv4options.h linux-2.6.4-rc2/include/linux/netfilter_ipv4/ipt_ipv4options.h | |
111 | --- linux-2.6.4-rc2.org/include/linux/netfilter_ipv4/ipt_ipv4options.h 1970-01-01 00:00:00.000000000 +0000 | |
112 | +++ linux-2.6.4-rc2/include/linux/netfilter_ipv4/ipt_ipv4options.h 2004-03-05 07:40:09.000000000 +0000 | |
113 | @@ -0,0 +1,21 @@ | |
114 | +#ifndef __ipt_ipv4options_h_included__ | |
115 | +#define __ipt_ipv4options_h_included__ | |
116 | + | |
117 | +#define IPT_IPV4OPTION_MATCH_SSRR 0x01 /* For strict source routing */ | |
118 | +#define IPT_IPV4OPTION_MATCH_LSRR 0x02 /* For loose source routing */ | |
119 | +#define IPT_IPV4OPTION_DONT_MATCH_SRR 0x04 /* any source routing */ | |
120 | +#define IPT_IPV4OPTION_MATCH_RR 0x08 /* For Record route */ | |
121 | +#define IPT_IPV4OPTION_DONT_MATCH_RR 0x10 | |
122 | +#define IPT_IPV4OPTION_MATCH_TIMESTAMP 0x20 /* For timestamp request */ | |
123 | +#define IPT_IPV4OPTION_DONT_MATCH_TIMESTAMP 0x40 | |
124 | +#define IPT_IPV4OPTION_MATCH_ROUTER_ALERT 0x80 /* For router-alert */ | |
125 | +#define IPT_IPV4OPTION_DONT_MATCH_ROUTER_ALERT 0x100 | |
126 | +#define IPT_IPV4OPTION_MATCH_ANY_OPT 0x200 /* match packet with any option */ | |
127 | +#define IPT_IPV4OPTION_DONT_MATCH_ANY_OPT 0x400 /* match packet with no option */ | |
128 | + | |
129 | +struct ipt_ipv4options_info { | |
130 | + u_int16_t options; | |
131 | +}; | |
132 | + | |
133 | + | |
134 | +#endif /* __ipt_ipv4options_h_included__ */ | |
135 | diff -Nur linux-2.6.4-rc2.org/include/linux/netfilter_ipv4/ipt_mport.h linux-2.6.4-rc2/include/linux/netfilter_ipv4/ipt_mport.h | |
136 | --- linux-2.6.4-rc2.org/include/linux/netfilter_ipv4/ipt_mport.h 1970-01-01 00:00:00.000000000 +0000 | |
137 | +++ linux-2.6.4-rc2/include/linux/netfilter_ipv4/ipt_mport.h 2004-03-05 07:40:11.000000000 +0000 | |
138 | @@ -0,0 +1,24 @@ | |
139 | +#ifndef _IPT_MPORT_H | |
140 | +#define _IPT_MPORT_H | |
141 | +#include <linux/netfilter_ipv4/ip_tables.h> | |
142 | + | |
143 | +#define IPT_MPORT_SOURCE (1<<0) | |
144 | +#define IPT_MPORT_DESTINATION (1<<1) | |
145 | +#define IPT_MPORT_EITHER (IPT_MPORT_SOURCE|IPT_MPORT_DESTINATION) | |
146 | + | |
147 | +#define IPT_MULTI_PORTS 15 | |
148 | + | |
149 | +/* Must fit inside union ipt_matchinfo: 32 bytes */ | |
150 | +/* every entry in ports[] except for the last one has one bit in pflags | |
151 | + * associated with it. If this bit is set, the port is the first port of | |
152 | + * a portrange, with the next entry being the last. | |
153 | + * End of list is marked with pflags bit set and port=65535. | |
154 | + * If 14 ports are used (last one does not have a pflag), the last port | |
155 | + * is repeated to fill the last entry in ports[] */ | |
156 | +struct ipt_mport | |
157 | +{ | |
158 | + u_int8_t flags:2; /* Type of comparison */ | |
159 | + u_int16_t pflags:14; /* Port flags */ | |
160 | + u_int16_t ports[IPT_MULTI_PORTS]; /* Ports */ | |
161 | +}; | |
162 | +#endif /*_IPT_MPORT_H*/ | |
163 | diff -Nur linux-2.6.4-rc2.org/include/linux/netfilter_ipv4/ipt_nth.h linux-2.6.4-rc2/include/linux/netfilter_ipv4/ipt_nth.h | |
164 | --- linux-2.6.4-rc2.org/include/linux/netfilter_ipv4/ipt_nth.h 1970-01-01 00:00:00.000000000 +0000 | |
165 | +++ linux-2.6.4-rc2/include/linux/netfilter_ipv4/ipt_nth.h 2004-03-05 07:40:13.000000000 +0000 | |
166 | @@ -0,0 +1,19 @@ | |
167 | +#ifndef _IPT_NTH_H | |
168 | +#define _IPT_NTH_H | |
169 | + | |
170 | +#include <linux/param.h> | |
171 | +#include <linux/types.h> | |
172 | + | |
173 | +#ifndef IPT_NTH_NUM_COUNTERS | |
174 | +#define IPT_NTH_NUM_COUNTERS 16 | |
175 | +#endif | |
176 | + | |
177 | +struct ipt_nth_info { | |
178 | + u_int8_t every; | |
179 | + u_int8_t not; | |
180 | + u_int8_t startat; | |
181 | + u_int8_t counter; | |
182 | + u_int8_t packet; | |
183 | +}; | |
184 | + | |
185 | +#endif /*_IPT_NTH_H*/ | |
186 | diff -Nur linux-2.6.4-rc2.org/include/linux/netfilter_ipv4/ipt_quota.h linux-2.6.4-rc2/include/linux/netfilter_ipv4/ipt_quota.h | |
187 | --- linux-2.6.4-rc2.org/include/linux/netfilter_ipv4/ipt_quota.h 1970-01-01 00:00:00.000000000 +0000 | |
188 | +++ linux-2.6.4-rc2/include/linux/netfilter_ipv4/ipt_quota.h 2004-03-05 07:40:14.000000000 +0000 | |
189 | @@ -0,0 +1,11 @@ | |
190 | +#ifndef _IPT_QUOTA_H | |
191 | +#define _IPT_QUOTA_H | |
192 | + | |
193 | +/* print debug info in both kernel/netfilter module & iptable library */ | |
194 | +//#define DEBUG_IPT_QUOTA | |
195 | + | |
196 | +struct ipt_quota_info { | |
197 | + u_int64_t quota; | |
198 | +}; | |
199 | + | |
200 | +#endif /*_IPT_QUOTA_H*/ | |
201 | diff -Nur linux-2.6.4-rc2.org/include/linux/netfilter_ipv4/ipt_realm.h linux-2.6.4-rc2/include/linux/netfilter_ipv4/ipt_realm.h | |
202 | --- linux-2.6.4-rc2.org/include/linux/netfilter_ipv4/ipt_realm.h 1970-01-01 00:00:00.000000000 +0000 | |
203 | +++ linux-2.6.4-rc2/include/linux/netfilter_ipv4/ipt_realm.h 2004-03-05 07:40:22.000000000 +0000 | |
204 | @@ -0,0 +1,9 @@ | |
205 | +#ifndef _IPT_REALM_H | |
206 | +#define _IPT_REALM_H | |
207 | + | |
208 | +struct ipt_realm_info { | |
209 | + u_int32_t id; | |
210 | + u_int32_t mask; | |
211 | + u_int8_t invert; | |
212 | +}; | |
213 | +#endif /*_IPT_REALM_H*/ | |
214 | diff -Nur linux-2.6.4-rc2.org/include/linux/netfilter_ipv4/ipt_sctp.h linux-2.6.4-rc2/include/linux/netfilter_ipv4/ipt_sctp.h | |
215 | --- linux-2.6.4-rc2.org/include/linux/netfilter_ipv4/ipt_sctp.h 1970-01-01 00:00:00.000000000 +0000 | |
216 | +++ linux-2.6.4-rc2/include/linux/netfilter_ipv4/ipt_sctp.h 2004-03-05 07:40:24.000000000 +0000 | |
217 | @@ -0,0 +1,107 @@ | |
218 | +#ifndef _IPT_SCTP_H_ | |
219 | +#define _IPT_SCTP_H_ | |
220 | + | |
221 | +#define IPT_SCTP_SRC_PORTS 0x01 | |
222 | +#define IPT_SCTP_DEST_PORTS 0x02 | |
223 | +#define IPT_SCTP_CHUNK_TYPES 0x04 | |
224 | + | |
225 | +#define IPT_SCTP_VALID_FLAGS 0x07 | |
226 | + | |
227 | +#define ELEMCOUNT(x) (sizeof(x)/sizeof(x[0])) | |
228 | + | |
229 | + | |
230 | +struct ipt_sctp_flag_info { | |
231 | + u_int8_t chunktype; | |
232 | + u_int8_t flag; | |
233 | + u_int8_t flag_mask; | |
234 | +}; | |
235 | + | |
236 | +#define IPT_NUM_SCTP_FLAGS 4 | |
237 | + | |
238 | +struct ipt_sctp_info { | |
239 | + u_int16_t dpts[2]; /* Min, Max */ | |
240 | + u_int16_t spts[2]; /* Min, Max */ | |
241 | + | |
242 | + u_int32_t chunkmap[256 / sizeof (u_int32_t)]; /* Bit mask of chunks to be matched according to RFC 2960 */ | |
243 | + | |
244 | +#define SCTP_CHUNK_MATCH_ANY 0x01 /* Match if any of the chunk types are present */ | |
245 | +#define SCTP_CHUNK_MATCH_ALL 0x02 /* Match if all of the chunk types are present */ | |
246 | +#define SCTP_CHUNK_MATCH_ONLY 0x04 /* Match if these are the only chunk types present */ | |
247 | + | |
248 | + u_int32_t chunk_match_type; | |
249 | + struct ipt_sctp_flag_info flag_info[IPT_NUM_SCTP_FLAGS]; | |
250 | + int flag_count; | |
251 | + | |
252 | + u_int32_t flags; | |
253 | + u_int32_t invflags; | |
254 | +}; | |
255 | + | |
256 | +#define bytes(type) (sizeof(type) * 8) | |
257 | + | |
258 | +#define SCTP_CHUNKMAP_SET(chunkmap, type) \ | |
259 | + do { \ | |
260 | + chunkmap[type / bytes(u_int32_t)] |= \ | |
261 | + 1 << (type % bytes(u_int32_t)); \ | |
262 | + } while (0) | |
263 | + | |
264 | +#define SCTP_CHUNKMAP_CLEAR(chunkmap, type) \ | |
265 | + do { \ | |
266 | + chunkmap[type / bytes(u_int32_t)] &= \ | |
267 | + ~(1 << (type % bytes(u_int32_t))); \ | |
268 | + } while (0) | |
269 | + | |
270 | +#define SCTP_CHUNKMAP_IS_SET(chunkmap, type) \ | |
271 | +({ \ | |
272 | + (chunkmap[type / bytes (u_int32_t)] & \ | |
273 | + (1 << (type % bytes (u_int32_t)))) ? 1: 0; \ | |
274 | +}) | |
275 | + | |
276 | +#define SCTP_CHUNKMAP_RESET(chunkmap) \ | |
277 | + do { \ | |
278 | + int i; \ | |
279 | + for (i = 0; i < ELEMCOUNT(chunkmap); i++) \ | |
280 | + chunkmap[i] = 0; \ | |
281 | + } while (0) | |
282 | + | |
283 | +#define SCTP_CHUNKMAP_SET_ALL(chunkmap) \ | |
284 | + do { \ | |
285 | + int i; \ | |
286 | + for (i = 0; i < ELEMCOUNT(chunkmap); i++) \ | |
287 | + chunkmap[i] = ~0; \ | |
288 | + } while (0) | |
289 | + | |
290 | +#define SCTP_CHUNKMAP_COPY(destmap, srcmap) \ | |
291 | + do { \ | |
292 | + int i; \ | |
293 | + for (i = 0; i < ELEMCOUNT(chunkmap); i++) \ | |
294 | + destmap[i] = srcmap[i]; \ | |
295 | + } while (0) | |
296 | + | |
297 | +#define SCTP_CHUNKMAP_IS_CLEAR(chunkmap) \ | |
298 | +({ \ | |
299 | + int i; \ | |
300 | + int flag = 1; \ | |
301 | + for (i = 0; i < ELEMCOUNT(chunkmap); i++) { \ | |
302 | + if (chunkmap[i]) { \ | |
303 | + flag = 0; \ | |
304 | + break; \ | |
305 | + } \ | |
306 | + } \ | |
307 | + flag; \ | |
308 | +}) | |
309 | + | |
310 | +#define SCTP_CHUNKMAP_IS_ALL_SET(chunkmap) \ | |
311 | +({ \ | |
312 | + int i; \ | |
313 | + int flag = 1; \ | |
314 | + for (i = 0; i < ELEMCOUNT(chunkmap); i++) { \ | |
315 | + if (chunkmap[i] != ~0) { \ | |
316 | + flag = 0; \ | |
317 | + break; \ | |
318 | + } \ | |
319 | + } \ | |
320 | + flag; \ | |
321 | +}) | |
322 | + | |
323 | +#endif /* _IPT_SCTP_H_ */ | |
324 | + | |
325 | diff -Nur linux-2.6.4-rc2.org/include/linux/netfilter_ipv6/ip6t_HL.h linux-2.6.4-rc2/include/linux/netfilter_ipv6/ip6t_HL.h | |
326 | --- linux-2.6.4-rc2.org/include/linux/netfilter_ipv6/ip6t_HL.h 1970-01-01 00:00:00.000000000 +0000 | |
327 | +++ linux-2.6.4-rc2/include/linux/netfilter_ipv6/ip6t_HL.h 2004-03-05 07:39:53.000000000 +0000 | |
328 | @@ -0,0 +1,22 @@ | |
329 | +/* Hop Limit modification module for ip6tables | |
330 | + * Maciej Soltysiak <solt@dns.toxicfilms.tv> | |
331 | + * Based on HW's TTL module */ | |
332 | + | |
333 | +#ifndef _IP6T_HOPLIMIT_H | |
334 | +#define _IP6T_HOPLIMIT_H | |
335 | + | |
336 | +enum { | |
337 | + IP6T_HOPLIMIT_SET = 0, | |
338 | + IP6T_HOPLIMIT_INC, | |
339 | + IP6T_HOPLIMIT_DEC | |
340 | +}; | |
341 | + | |
342 | +#define IP6T_HOPLIMIT_MAXMODE IP6T_HOPLIMIT_DEC | |
343 | + | |
344 | +struct ip6t_HOPLIMIT_info { | |
345 | + u_int8_t mode; | |
346 | + u_int8_t hop_limit; | |
347 | +}; | |
348 | + | |
349 | + | |
350 | +#endif | |
351 | diff -Nur linux-2.6.4-rc2.org/include/linux/netfilter_ipv6/ip6t_REJECT.h linux-2.6.4-rc2/include/linux/netfilter_ipv6/ip6t_REJECT.h | |
352 | --- linux-2.6.4-rc2.org/include/linux/netfilter_ipv6/ip6t_REJECT.h 2004-03-04 06:16:34.000000000 +0000 | |
353 | +++ linux-2.6.4-rc2/include/linux/netfilter_ipv6/ip6t_REJECT.h 2004-03-05 07:39:59.000000000 +0000 | |
354 | @@ -2,15 +2,17 @@ | |
355 | #define _IP6T_REJECT_H | |
356 | ||
357 | enum ip6t_reject_with { | |
358 | - IP6T_ICMP_NET_UNREACHABLE, | |
359 | - IP6T_ICMP_HOST_UNREACHABLE, | |
360 | - IP6T_ICMP_PROT_UNREACHABLE, | |
361 | - IP6T_ICMP_PORT_UNREACHABLE, | |
362 | - IP6T_ICMP_ECHOREPLY | |
363 | + IP6T_ICMP6_NO_ROUTE, | |
364 | + IP6T_ICMP6_ADM_PROHIBITED, | |
365 | + IP6T_ICMP6_NOT_NEIGHBOUR, | |
366 | + IP6T_ICMP6_ADDR_UNREACH, | |
367 | + IP6T_ICMP6_PORT_UNREACH, | |
368 | + IP6T_ICMP6_ECHOREPLY, | |
369 | + IP6T_TCP_RESET | |
370 | }; | |
371 | ||
372 | struct ip6t_reject_info { | |
373 | enum ip6t_reject_with with; /* reject type */ | |
374 | }; | |
375 | ||
376 | -#endif /*_IPT_REJECT_H*/ | |
377 | +#endif /*_IP6T_REJECT_H*/ | |
378 | diff -Nur linux-2.6.4-rc2.org/include/linux/netfilter_ipv6/ip6t_fuzzy.h linux-2.6.4-rc2/include/linux/netfilter_ipv6/ip6t_fuzzy.h | |
379 | --- linux-2.6.4-rc2.org/include/linux/netfilter_ipv6/ip6t_fuzzy.h 1970-01-01 00:00:00.000000000 +0000 | |
380 | +++ linux-2.6.4-rc2/include/linux/netfilter_ipv6/ip6t_fuzzy.h 2004-03-05 07:40:08.000000000 +0000 | |
381 | @@ -0,0 +1,21 @@ | |
382 | +#ifndef _IP6T_FUZZY_H | |
383 | +#define _IP6T_FUZZY_H | |
384 | + | |
385 | +#include <linux/param.h> | |
386 | +#include <linux/types.h> | |
387 | + | |
388 | +#define MAXFUZZYRATE 10000000 | |
389 | +#define MINFUZZYRATE 3 | |
390 | + | |
391 | +struct ip6t_fuzzy_info { | |
392 | + u_int32_t minimum_rate; | |
393 | + u_int32_t maximum_rate; | |
394 | + u_int32_t packets_total; | |
395 | + u_int32_t bytes_total; | |
396 | + u_int32_t previous_time; | |
397 | + u_int32_t present_time; | |
398 | + u_int32_t mean_rate; | |
399 | + u_int8_t acceptance_rate; | |
400 | +}; | |
401 | + | |
402 | +#endif /*_IP6T_FUZZY_H*/ | |
403 | diff -Nur linux-2.6.4-rc2.org/include/linux/netfilter_ipv6/ip6t_nth.h linux-2.6.4-rc2/include/linux/netfilter_ipv6/ip6t_nth.h | |
404 | --- linux-2.6.4-rc2.org/include/linux/netfilter_ipv6/ip6t_nth.h 1970-01-01 00:00:00.000000000 +0000 | |
405 | +++ linux-2.6.4-rc2/include/linux/netfilter_ipv6/ip6t_nth.h 2004-03-05 07:40:13.000000000 +0000 | |
406 | @@ -0,0 +1,19 @@ | |
407 | +#ifndef _IP6T_NTH_H | |
408 | +#define _IP6T_NTH_H | |
409 | + | |
410 | +#include <linux/param.h> | |
411 | +#include <linux/types.h> | |
412 | + | |
413 | +#ifndef IP6T_NTH_NUM_COUNTERS | |
414 | +#define IP6T_NTH_NUM_COUNTERS 16 | |
415 | +#endif | |
416 | + | |
417 | +struct ip6t_nth_info { | |
418 | + u_int8_t every; | |
419 | + u_int8_t not; | |
420 | + u_int8_t startat; | |
421 | + u_int8_t counter; | |
422 | + u_int8_t packet; | |
423 | +}; | |
424 | + | |
425 | +#endif /*_IP6T_NTH_H*/ | |
426 | diff -Nur linux-2.6.4-rc2.org/net/core/netfilter.c linux-2.6.4-rc2/net/core/netfilter.c | |
427 | --- linux-2.6.4-rc2.org/net/core/netfilter.c 2004-03-04 06:16:45.000000000 +0000 | |
428 | +++ linux-2.6.4-rc2/net/core/netfilter.c 2004-03-05 07:39:43.000000000 +0000 | |
429 | @@ -58,6 +58,10 @@ | |
430 | } queue_handler[NPROTO]; | |
431 | static rwlock_t queue_handler_lock = RW_LOCK_UNLOCKED; | |
432 | ||
433 | +/** | |
434 | + * nf_register_hook - Register with a netfilter hook | |
435 | + * @reg: Hook operations to be registered | |
436 | + */ | |
437 | int nf_register_hook(struct nf_hook_ops *reg) | |
438 | { | |
439 | struct list_head *i; | |
440 | @@ -74,6 +78,10 @@ | |
441 | return 0; | |
442 | } | |
443 | ||
444 | +/** | |
445 | + * nf_unregister_hook - Unregister from a netfilter hook | |
446 | + * @reg: hook operations to be unregistered | |
447 | + */ | |
448 | void nf_unregister_hook(struct nf_hook_ops *reg) | |
449 | { | |
450 | spin_lock_bh(&nf_hook_lock); | |
451 | @@ -386,6 +394,18 @@ | |
452 | return NF_ACCEPT; | |
453 | } | |
454 | ||
455 | +/** | |
456 | + * nf_register_queue_handler - Registere a queue handler with netfilter | |
457 | + * @pf: protocol family | |
458 | + * @outfn: function called by core to enqueue a packet | |
459 | + * @data: opaque parameter, passed through | |
460 | + * | |
461 | + * This function registers a queue handler with netfilter. There can only | |
462 | + * be one queue handler for every protocol family. | |
463 | + * | |
464 | + * A queue handler _must_ reinject every packet via nf_reinject, no | |
465 | + * matter what. | |
466 | + */ | |
467 | int nf_register_queue_handler(int pf, nf_queue_outfn_t outfn, void *data) | |
468 | { | |
469 | int ret; | |
470 | @@ -403,7 +423,12 @@ | |
471 | return ret; | |
472 | } | |
473 | ||
474 | -/* The caller must flush their queue before this */ | |
475 | +/** | |
476 | + * nf_unregister_queue_handler - Unregister queue handler from netfilter | |
477 | + * @pf: protocol family | |
478 | + * | |
479 | + * The caller must flush their queue before unregistering | |
480 | + */ | |
481 | int nf_unregister_queue_handler(int pf) | |
482 | { | |
483 | write_lock_bh(&queue_handler_lock); | |
484 | @@ -546,6 +571,15 @@ | |
485 | return ret; | |
486 | } | |
487 | ||
488 | +/** | |
489 | + * nf_reinject - Reinject a packet from a queue handler | |
490 | + * @skb: the packet to be reinjected | |
491 | + * @info: info which was passed to the outfn() of the queue handler | |
492 | + * @verdict: verdict (NF_ACCEPT, ...) for this packet | |
493 | + * | |
494 | + * This is the function called by a queue handler to reinject a | |
495 | + * packet. | |
496 | + */ | |
497 | void nf_reinject(struct sk_buff *skb, struct nf_info *info, | |
498 | unsigned int verdict) | |
499 | { | |
500 | diff -Nur linux-2.6.4-rc2.org/net/core/netfilter.c.orig linux-2.6.4-rc2/net/core/netfilter.c.orig | |
501 | --- linux-2.6.4-rc2.org/net/core/netfilter.c.orig 1970-01-01 00:00:00.000000000 +0000 | |
502 | +++ linux-2.6.4-rc2/net/core/netfilter.c.orig 2004-03-04 06:16:45.000000000 +0000 | |
503 | @@ -0,0 +1,772 @@ | |
504 | +/* netfilter.c: look after the filters for various protocols. | |
505 | + * Heavily influenced by the old firewall.c by David Bonn and Alan Cox. | |
506 | + * | |
507 | + * Thanks to Rob `CmdrTaco' Malda for not influencing this code in any | |
508 | + * way. | |
509 | + * | |
510 | + * Rusty Russell (C)2000 -- This code is GPL. | |
511 | + * | |
512 | + * February 2000: Modified by James Morris to have 1 queue per protocol. | |
513 | + * 15-Mar-2000: Added NF_REPEAT --RR. | |
514 | + */ | |
515 | +#include <linux/config.h> | |
516 | +#include <linux/netfilter.h> | |
517 | +#include <net/protocol.h> | |
518 | +#include <linux/init.h> | |
519 | +#include <linux/skbuff.h> | |
520 | +#include <linux/wait.h> | |
521 | +#include <linux/module.h> | |
522 | +#include <linux/interrupt.h> | |
523 | +#include <linux/if.h> | |
524 | +#include <linux/netdevice.h> | |
525 | +#include <linux/inetdevice.h> | |
526 | +#include <linux/tcp.h> | |
527 | +#include <linux/udp.h> | |
528 | +#include <linux/icmp.h> | |
529 | +#include <net/sock.h> | |
530 | +#include <net/route.h> | |
531 | +#include <linux/ip.h> | |
532 | + | |
533 | +/* In this code, we can be waiting indefinitely for userspace to | |
534 | + * service a packet if a hook returns NF_QUEUE. We could keep a count | |
535 | + * of skbuffs queued for userspace, and not deregister a hook unless | |
536 | + * this is zero, but that sucks. Now, we simply check when the | |
537 | + * packets come back: if the hook is gone, the packet is discarded. */ | |
538 | +#ifdef CONFIG_NETFILTER_DEBUG | |
539 | +#define NFDEBUG(format, args...) printk(format , ## args) | |
540 | +#else | |
541 | +#define NFDEBUG(format, args...) | |
542 | +#endif | |
543 | + | |
544 | +/* Sockopts only registered and called from user context, so | |
545 | + net locking would be overkill. Also, [gs]etsockopt calls may | |
546 | + sleep. */ | |
547 | +static DECLARE_MUTEX(nf_sockopt_mutex); | |
548 | + | |
549 | +struct list_head nf_hooks[NPROTO][NF_MAX_HOOKS]; | |
550 | +static LIST_HEAD(nf_sockopts); | |
551 | +static spinlock_t nf_hook_lock = SPIN_LOCK_UNLOCKED; | |
552 | + | |
553 | +/* | |
554 | + * A queue handler may be registered for each protocol. Each is protected by | |
555 | + * long term mutex. The handler must provide an an outfn() to accept packets | |
556 | + * for queueing and must reinject all packets it receives, no matter what. | |
557 | + */ | |
558 | +static struct nf_queue_handler_t { | |
559 | + nf_queue_outfn_t outfn; | |
560 | + void *data; | |
561 | +} queue_handler[NPROTO]; | |
562 | +static rwlock_t queue_handler_lock = RW_LOCK_UNLOCKED; | |
563 | + | |
564 | +int nf_register_hook(struct nf_hook_ops *reg) | |
565 | +{ | |
566 | + struct list_head *i; | |
567 | + | |
568 | + spin_lock_bh(&nf_hook_lock); | |
569 | + list_for_each(i, &nf_hooks[reg->pf][reg->hooknum]) { | |
570 | + if (reg->priority < ((struct nf_hook_ops *)i)->priority) | |
571 | + break; | |
572 | + } | |
573 | + list_add_rcu(®->list, i->prev); | |
574 | + spin_unlock_bh(&nf_hook_lock); | |
575 | + | |
576 | + synchronize_net(); | |
577 | + return 0; | |
578 | +} | |
579 | + | |
580 | +void nf_unregister_hook(struct nf_hook_ops *reg) | |
581 | +{ | |
582 | + spin_lock_bh(&nf_hook_lock); | |
583 | + list_del_rcu(®->list); | |
584 | + spin_unlock_bh(&nf_hook_lock); | |
585 | + | |
586 | + synchronize_net(); | |
587 | +} | |
588 | + | |
589 | +/* Do exclusive ranges overlap? */ | |
590 | +static inline int overlap(int min1, int max1, int min2, int max2) | |
591 | +{ | |
592 | + return max1 > min2 && min1 < max2; | |
593 | +} | |
594 | + | |
595 | +/* Functions to register sockopt ranges (exclusive). */ | |
596 | +int nf_register_sockopt(struct nf_sockopt_ops *reg) | |
597 | +{ | |
598 | + struct list_head *i; | |
599 | + int ret = 0; | |
600 | + | |
601 | + if (down_interruptible(&nf_sockopt_mutex) != 0) | |
602 | + return -EINTR; | |
603 | + | |
604 | + list_for_each(i, &nf_sockopts) { | |
605 | + struct nf_sockopt_ops *ops = (struct nf_sockopt_ops *)i; | |
606 | + if (ops->pf == reg->pf | |
607 | + && (overlap(ops->set_optmin, ops->set_optmax, | |
608 | + reg->set_optmin, reg->set_optmax) | |
609 | + || overlap(ops->get_optmin, ops->get_optmax, | |
610 | + reg->get_optmin, reg->get_optmax))) { | |
611 | + NFDEBUG("nf_sock overlap: %u-%u/%u-%u v %u-%u/%u-%u\n", | |
612 | + ops->set_optmin, ops->set_optmax, | |
613 | + ops->get_optmin, ops->get_optmax, | |
614 | + reg->set_optmin, reg->set_optmax, | |
615 | + reg->get_optmin, reg->get_optmax); | |
616 | + ret = -EBUSY; | |
617 | + goto out; | |
618 | + } | |
619 | + } | |
620 | + | |
621 | + list_add(®->list, &nf_sockopts); | |
622 | +out: | |
623 | + up(&nf_sockopt_mutex); | |
624 | + return ret; | |
625 | +} | |
626 | + | |
627 | +void nf_unregister_sockopt(struct nf_sockopt_ops *reg) | |
628 | +{ | |
629 | + /* No point being interruptible: we're probably in cleanup_module() */ | |
630 | + restart: | |
631 | + down(&nf_sockopt_mutex); | |
632 | + if (reg->use != 0) { | |
633 | + /* To be woken by nf_sockopt call... */ | |
634 | + /* FIXME: Stuart Young's name appears gratuitously. */ | |
635 | + set_current_state(TASK_UNINTERRUPTIBLE); | |
636 | + reg->cleanup_task = current; | |
637 | + up(&nf_sockopt_mutex); | |
638 | + schedule(); | |
639 | + goto restart; | |
640 | + } | |
641 | + list_del(®->list); | |
642 | + up(&nf_sockopt_mutex); | |
643 | +} | |
644 | + | |
645 | +#ifdef CONFIG_NETFILTER_DEBUG | |
646 | +#include <net/ip.h> | |
647 | +#include <net/tcp.h> | |
648 | +#include <linux/netfilter_ipv4.h> | |
649 | + | |
650 | +static void debug_print_hooks_ip(unsigned int nf_debug) | |
651 | +{ | |
652 | + if (nf_debug & (1 << NF_IP_PRE_ROUTING)) { | |
653 | + printk("PRE_ROUTING "); | |
654 | + nf_debug ^= (1 << NF_IP_PRE_ROUTING); | |
655 | + } | |
656 | + if (nf_debug & (1 << NF_IP_LOCAL_IN)) { | |
657 | + printk("LOCAL_IN "); | |
658 | + nf_debug ^= (1 << NF_IP_LOCAL_IN); | |
659 | + } | |
660 | + if (nf_debug & (1 << NF_IP_FORWARD)) { | |
661 | + printk("FORWARD "); | |
662 | + nf_debug ^= (1 << NF_IP_FORWARD); | |
663 | + } | |
664 | + if (nf_debug & (1 << NF_IP_LOCAL_OUT)) { | |
665 | + printk("LOCAL_OUT "); | |
666 | + nf_debug ^= (1 << NF_IP_LOCAL_OUT); | |
667 | + } | |
668 | + if (nf_debug & (1 << NF_IP_POST_ROUTING)) { | |
669 | + printk("POST_ROUTING "); | |
670 | + nf_debug ^= (1 << NF_IP_POST_ROUTING); | |
671 | + } | |
672 | + if (nf_debug) | |
673 | + printk("Crap bits: 0x%04X", nf_debug); | |
674 | + printk("\n"); | |
675 | +} | |
676 | + | |
677 | +void nf_dump_skb(int pf, struct sk_buff *skb) | |
678 | +{ | |
679 | + printk("skb: pf=%i %s dev=%s len=%u\n", | |
680 | + pf, | |
681 | + skb->sk ? "(owned)" : "(unowned)", | |
682 | + skb->dev ? skb->dev->name : "(no dev)", | |
683 | + skb->len); | |
684 | + switch (pf) { | |
685 | + case PF_INET: { | |
686 | + const struct iphdr *ip = skb->nh.iph; | |
687 | + __u32 *opt = (__u32 *) (ip + 1); | |
688 | + int opti; | |
689 | + __u16 src_port = 0, dst_port = 0; | |
690 | + | |
691 | + if (ip->protocol == IPPROTO_TCP | |
692 | + || ip->protocol == IPPROTO_UDP) { | |
693 | + struct tcphdr *tcp=(struct tcphdr *)((__u32 *)ip+ip->ihl); | |
694 | + src_port = ntohs(tcp->source); | |
695 | + dst_port = ntohs(tcp->dest); | |
696 | + } | |
697 | + | |
698 | + printk("PROTO=%d %u.%u.%u.%u:%hu %u.%u.%u.%u:%hu" | |
699 | + " L=%hu S=0x%2.2hX I=%hu F=0x%4.4hX T=%hu", | |
700 | + ip->protocol, NIPQUAD(ip->saddr), | |
701 | + src_port, NIPQUAD(ip->daddr), | |
702 | + dst_port, | |
703 | + ntohs(ip->tot_len), ip->tos, ntohs(ip->id), | |
704 | + ntohs(ip->frag_off), ip->ttl); | |
705 | + | |
706 | + for (opti = 0; opti < (ip->ihl - sizeof(struct iphdr) / 4); opti++) | |
707 | + printk(" O=0x%8.8X", *opt++); | |
708 | + printk("\n"); | |
709 | + } | |
710 | + } | |
711 | +} | |
712 | + | |
713 | +void nf_debug_ip_local_deliver(struct sk_buff *skb) | |
714 | +{ | |
715 | + /* If it's a loopback packet, it must have come through | |
716 | + * NF_IP_LOCAL_OUT, NF_IP_RAW_INPUT, NF_IP_PRE_ROUTING and | |
717 | + * NF_IP_LOCAL_IN. Otherwise, must have gone through | |
718 | + * NF_IP_RAW_INPUT and NF_IP_PRE_ROUTING. */ | |
719 | + if (!skb->dev) { | |
720 | + printk("ip_local_deliver: skb->dev is NULL.\n"); | |
721 | + } | |
722 | + else if (strcmp(skb->dev->name, "lo") == 0) { | |
723 | + if (skb->nf_debug != ((1 << NF_IP_LOCAL_OUT) | |
724 | + | (1 << NF_IP_POST_ROUTING) | |
725 | + | (1 << NF_IP_PRE_ROUTING) | |
726 | + | (1 << NF_IP_LOCAL_IN))) { | |
727 | + printk("ip_local_deliver: bad loopback skb: "); | |
728 | + debug_print_hooks_ip(skb->nf_debug); | |
729 | + nf_dump_skb(PF_INET, skb); | |
730 | + } | |
731 | + } | |
732 | + else { | |
733 | + if (skb->nf_debug != ((1<<NF_IP_PRE_ROUTING) | |
734 | + | (1<<NF_IP_LOCAL_IN))) { | |
735 | + printk("ip_local_deliver: bad non-lo skb: "); | |
736 | + debug_print_hooks_ip(skb->nf_debug); | |
737 | + nf_dump_skb(PF_INET, skb); | |
738 | + } | |
739 | + } | |
740 | +} | |
741 | + | |
742 | +void nf_debug_ip_loopback_xmit(struct sk_buff *newskb) | |
743 | +{ | |
744 | + if (newskb->nf_debug != ((1 << NF_IP_LOCAL_OUT) | |
745 | + | (1 << NF_IP_POST_ROUTING))) { | |
746 | + printk("ip_dev_loopback_xmit: bad owned skb = %p: ", | |
747 | + newskb); | |
748 | + debug_print_hooks_ip(newskb->nf_debug); | |
749 | + nf_dump_skb(PF_INET, newskb); | |
750 | + } | |
751 | + /* Clear to avoid confusing input check */ | |
752 | + newskb->nf_debug = 0; | |
753 | +} | |
754 | + | |
755 | +void nf_debug_ip_finish_output2(struct sk_buff *skb) | |
756 | +{ | |
757 | + /* If it's owned, it must have gone through the | |
758 | + * NF_IP_LOCAL_OUT and NF_IP_POST_ROUTING. | |
759 | + * Otherwise, must have gone through | |
760 | + * NF_IP_PRE_ROUTING, NF_IP_FORWARD and NF_IP_POST_ROUTING. | |
761 | + */ | |
762 | + if (skb->sk) { | |
763 | + if (skb->nf_debug != ((1 << NF_IP_LOCAL_OUT) | |
764 | + | (1 << NF_IP_POST_ROUTING))) { | |
765 | + printk("ip_finish_output: bad owned skb = %p: ", skb); | |
766 | + debug_print_hooks_ip(skb->nf_debug); | |
767 | + nf_dump_skb(PF_INET, skb); | |
768 | + } | |
769 | + } else { | |
770 | + if (skb->nf_debug != ((1 << NF_IP_PRE_ROUTING) | |
771 | + | (1 << NF_IP_FORWARD) | |
772 | + | (1 << NF_IP_POST_ROUTING))) { | |
773 | + /* Fragments, entunnelled packets, TCP RSTs | |
774 | + generated by ipt_REJECT will have no | |
775 | + owners, but still may be local */ | |
776 | + if (skb->nf_debug != ((1 << NF_IP_LOCAL_OUT) | |
777 | + | (1 << NF_IP_POST_ROUTING))){ | |
778 | + printk("ip_finish_output:" | |
779 | + " bad unowned skb = %p: ",skb); | |
780 | + debug_print_hooks_ip(skb->nf_debug); | |
781 | + nf_dump_skb(PF_INET, skb); | |
782 | + } | |
783 | + } | |
784 | + } | |
785 | +} | |
786 | +#endif /*CONFIG_NETFILTER_DEBUG*/ | |
787 | + | |
788 | +/* Call get/setsockopt() */ | |
789 | +static int nf_sockopt(struct sock *sk, int pf, int val, | |
790 | + char *opt, int *len, int get) | |
791 | +{ | |
792 | + struct list_head *i; | |
793 | + struct nf_sockopt_ops *ops; | |
794 | + int ret; | |
795 | + | |
796 | + if (down_interruptible(&nf_sockopt_mutex) != 0) | |
797 | + return -EINTR; | |
798 | + | |
799 | + list_for_each(i, &nf_sockopts) { | |
800 | + ops = (struct nf_sockopt_ops *)i; | |
801 | + if (ops->pf == pf) { | |
802 | + if (get) { | |
803 | + if (val >= ops->get_optmin | |
804 | + && val < ops->get_optmax) { | |
805 | + ops->use++; | |
806 | + up(&nf_sockopt_mutex); | |
807 | + ret = ops->get(sk, val, opt, len); | |
808 | + goto out; | |
809 | + } | |
810 | + } else { | |
811 | + if (val >= ops->set_optmin | |
812 | + && val < ops->set_optmax) { | |
813 | + ops->use++; | |
814 | + up(&nf_sockopt_mutex); | |
815 | + ret = ops->set(sk, val, opt, *len); | |
816 | + goto out; | |
817 | + } | |
818 | + } | |
819 | + } | |
820 | + } | |
821 | + up(&nf_sockopt_mutex); | |
822 | + return -ENOPROTOOPT; | |
823 | + | |
824 | + out: | |
825 | + down(&nf_sockopt_mutex); | |
826 | + ops->use--; | |
827 | + if (ops->cleanup_task) | |
828 | + wake_up_process(ops->cleanup_task); | |
829 | + up(&nf_sockopt_mutex); | |
830 | + return ret; | |
831 | +} | |
832 | + | |
833 | +int nf_setsockopt(struct sock *sk, int pf, int val, char *opt, | |
834 | + int len) | |
835 | +{ | |
836 | + return nf_sockopt(sk, pf, val, opt, &len, 0); | |
837 | +} | |
838 | + | |
839 | +int nf_getsockopt(struct sock *sk, int pf, int val, char *opt, int *len) | |
840 | +{ | |
841 | + return nf_sockopt(sk, pf, val, opt, len, 1); | |
842 | +} | |
843 | + | |
844 | +static unsigned int nf_iterate(struct list_head *head, | |
845 | + struct sk_buff **skb, | |
846 | + int hook, | |
847 | + const struct net_device *indev, | |
848 | + const struct net_device *outdev, | |
849 | + struct list_head **i, | |
850 | + int (*okfn)(struct sk_buff *), | |
851 | + int hook_thresh) | |
852 | +{ | |
853 | + /* | |
854 | + * The caller must not block between calls to this | |
855 | + * function because of risk of continuing from deleted element. | |
856 | + */ | |
857 | + list_for_each_continue_rcu(*i, head) { | |
858 | + struct nf_hook_ops *elem = (struct nf_hook_ops *)*i; | |
859 | + | |
860 | + if (hook_thresh > elem->priority) | |
861 | + continue; | |
862 | + | |
863 | + /* Optimization: we don't need to hold module | |
864 | + reference here, since function can't sleep. --RR */ | |
865 | + switch (elem->hook(hook, skb, indev, outdev, okfn)) { | |
866 | + case NF_QUEUE: | |
867 | + return NF_QUEUE; | |
868 | + | |
869 | + case NF_STOLEN: | |
870 | + return NF_STOLEN; | |
871 | + | |
872 | + case NF_DROP: | |
873 | + return NF_DROP; | |
874 | + | |
875 | + case NF_REPEAT: | |
876 | + *i = (*i)->prev; | |
877 | + break; | |
878 | + | |
879 | +#ifdef CONFIG_NETFILTER_DEBUG | |
880 | + case NF_ACCEPT: | |
881 | + break; | |
882 | + | |
883 | + default: | |
884 | + NFDEBUG("Evil return from %p(%u).\n", | |
885 | + elem->hook, hook); | |
886 | +#endif | |
887 | + } | |
888 | + } | |
889 | + return NF_ACCEPT; | |
890 | +} | |
891 | + | |
892 | +int nf_register_queue_handler(int pf, nf_queue_outfn_t outfn, void *data) | |
893 | +{ | |
894 | + int ret; | |
895 | + | |
896 | + write_lock_bh(&queue_handler_lock); | |
897 | + if (queue_handler[pf].outfn) | |
898 | + ret = -EBUSY; | |
899 | + else { | |
900 | + queue_handler[pf].outfn = outfn; | |
901 | + queue_handler[pf].data = data; | |
902 | + ret = 0; | |
903 | + } | |
904 | + write_unlock_bh(&queue_handler_lock); | |
905 | + | |
906 | + return ret; | |
907 | +} | |
908 | + | |
909 | +/* The caller must flush their queue before this */ | |
910 | +int nf_unregister_queue_handler(int pf) | |
911 | +{ | |
912 | + write_lock_bh(&queue_handler_lock); | |
913 | + queue_handler[pf].outfn = NULL; | |
914 | + queue_handler[pf].data = NULL; | |
915 | + write_unlock_bh(&queue_handler_lock); | |
916 | + | |
917 | + return 0; | |
918 | +} | |
919 | + | |
920 | +/* | |
921 | + * Any packet that leaves via this function must come back | |
922 | + * through nf_reinject(). | |
923 | + */ | |
924 | +static int nf_queue(struct sk_buff *skb, | |
925 | + struct list_head *elem, | |
926 | + int pf, unsigned int hook, | |
927 | + struct net_device *indev, | |
928 | + struct net_device *outdev, | |
929 | + int (*okfn)(struct sk_buff *)) | |
930 | +{ | |
931 | + int status; | |
932 | + struct nf_info *info; | |
933 | +#ifdef CONFIG_BRIDGE_NETFILTER | |
934 | + struct net_device *physindev = NULL; | |
935 | + struct net_device *physoutdev = NULL; | |
936 | +#endif | |
937 | + | |
938 | + /* QUEUE == DROP if noone is waiting, to be safe. */ | |
939 | + read_lock(&queue_handler_lock); | |
940 | + if (!queue_handler[pf].outfn) { | |
941 | + read_unlock(&queue_handler_lock); | |
942 | + kfree_skb(skb); | |
943 | + return 1; | |
944 | + } | |
945 | + | |
946 | + info = kmalloc(sizeof(*info), GFP_ATOMIC); | |
947 | + if (!info) { | |
948 | + if (net_ratelimit()) | |
949 | + printk(KERN_ERR "OOM queueing packet %p\n", | |
950 | + skb); | |
951 | + read_unlock(&queue_handler_lock); | |
952 | + kfree_skb(skb); | |
953 | + return 1; | |
954 | + } | |
955 | + | |
956 | + *info = (struct nf_info) { | |
957 | + (struct nf_hook_ops *)elem, pf, hook, indev, outdev, okfn }; | |
958 | + | |
959 | + /* If it's going away, ignore hook. */ | |
960 | + if (!try_module_get(info->elem->owner)) { | |
961 | + read_unlock(&queue_handler_lock); | |
962 | + kfree(info); | |
963 | + return 0; | |
964 | + } | |
965 | + | |
966 | + /* Bump dev refs so they don't vanish while packet is out */ | |
967 | + if (indev) dev_hold(indev); | |
968 | + if (outdev) dev_hold(outdev); | |
969 | + | |
970 | +#ifdef CONFIG_BRIDGE_NETFILTER | |
971 | + if (skb->nf_bridge) { | |
972 | + physindev = skb->nf_bridge->physindev; | |
973 | + if (physindev) dev_hold(physindev); | |
974 | + physoutdev = skb->nf_bridge->physoutdev; | |
975 | + if (physoutdev) dev_hold(physoutdev); | |
976 | + } | |
977 | +#endif | |
978 | + | |
979 | + status = queue_handler[pf].outfn(skb, info, queue_handler[pf].data); | |
980 | + read_unlock(&queue_handler_lock); | |
981 | + | |
982 | + if (status < 0) { | |
983 | + /* James M doesn't say fuck enough. */ | |
984 | + if (indev) dev_put(indev); | |
985 | + if (outdev) dev_put(outdev); | |
986 | +#ifdef CONFIG_BRIDGE_NETFILTER | |
987 | + if (physindev) dev_put(physindev); | |
988 | + if (physoutdev) dev_put(physoutdev); | |
989 | +#endif | |
990 | + module_put(info->elem->owner); | |
991 | + kfree(info); | |
992 | + kfree_skb(skb); | |
993 | + return 1; | |
994 | + } | |
995 | + return 1; | |
996 | +} | |
997 | + | |
998 | +int nf_hook_slow(int pf, unsigned int hook, struct sk_buff *skb, | |
999 | + struct net_device *indev, | |
1000 | + struct net_device *outdev, | |
1001 | + int (*okfn)(struct sk_buff *), | |
1002 | + int hook_thresh) | |
1003 | +{ | |
1004 | + struct list_head *elem; | |
1005 | + unsigned int verdict; | |
1006 | + int ret = 0; | |
1007 | + | |
1008 | + if (skb->ip_summed == CHECKSUM_HW) { | |
1009 | + if (outdev == NULL) { | |
1010 | + skb->ip_summed = CHECKSUM_NONE; | |
1011 | + } else { | |
1012 | + skb_checksum_help(skb); | |
1013 | + } | |
1014 | + } | |
1015 | + | |
1016 | + /* We may already have this, but read-locks nest anyway */ | |
1017 | + rcu_read_lock(); | |
1018 | + | |
1019 | +#ifdef CONFIG_NETFILTER_DEBUG | |
1020 | + if (skb->nf_debug & (1 << hook)) { | |
1021 | + printk("nf_hook: hook %i already set.\n", hook); | |
1022 | + nf_dump_skb(pf, skb); | |
1023 | + } | |
1024 | + skb->nf_debug |= (1 << hook); | |
1025 | +#endif | |
1026 | + | |
1027 | + elem = &nf_hooks[pf][hook]; | |
1028 | + next_hook: | |
1029 | + verdict = nf_iterate(&nf_hooks[pf][hook], &skb, hook, indev, | |
1030 | + outdev, &elem, okfn, hook_thresh); | |
1031 | + if (verdict == NF_QUEUE) { | |
1032 | + NFDEBUG("nf_hook: Verdict = QUEUE.\n"); | |
1033 | + if (!nf_queue(skb, elem, pf, hook, indev, outdev, okfn)) | |
1034 | + goto next_hook; | |
1035 | + } | |
1036 | + | |
1037 | + switch (verdict) { | |
1038 | + case NF_ACCEPT: | |
1039 | + ret = okfn(skb); | |
1040 | + break; | |
1041 | + | |
1042 | + case NF_DROP: | |
1043 | + kfree_skb(skb); | |
1044 | + ret = -EPERM; | |
1045 | + break; | |
1046 | + } | |
1047 | + | |
1048 | + rcu_read_unlock(); | |
1049 | + return ret; | |
1050 | +} | |
1051 | + | |
1052 | +void nf_reinject(struct sk_buff *skb, struct nf_info *info, | |
1053 | + unsigned int verdict) | |
1054 | +{ | |
1055 | + struct list_head *elem = &info->elem->list; | |
1056 | + struct list_head *i; | |
1057 | + | |
1058 | + rcu_read_lock(); | |
1059 | + | |
1060 | + /* Release those devices we held, or Alexey will kill me. */ | |
1061 | + if (info->indev) dev_put(info->indev); | |
1062 | + if (info->outdev) dev_put(info->outdev); | |
1063 | +#ifdef CONFIG_BRIDGE_NETFILTER | |
1064 | + if (skb->nf_bridge) { | |
1065 | + if (skb->nf_bridge->physindev) | |
1066 | + dev_put(skb->nf_bridge->physindev); | |
1067 | + if (skb->nf_bridge->physoutdev) | |
1068 | + dev_put(skb->nf_bridge->physoutdev); | |
1069 | + } | |
1070 | +#endif | |
1071 | + | |
1072 | + /* Drop reference to owner of hook which queued us. */ | |
1073 | + module_put(info->elem->owner); | |
1074 | + | |
1075 | + list_for_each_rcu(i, &nf_hooks[info->pf][info->hook]) { | |
1076 | + if (i == elem) | |
1077 | + break; | |
1078 | + } | |
1079 | + | |
1080 | + if (elem == &nf_hooks[info->pf][info->hook]) { | |
1081 | + /* The module which sent it to userspace is gone. */ | |
1082 | + NFDEBUG("%s: module disappeared, dropping packet.\n", | |
1083 | + __FUNCTION__); | |
1084 | + verdict = NF_DROP; | |
1085 | + } | |
1086 | + | |
1087 | + /* Continue traversal iff userspace said ok... */ | |
1088 | + if (verdict == NF_REPEAT) { | |
1089 | + elem = elem->prev; | |
1090 | + verdict = NF_ACCEPT; | |
1091 | + } | |
1092 | + | |
1093 | + if (verdict == NF_ACCEPT) { | |
1094 | + next_hook: | |
1095 | + verdict = nf_iterate(&nf_hooks[info->pf][info->hook], | |
1096 | + &skb, info->hook, | |
1097 | + info->indev, info->outdev, &elem, | |
1098 | + info->okfn, INT_MIN); | |
1099 | + } | |
1100 | + | |
1101 | + switch (verdict) { | |
1102 | + case NF_ACCEPT: | |
1103 | + info->okfn(skb); | |
1104 | + break; | |
1105 | + | |
1106 | + case NF_QUEUE: | |
1107 | + if (!nf_queue(skb, elem, info->pf, info->hook, | |
1108 | + info->indev, info->outdev, info->okfn)) | |
1109 | + goto next_hook; | |
1110 | + break; | |
1111 | + } | |
1112 | + rcu_read_unlock(); | |
1113 | + | |
1114 | + if (verdict == NF_DROP) | |
1115 | + kfree_skb(skb); | |
1116 | + | |
1117 | + kfree(info); | |
1118 | + return; | |
1119 | +} | |
1120 | + | |
1121 | +#ifdef CONFIG_INET | |
1122 | +/* route_me_harder function, used by iptable_nat, iptable_mangle + ip_queue */ | |
1123 | +int ip_route_me_harder(struct sk_buff **pskb) | |
1124 | +{ | |
1125 | + struct iphdr *iph = (*pskb)->nh.iph; | |
1126 | + struct rtable *rt; | |
1127 | + struct flowi fl = {}; | |
1128 | + struct dst_entry *odst; | |
1129 | + unsigned int hh_len; | |
1130 | + | |
1131 | + /* some non-standard hacks like ipt_REJECT.c:send_reset() can cause | |
1132 | + * packets with foreign saddr to appear on the NF_IP_LOCAL_OUT hook. | |
1133 | + */ | |
1134 | + if (inet_addr_type(iph->saddr) == RTN_LOCAL) { | |
1135 | + fl.nl_u.ip4_u.daddr = iph->daddr; | |
1136 | + fl.nl_u.ip4_u.saddr = iph->saddr; | |
1137 | + fl.nl_u.ip4_u.tos = RT_TOS(iph->tos); | |
1138 | + fl.oif = (*pskb)->sk ? (*pskb)->sk->sk_bound_dev_if : 0; | |
1139 | +#ifdef CONFIG_IP_ROUTE_FWMARK | |
1140 | + fl.nl_u.ip4_u.fwmark = (*pskb)->nfmark; | |
1141 | +#endif | |
1142 | + if (ip_route_output_key(&rt, &fl) != 0) | |
1143 | + return -1; | |
1144 | + | |
1145 | + /* Drop old route. */ | |
1146 | + dst_release((*pskb)->dst); | |
1147 | + (*pskb)->dst = &rt->u.dst; | |
1148 | + } else { | |
1149 | + /* non-local src, find valid iif to satisfy | |
1150 | + * rp-filter when calling ip_route_input. */ | |
1151 | + fl.nl_u.ip4_u.daddr = iph->saddr; | |
1152 | + if (ip_route_output_key(&rt, &fl) != 0) | |
1153 | + return -1; | |
1154 | + | |
1155 | + odst = (*pskb)->dst; | |
1156 | + if (ip_route_input(*pskb, iph->daddr, iph->saddr, | |
1157 | + RT_TOS(iph->tos), rt->u.dst.dev) != 0) { | |
1158 | + dst_release(&rt->u.dst); | |
1159 | + return -1; | |
1160 | + } | |
1161 | + dst_release(&rt->u.dst); | |
1162 | + dst_release(odst); | |
1163 | + } | |
1164 | + | |
1165 | + if ((*pskb)->dst->error) | |
1166 | + return -1; | |
1167 | + | |
1168 | + /* Change in oif may mean change in hh_len. */ | |
1169 | + hh_len = (*pskb)->dst->dev->hard_header_len; | |
1170 | + if (skb_headroom(*pskb) < hh_len) { | |
1171 | + struct sk_buff *nskb; | |
1172 | + | |
1173 | + nskb = skb_realloc_headroom(*pskb, hh_len); | |
1174 | + if (!nskb) | |
1175 | + return -1; | |
1176 | + if ((*pskb)->sk) | |
1177 | + skb_set_owner_w(nskb, (*pskb)->sk); | |
1178 | + kfree_skb(*pskb); | |
1179 | + *pskb = nskb; | |
1180 | + } | |
1181 | + | |
1182 | + return 0; | |
1183 | +} | |
1184 | + | |
1185 | +int skb_ip_make_writable(struct sk_buff **pskb, unsigned int writable_len) | |
1186 | +{ | |
1187 | + struct sk_buff *nskb; | |
1188 | + unsigned int iplen; | |
1189 | + | |
1190 | + if (writable_len > (*pskb)->len) | |
1191 | + return 0; | |
1192 | + | |
1193 | + /* Not exclusive use of packet? Must copy. */ | |
1194 | + if (skb_shared(*pskb) || skb_cloned(*pskb)) | |
1195 | + goto copy_skb; | |
1196 | + | |
1197 | + /* Alexey says IP hdr is always modifiable and linear, so ok. */ | |
1198 | + if (writable_len <= (*pskb)->nh.iph->ihl*4) | |
1199 | + return 1; | |
1200 | + | |
1201 | + iplen = writable_len - (*pskb)->nh.iph->ihl*4; | |
1202 | + | |
1203 | + /* DaveM says protocol headers are also modifiable. */ | |
1204 | + switch ((*pskb)->nh.iph->protocol) { | |
1205 | + case IPPROTO_TCP: { | |
1206 | + struct tcphdr hdr; | |
1207 | + if (skb_copy_bits(*pskb, (*pskb)->nh.iph->ihl*4, | |
1208 | + &hdr, sizeof(hdr)) != 0) | |
1209 | + goto copy_skb; | |
1210 | + if (writable_len <= (*pskb)->nh.iph->ihl*4 + hdr.doff*4) | |
1211 | + goto pull_skb; | |
1212 | + goto copy_skb; | |
1213 | + } | |
1214 | + case IPPROTO_UDP: | |
1215 | + if (writable_len<=(*pskb)->nh.iph->ihl*4+sizeof(struct udphdr)) | |
1216 | + goto pull_skb; | |
1217 | + goto copy_skb; | |
1218 | + case IPPROTO_ICMP: | |
1219 | + if (writable_len | |
1220 | + <= (*pskb)->nh.iph->ihl*4 + sizeof(struct icmphdr)) | |
1221 | + goto pull_skb; | |
1222 | + goto copy_skb; | |
1223 | + /* Insert other cases here as desired */ | |
1224 | + } | |
1225 | + | |
1226 | +copy_skb: | |
1227 | + nskb = skb_copy(*pskb, GFP_ATOMIC); | |
1228 | + if (!nskb) | |
1229 | + return 0; | |
1230 | + BUG_ON(skb_is_nonlinear(nskb)); | |
1231 | + | |
1232 | + /* Rest of kernel will get very unhappy if we pass it a | |
1233 | + suddenly-orphaned skbuff */ | |
1234 | + if ((*pskb)->sk) | |
1235 | + skb_set_owner_w(nskb, (*pskb)->sk); | |
1236 | + kfree_skb(*pskb); | |
1237 | + *pskb = nskb; | |
1238 | + return 1; | |
1239 | + | |
1240 | +pull_skb: | |
1241 | + return pskb_may_pull(*pskb, writable_len); | |
1242 | +} | |
1243 | +EXPORT_SYMBOL(skb_ip_make_writable); | |
1244 | +#endif /*CONFIG_INET*/ | |
1245 | + | |
1246 | + | |
1247 | +/* This does not belong here, but ipt_REJECT needs it if connection | |
1248 | + tracking in use: without this, connection may not be in hash table, | |
1249 | + and hence manufactured ICMP or RST packets will not be associated | |
1250 | + with it. */ | |
1251 | +void (*ip_ct_attach)(struct sk_buff *, struct nf_ct_info *); | |
1252 | + | |
1253 | +void __init netfilter_init(void) | |
1254 | +{ | |
1255 | + int i, h; | |
1256 | + | |
1257 | + for (i = 0; i < NPROTO; i++) { | |
1258 | + for (h = 0; h < NF_MAX_HOOKS; h++) | |
1259 | + INIT_LIST_HEAD(&nf_hooks[i][h]); | |
1260 | + } | |
1261 | +} | |
1262 | + | |
1263 | +EXPORT_SYMBOL(ip_ct_attach); | |
1264 | +EXPORT_SYMBOL(ip_route_me_harder); | |
1265 | +EXPORT_SYMBOL(nf_getsockopt); | |
1266 | +EXPORT_SYMBOL(nf_hook_slow); | |
1267 | +EXPORT_SYMBOL(nf_hooks); | |
1268 | +EXPORT_SYMBOL(nf_register_hook); | |
1269 | +EXPORT_SYMBOL(nf_register_queue_handler); | |
1270 | +EXPORT_SYMBOL(nf_register_sockopt); | |
1271 | +EXPORT_SYMBOL(nf_reinject); | |
1272 | +EXPORT_SYMBOL(nf_setsockopt); | |
1273 | +EXPORT_SYMBOL(nf_unregister_hook); | |
1274 | +EXPORT_SYMBOL(nf_unregister_queue_handler); | |
1275 | +EXPORT_SYMBOL(nf_unregister_sockopt); | |
1276 | diff -Nur linux-2.6.4-rc2.org/net/ipv4/netfilter/Kconfig linux-2.6.4-rc2/net/ipv4/netfilter/Kconfig | |
1277 | --- linux-2.6.4-rc2.org/net/ipv4/netfilter/Kconfig 2004-03-04 06:16:58.000000000 +0000 | |
1278 | +++ linux-2.6.4-rc2/net/ipv4/netfilter/Kconfig 2004-03-05 07:40:24.000000000 +0000 | |
1279 | @@ -579,5 +579,60 @@ | |
1280 | ||
1281 | To compile it as a module, choose M here. If unsure, say N. | |
1282 | ||
1283 | +config IP_NF_TARGET_IPV4OPTSSTRIP | |
1284 | + tristate 'IPV4OPTSSTRIP target support' | |
1285 | + depends on IP_NF_MANGLE | |
1286 | + help | |
1287 | + | |
1288 | +config IP_NF_TARGET_TTL | |
1289 | + tristate 'TTL target support' | |
1290 | + depends on IP_NF_MANGLE | |
1291 | + help | |
1292 | + | |
1293 | +config IP_NF_MATCH_CONNLIMIT | |
1294 | + tristate 'Connections/IP limit match support' | |
1295 | + depends on IP_NF_IPTABLES | |
1296 | + help | |
1297 | + | |
1298 | +config IP_NF_MATCH_DSTLIMIT | |
1299 | + tristate 'dstlimit match support' | |
1300 | + depends on IP_NF_IPTABLES | |
1301 | + help | |
1302 | + | |
1303 | +config IP_NF_MATCH_FUZZY | |
1304 | + tristate 'fuzzy match support' | |
1305 | + depends on IP_NF_IPTABLES | |
1306 | + help | |
1307 | + | |
1308 | +config IP_NF_MATCH_IPV4OPTIONS | |
1309 | + tristate 'IPV4OPTIONS match support' | |
1310 | + depends on IP_NF_IPTABLES | |
1311 | + help | |
1312 | + | |
1313 | +config IP_NF_MATCH_MPORT | |
1314 | + tristate 'Multiple port with ranges match support' | |
1315 | + depends on IP_NF_IPTABLES | |
1316 | + help | |
1317 | + | |
1318 | +config IP_NF_MATCH_NTH | |
1319 | + tristate 'Nth match support' | |
1320 | + depends on IP_NF_IPTABLES | |
1321 | + help | |
1322 | + | |
1323 | +config IP_NF_MATCH_QUOTA | |
1324 | + tristate 'quota match support' | |
1325 | + depends on IP_NF_IPTABLES | |
1326 | + help | |
1327 | + | |
1328 | +config IP_NF_MATCH_REALM | |
1329 | + tristate 'realm match support' | |
1330 | + depends on IP_NF_IPTABLES && NET_CLS_ROUTE | |
1331 | + help | |
1332 | + | |
1333 | +config IP_NF_MATCH_SCTP | |
1334 | + tristate 'SCTP protocol match support' | |
1335 | + depends on IP_NF_IPTABLES | |
1336 | + help | |
1337 | + | |
1338 | endmenu | |
1339 | ||
1340 | diff -Nur linux-2.6.4-rc2.org/net/ipv4/netfilter/Makefile linux-2.6.4-rc2/net/ipv4/netfilter/Makefile | |
1341 | --- linux-2.6.4-rc2.org/net/ipv4/netfilter/Makefile 2004-03-04 06:16:38.000000000 +0000 | |
1342 | +++ linux-2.6.4-rc2/net/ipv4/netfilter/Makefile 2004-03-05 07:40:24.000000000 +0000 | |
1343 | @@ -42,15 +42,28 @@ | |
1344 | # matches | |
1345 | obj-$(CONFIG_IP_NF_MATCH_HELPER) += ipt_helper.o | |
1346 | obj-$(CONFIG_IP_NF_MATCH_LIMIT) += ipt_limit.o | |
1347 | +obj-$(CONFIG_IP_NF_MATCH_SCTP) += ipt_sctp.o | |
1348 | +obj-$(CONFIG_IP_NF_MATCH_QUOTA) += ipt_quota.o | |
1349 | +obj-$(CONFIG_IP_NF_MATCH_DSTLIMIT) += ipt_dstlimit.o | |
1350 | obj-$(CONFIG_IP_NF_MATCH_MARK) += ipt_mark.o | |
1351 | obj-$(CONFIG_IP_NF_MATCH_MAC) += ipt_mac.o | |
1352 | obj-$(CONFIG_IP_NF_MATCH_IPRANGE) += ipt_iprange.o | |
1353 | ||
1354 | obj-$(CONFIG_IP_NF_MATCH_PKTTYPE) += ipt_pkttype.o | |
1355 | obj-$(CONFIG_IP_NF_MATCH_MULTIPORT) += ipt_multiport.o | |
1356 | + | |
1357 | +obj-$(CONFIG_IP_NF_MATCH_MPORT) += ipt_mport.o | |
1358 | + | |
1359 | obj-$(CONFIG_IP_NF_MATCH_OWNER) += ipt_owner.o | |
1360 | obj-$(CONFIG_IP_NF_MATCH_TOS) += ipt_tos.o | |
1361 | ||
1362 | +obj-$(CONFIG_IP_NF_MATCH_NTH) += ipt_nth.o | |
1363 | + | |
1364 | +obj-$(CONFIG_IP_NF_MATCH_IPV4OPTIONS) += ipt_ipv4options.o | |
1365 | + | |
1366 | + | |
1367 | +obj-$(CONFIG_IP_NF_MATCH_FUZZY) += ipt_fuzzy.o | |
1368 | + | |
1369 | obj-$(CONFIG_IP_NF_MATCH_RECENT) += ipt_recent.o | |
1370 | ||
1371 | obj-$(CONFIG_IP_NF_MATCH_ECN) += ipt_ecn.o | |
1372 | @@ -61,8 +74,10 @@ | |
1373 | ||
1374 | obj-$(CONFIG_IP_NF_MATCH_TTL) += ipt_ttl.o | |
1375 | obj-$(CONFIG_IP_NF_MATCH_STATE) += ipt_state.o | |
1376 | +obj-$(CONFIG_IP_NF_MATCH_CONNLIMIT) += ipt_connlimit.o | |
1377 | obj-$(CONFIG_IP_NF_MATCH_CONNTRACK) += ipt_conntrack.o | |
1378 | obj-$(CONFIG_IP_NF_MATCH_TCPMSS) += ipt_tcpmss.o | |
1379 | +obj-$(CONFIG_IP_NF_MATCH_REALM) += ipt_realm.o | |
1380 | ||
1381 | obj-$(CONFIG_IP_NF_MATCH_PHYSDEV) += ipt_physdev.o | |
1382 | ||
1383 | @@ -79,6 +94,8 @@ | |
1384 | obj-$(CONFIG_IP_NF_TARGET_CLASSIFY) += ipt_CLASSIFY.o | |
1385 | obj-$(CONFIG_IP_NF_NAT_SNMP_BASIC) += ip_nat_snmp_basic.o | |
1386 | obj-$(CONFIG_IP_NF_TARGET_LOG) += ipt_LOG.o | |
1387 | +obj-$(CONFIG_IP_NF_TARGET_TTL) += ipt_TTL.o | |
1388 | +obj-$(CONFIG_IP_NF_TARGET_IPV4OPTSSTRIP) += ipt_IPV4OPTSSTRIP.o | |
1389 | obj-$(CONFIG_IP_NF_TARGET_ULOG) += ipt_ULOG.o | |
1390 | obj-$(CONFIG_IP_NF_TARGET_TCPMSS) += ipt_TCPMSS.o | |
1391 | ||
1392 | diff -Nur linux-2.6.4-rc2.org/net/ipv4/netfilter/ip_conntrack_core.c linux-2.6.4-rc2/net/ipv4/netfilter/ip_conntrack_core.c | |
1393 | --- linux-2.6.4-rc2.org/net/ipv4/netfilter/ip_conntrack_core.c 2004-03-04 06:16:34.000000000 +0000 | |
1394 | +++ linux-2.6.4-rc2/net/ipv4/netfilter/ip_conntrack_core.c 2004-03-05 07:39:43.000000000 +0000 | |
1395 | @@ -15,6 +15,8 @@ | |
1396 | * 16 Jul 2002: Harald Welte <laforge@gnumonks.org> | |
1397 | * - add usage/reference counts to ip_conntrack_expect | |
1398 | * - export ip_conntrack[_expect]_{find_get,put} functions | |
1399 | + * 05 Aug 2002: Harald Welte <laforge@gnumonks.org> | |
1400 | + * - added DocBook-style comments for public API | |
1401 | * */ | |
1402 | ||
1403 | #include <linux/config.h> | |
1404 | @@ -89,6 +91,10 @@ | |
1405 | return p; | |
1406 | } | |
1407 | ||
1408 | +/** | |
1409 | + * ip_ct_find_proto - Find layer 4 protocol helper for given protocol number | |
1410 | + * @protocol: protocol number | |
1411 | + */ | |
1412 | struct ip_conntrack_protocol *ip_ct_find_proto(u_int8_t protocol) | |
1413 | { | |
1414 | struct ip_conntrack_protocol *p; | |
1415 | @@ -112,6 +118,11 @@ | |
1416 | static int ip_conntrack_hash_rnd_initted; | |
1417 | static unsigned int ip_conntrack_hash_rnd; | |
1418 | ||
1419 | +/** | |
1420 | + * hash_conntrack - Calculate the position of an entry in the connection | |
1421 | + * tracking table. | |
1422 | + * @tuple: conntrack tuple which we want to calculate the hash position | |
1423 | + */ | |
1424 | static u_int32_t | |
1425 | hash_conntrack(const struct ip_conntrack_tuple *tuple) | |
1426 | { | |
1427 | @@ -124,6 +135,19 @@ | |
1428 | ip_conntrack_hash_rnd) % ip_conntrack_htable_size); | |
1429 | } | |
1430 | ||
1431 | +/** | |
1432 | + * get_tuple - set all the fields of a tuple which is passed as parameter | |
1433 | + * given a network buffer. | |
1434 | + * @iph:pointer an IP header. | |
1435 | + * @skb:network buffer for which we want to generate the tuple | |
1436 | + * @dataoff: FIXME: Deprecated? | |
1437 | + * @tuple: tuple which will be generate. Used as return parameter. | |
1438 | + * @protocol: structure which contains pointer to protocol specific functions. | |
1439 | + * | |
1440 | + * Note: This function doesn't allocate space for the tuple passed as | |
1441 | + * parameter. The function pkt_to_packet which set all the protocol specific | |
1442 | + * fields of a given tuple. | |
1443 | + */ | |
1444 | int | |
1445 | get_tuple(const struct iphdr *iph, | |
1446 | const struct sk_buff *skb, | |
1447 | @@ -145,6 +169,15 @@ | |
1448 | return protocol->pkt_to_tuple(skb, dataoff, tuple); | |
1449 | } | |
1450 | ||
1451 | +/** | |
1452 | + * invert_tuple - Returns the inverse of a given tuple. It is used to | |
1453 | + * calculate the tuple which represents the other sense of the flow | |
1454 | + * of a connection. | |
1455 | + * @inverse: the inverted tuple. Use as return value. | |
1456 | + * @orig: the original tuple which will be inverted. | |
1457 | + * @protocol: a pointer to the protocol structure which contains all the | |
1458 | + * specifical functions available for this tuple. | |
1459 | + */ | |
1460 | static int | |
1461 | invert_tuple(struct ip_conntrack_tuple *inverse, | |
1462 | const struct ip_conntrack_tuple *orig, | |
1463 | @@ -160,7 +193,15 @@ | |
1464 | ||
1465 | /* ip_conntrack_expect helper functions */ | |
1466 | ||
1467 | -/* Compare tuple parts depending on mask. */ | |
1468 | +/** | |
1469 | + * expect_cmp - compare a tuple with a expectation depending on a mask | |
1470 | + * @i: pointer to an expectation. | |
1471 | + * @tuple: tuple which will be compared with the expectation tuple. | |
1472 | + * | |
1473 | + * Actually the tuple field of an expectation is compared with a tuple | |
1474 | + * This function is used by LIST_FIND to find a expectation which match a te | |
1475 | + * given tuple. | |
1476 | + */ | |
1477 | static inline int expect_cmp(const struct ip_conntrack_expect *i, | |
1478 | const struct ip_conntrack_tuple *tuple) | |
1479 | { | |
1480 | @@ -168,6 +209,10 @@ | |
1481 | return ip_ct_tuple_mask_cmp(tuple, &i->tuple, &i->mask); | |
1482 | } | |
1483 | ||
1484 | +/** | |
1485 | + * destroy_expect - Release all the resources allocated by an expectation. | |
1486 | + * @exp: pointer to the expectation which we want to release. | |
1487 | + */ | |
1488 | static void | |
1489 | destroy_expect(struct ip_conntrack_expect *exp) | |
1490 | { | |
1491 | @@ -178,7 +223,11 @@ | |
1492 | kfree(exp); | |
1493 | } | |
1494 | ||
1495 | - | |
1496 | +/** | |
1497 | + * ip_conntrack_expect_put - it decrements the counter of use related | |
1498 | + * associated to an expectation and it calls destroy_expect. | |
1499 | + * @exp: pointer to the expectation which we want to release. | |
1500 | + */ | |
1501 | inline void ip_conntrack_expect_put(struct ip_conntrack_expect *exp) | |
1502 | { | |
1503 | IP_NF_ASSERT(exp); | |
1504 | @@ -198,7 +247,14 @@ | |
1505 | struct ip_conntrack_expect *, tuple); | |
1506 | } | |
1507 | ||
1508 | -/* Find a expectation corresponding to a tuple. */ | |
1509 | +/** | |
1510 | + * ip_conntrack_find_get - find conntrack according to tuple | |
1511 | + * @tuple: conntrack tuple for which we search conntrack | |
1512 | + * @ignored_conntrack: ignore this conntrack during search | |
1513 | + * | |
1514 | + * This function increments the reference count of the found | |
1515 | + * conntrack (if any). | |
1516 | + */ | |
1517 | struct ip_conntrack_expect * | |
1518 | ip_conntrack_expect_find_get(const struct ip_conntrack_tuple *tuple) | |
1519 | { | |
1520 | @@ -381,7 +437,14 @@ | |
1521 | return h; | |
1522 | } | |
1523 | ||
1524 | -/* Find a connection corresponding to a tuple. */ | |
1525 | +/** | |
1526 | + * ip_conntrack_find_get - find conntrack according to tuple | |
1527 | + * @tuple: conntrack tuple for which we search conntrack | |
1528 | + * @ignored_conntrack: ignore this conntrack during search | |
1529 | + * | |
1530 | + * This function increments the reference count of the found | |
1531 | + * conntrack (if any). | |
1532 | + */ | |
1533 | struct ip_conntrack_tuple_hash * | |
1534 | ip_conntrack_find_get(const struct ip_conntrack_tuple *tuple, | |
1535 | const struct ip_conntrack *ignored_conntrack) | |
1536 | @@ -409,7 +472,14 @@ | |
1537 | return ct; | |
1538 | } | |
1539 | ||
1540 | -/* Return conntrack and conntrack_info given skb->nfct->master */ | |
1541 | +/** | |
1542 | + * ip_conntrack_get - Return conntrack and conntrack_info for given skb | |
1543 | + * @skb: skb for which we want to find conntrack and conntrack_info | |
1544 | + * @ctinfo: pointer to ctinfo, used as return value | |
1545 | + * | |
1546 | + * This function resolves the respective conntrack and conntrack_info | |
1547 | + * structures for the connection this packet (skb) is part of. | |
1548 | + */ | |
1549 | struct ip_conntrack * | |
1550 | ip_conntrack_get(struct sk_buff *skb, enum ip_conntrack_info *ctinfo) | |
1551 | { | |
1552 | @@ -479,8 +549,14 @@ | |
1553 | return NF_DROP; | |
1554 | } | |
1555 | ||
1556 | -/* Returns true if a connection correspondings to the tuple (required | |
1557 | - for NAT). */ | |
1558 | +/** | |
1559 | + * ip_conntrack_tuple_taken - Find out if tuple is already in use | |
1560 | + * @tuple: tuple to be used for this test | |
1561 | + * @ignored_conntrack: conntrack which is excluded from result | |
1562 | + * | |
1563 | + * This function is called by the NAT code in order to find out if | |
1564 | + * a particular tuple is already in use by some connection. | |
1565 | + */ | |
1566 | int | |
1567 | ip_conntrack_tuple_taken(const struct ip_conntrack_tuple *tuple, | |
1568 | const struct ip_conntrack *ignored_conntrack) | |
1569 | @@ -606,7 +682,13 @@ | |
1570 | { | |
1571 | return ip_ct_tuple_mask_cmp(rtuple, &i->tuple, &i->mask); | |
1572 | } | |
1573 | - | |
1574 | +/** | |
1575 | + * ip_ct_find_helper - Find application helper according to tuple | |
1576 | + * @tuple: tuple for which helper needs to be found | |
1577 | + * | |
1578 | + * This function is used to determine if any registered conntrack helper | |
1579 | + * is to be used for the given tuple. | |
1580 | + */ | |
1581 | struct ip_conntrack_helper *ip_ct_find_helper(const struct ip_conntrack_tuple *tuple) | |
1582 | { | |
1583 | return LIST_FIND(&helpers, helper_cmp, | |
1584 | @@ -691,42 +773,50 @@ | |
1585 | struct ip_conntrack_expect *, tuple); | |
1586 | READ_UNLOCK(&ip_conntrack_expect_tuple_lock); | |
1587 | ||
1588 | - /* If master is not in hash table yet (ie. packet hasn't left | |
1589 | - this machine yet), how can other end know about expected? | |
1590 | - Hence these are not the droids you are looking for (if | |
1591 | - master ct never got confirmed, we'd hold a reference to it | |
1592 | - and weird things would happen to future packets). */ | |
1593 | - if (expected && !is_confirmed(expected->expectant)) | |
1594 | - expected = NULL; | |
1595 | - | |
1596 | - /* Look up the conntrack helper for master connections only */ | |
1597 | - if (!expected) | |
1598 | - conntrack->helper = ip_ct_find_helper(&repl_tuple); | |
1599 | - | |
1600 | - /* If the expectation is dying, then this is a loser. */ | |
1601 | - if (expected | |
1602 | - && expected->expectant->helper->timeout | |
1603 | - && ! del_timer(&expected->timeout)) | |
1604 | - expected = NULL; | |
1605 | - | |
1606 | if (expected) { | |
1607 | - DEBUGP("conntrack: expectation arrives ct=%p exp=%p\n", | |
1608 | - conntrack, expected); | |
1609 | - /* Welcome, Mr. Bond. We've been expecting you... */ | |
1610 | - IP_NF_ASSERT(master_ct(conntrack)); | |
1611 | - __set_bit(IPS_EXPECTED_BIT, &conntrack->status); | |
1612 | - conntrack->master = expected; | |
1613 | - expected->sibling = conntrack; | |
1614 | - LIST_DELETE(&ip_conntrack_expect_list, expected); | |
1615 | - expected->expectant->expecting--; | |
1616 | - nf_conntrack_get(&master_ct(conntrack)->infos[0]); | |
1617 | - } | |
1618 | - atomic_inc(&ip_conntrack_count); | |
1619 | + /* If master is not in hash table yet (ie. packet hasn't left | |
1620 | + this machine yet), how can other end know about expected? | |
1621 | + Hence these are not the droids you are looking for (if | |
1622 | + master ct never got confirmed, we'd hold a reference to it | |
1623 | + and weird things would happen to future packets). */ | |
1624 | + if (!is_confirmed(expected->expectant)) { | |
1625 | + | |
1626 | + conntrack->helper = ip_ct_find_helper(&repl_tuple); | |
1627 | + goto end; | |
1628 | + } | |
1629 | + | |
1630 | + /* Expectation is dying... */ | |
1631 | + if (expected->expectant->helper->timeout | |
1632 | + && ! del_timer(&expected->timeout)) { | |
1633 | + goto end; | |
1634 | + } | |
1635 | + | |
1636 | + DEBUGP("conntrack: expectation arrives ct=%p exp=%p\n", | |
1637 | + conntrack, expected); | |
1638 | + /* Welcome, Mr. Bond. We've been expecting you... */ | |
1639 | + IP_NF_ASSERT(master_ct(conntrack)); | |
1640 | + __set_bit(IPS_EXPECTED_BIT, &conntrack->status); | |
1641 | + conntrack->master = expected; | |
1642 | + expected->sibling = conntrack; | |
1643 | + LIST_DELETE(&ip_conntrack_expect_list, expected); | |
1644 | + expected->expectant->expecting--; | |
1645 | + nf_conntrack_get(&master_ct(conntrack)->infos[0]); | |
1646 | + | |
1647 | + /* this is a braindead... --pablo */ | |
1648 | + atomic_inc(&ip_conntrack_count); | |
1649 | + WRITE_UNLOCK(&ip_conntrack_lock); | |
1650 | + | |
1651 | + if (expected->expectfn) | |
1652 | + expected->expectfn(conntrack); | |
1653 | + | |
1654 | + goto ret; | |
1655 | + } else | |
1656 | + conntrack->helper = ip_ct_find_helper(&repl_tuple); | |
1657 | + | |
1658 | +end: atomic_inc(&ip_conntrack_count); | |
1659 | WRITE_UNLOCK(&ip_conntrack_lock); | |
1660 | ||
1661 | - if (expected && expected->expectfn) | |
1662 | - expected->expectfn(conntrack); | |
1663 | - return &conntrack->tuplehash[IP_CT_DIR_ORIGINAL]; | |
1664 | +ret: return &conntrack->tuplehash[IP_CT_DIR_ORIGINAL]; | |
1665 | } | |
1666 | ||
1667 | /* On success, returns conntrack ptr, sets skb->nfct and ctinfo */ | |
1668 | @@ -900,6 +990,14 @@ | |
1669 | return ip_ct_tuple_mask_cmp(&i->tuple, tuple, &intersect_mask); | |
1670 | } | |
1671 | ||
1672 | +/** | |
1673 | + * ip_conntrack_unexpect_related - Unexpect a related connection | |
1674 | + * @expect: expecattin to be removed | |
1675 | + * | |
1676 | + * This function removes an existing expectation, that has not yet been | |
1677 | + * confirmed (i.e. expectation was issued, but expected connection didn't | |
1678 | + * arrive yet) | |
1679 | + */ | |
1680 | inline void ip_conntrack_unexpect_related(struct ip_conntrack_expect *expect) | |
1681 | { | |
1682 | WRITE_LOCK(&ip_conntrack_lock); | |
1683 | @@ -917,7 +1015,20 @@ | |
1684 | WRITE_UNLOCK(&ip_conntrack_lock); | |
1685 | } | |
1686 | ||
1687 | -/* Add a related connection. */ | |
1688 | +/** | |
1689 | + * ip_conntrack_expect_related - Expect a related connection | |
1690 | + * @related_to: master conntrack | |
1691 | + * @expect: expectation with all values filled in | |
1692 | + * | |
1693 | + * This function is called by conntrack application helpers who | |
1694 | + * have detected that the control (master) connection is just about | |
1695 | + * to negotiate a related slave connection. | |
1696 | + * | |
1697 | + * Note: This function allocates it's own struct ip_conntrack_expect, | |
1698 | + * copying the values from the 'expect' parameter. Thus, 'expect' can | |
1699 | + * be allocated on the stack and does not need to be valid after this | |
1700 | + * function returns. | |
1701 | + */ | |
1702 | int ip_conntrack_expect_related(struct ip_conntrack *related_to, | |
1703 | struct ip_conntrack_expect *expect) | |
1704 | { | |
1705 | @@ -1047,7 +1158,15 @@ | |
1706 | return ret; | |
1707 | } | |
1708 | ||
1709 | -/* Change tuple in an existing expectation */ | |
1710 | +/** | |
1711 | + * ip_conntrack_change_expect - Change tuple in existing expectation | |
1712 | + * @expect: expectation which is to be changed | |
1713 | + * @newtuple: new tuple for expect | |
1714 | + * | |
1715 | + * This function is mostly called by NAT application helpers, who want to | |
1716 | + * change an expectation issued by their respective conntrack application | |
1717 | + * helper counterpart. | |
1718 | + */ | |
1719 | int ip_conntrack_change_expect(struct ip_conntrack_expect *expect, | |
1720 | struct ip_conntrack_tuple *newtuple) | |
1721 | { | |
1722 | @@ -1088,8 +1207,15 @@ | |
1723 | return ret; | |
1724 | } | |
1725 | ||
1726 | -/* Alter reply tuple (maybe alter helper). If it's already taken, | |
1727 | - return 0 and don't do alteration. */ | |
1728 | +/** | |
1729 | + * ip_conntrack_alter_reply - Alter reply tuple of conntrack | |
1730 | + * @conntrack: conntrack whose reply tuple we want to alter | |
1731 | + * @newreply: designated reply tuple for this conntrack | |
1732 | + * | |
1733 | + * This function alters the reply tuple of a conntrack to the given | |
1734 | + * newreply tuple. If this newreply tuple is already taken, return 0 | |
1735 | + * and don't do alteration | |
1736 | + */ | |
1737 | int ip_conntrack_alter_reply(struct ip_conntrack *conntrack, | |
1738 | const struct ip_conntrack_tuple *newreply) | |
1739 | { | |
1740 | @@ -1114,6 +1240,13 @@ | |
1741 | return 1; | |
1742 | } | |
1743 | ||
1744 | +/** | |
1745 | + * ip_conntrack_helper_register - Register a conntrack application helper | |
1746 | + * @me: structure describing the helper | |
1747 | + * | |
1748 | + * This function is called by conntrack application helpers to register | |
1749 | + * themselves with the conntrack core. | |
1750 | + */ | |
1751 | int ip_conntrack_helper_register(struct ip_conntrack_helper *me) | |
1752 | { | |
1753 | WRITE_LOCK(&ip_conntrack_lock); | |
1754 | @@ -1135,6 +1268,13 @@ | |
1755 | return 0; | |
1756 | } | |
1757 | ||
1758 | +/** | |
1759 | + * ip_conntrack_helper_unregister - Unregister a conntrack application helper | |
1760 | + * @me: structure describing the helper | |
1761 | + * | |
1762 | + * This function is called by conntrack application helpers to unregister | |
1763 | + * themselvers from the conntrack core. | |
1764 | + */ | |
1765 | void ip_conntrack_helper_unregister(struct ip_conntrack_helper *me) | |
1766 | { | |
1767 | unsigned int i; | |
1768 | @@ -1153,7 +1293,14 @@ | |
1769 | synchronize_net(); | |
1770 | } | |
1771 | ||
1772 | -/* Refresh conntrack for this many jiffies. */ | |
1773 | +/** | |
1774 | + * ip_ct_refresh - Refresh conntrack timer for given conntrack | |
1775 | + * @ct: conntrack which we want to refresh | |
1776 | + * @extra_jiffies: number of jiffies to add | |
1777 | + * | |
1778 | + * This function is called by protocol helpers and application helpers in | |
1779 | + * order to change the expiration timer of a conntrack entry. | |
1780 | + */ | |
1781 | void ip_ct_refresh(struct ip_conntrack *ct, unsigned long extra_jiffies) | |
1782 | { | |
1783 | IP_NF_ASSERT(ct->timeout.data == (unsigned long)ct); | |
1784 | @@ -1172,7 +1319,16 @@ | |
1785 | WRITE_UNLOCK(&ip_conntrack_lock); | |
1786 | } | |
1787 | ||
1788 | -/* Returns new sk_buff, or NULL */ | |
1789 | + | |
1790 | +/** | |
1791 | + * ip_ct_gather_frags - Gather fragments of a particular skb | |
1792 | + * @skb: pointer to sk_buff of fragmented IP packet | |
1793 | + * | |
1794 | + * This code is just a wrapper around the defragmentation code in the core IPv4 | |
1795 | + * stack. It also takes care of nonlinear skb's. | |
1796 | + * | |
1797 | + * Returns new sk_buff, or NULL | |
1798 | + */ | |
1799 | struct sk_buff * | |
1800 | ip_ct_gather_frags(struct sk_buff *skb) | |
1801 | { | |
1802 | @@ -1256,6 +1412,16 @@ | |
1803 | return h; | |
1804 | } | |
1805 | ||
1806 | +/** | |
1807 | + * ip_ct_selective_cleanup - Selectively delete a set of conntrack entries | |
1808 | + * @kill: callback function selecting which entries to delete | |
1809 | + * @data: opaque data pointer, becomes 2nd argument for kill function | |
1810 | + * | |
1811 | + * This function can be used to selectively delete elements of the conntrack | |
1812 | + * hashtable. The function iterates over the list of conntrack entries and | |
1813 | + * calls the 'kill' function for every entry. If the return value is true, | |
1814 | + * the connection is deleted (death_by_timeout). | |
1815 | + */ | |
1816 | void | |
1817 | ip_ct_selective_cleanup(int (*kill)(const struct ip_conntrack *i, void *data), | |
1818 | void *data) | |
1819 | diff -Nur linux-2.6.4-rc2.org/net/ipv4/netfilter/ip_conntrack_core.c.orig linux-2.6.4-rc2/net/ipv4/netfilter/ip_conntrack_core.c.orig | |
1820 | --- linux-2.6.4-rc2.org/net/ipv4/netfilter/ip_conntrack_core.c.orig 1970-01-01 00:00:00.000000000 +0000 | |
1821 | +++ linux-2.6.4-rc2/net/ipv4/netfilter/ip_conntrack_core.c.orig 2004-03-05 07:39:41.000000000 +0000 | |
1822 | @@ -0,0 +1,1441 @@ | |
1823 | +/* Connection state tracking for netfilter. This is separated from, | |
1824 | + but required by, the NAT layer; it can also be used by an iptables | |
1825 | + extension. */ | |
1826 | + | |
1827 | +/* (C) 1999-2001 Paul `Rusty' Russell | |
1828 | + * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org> | |
1829 | + * | |
1830 | + * This program is free software; you can redistribute it and/or modify | |
1831 | + * it under the terms of the GNU General Public License version 2 as | |
1832 | + * published by the Free Software Foundation. | |
1833 | + * | |
1834 | + * 23 Apr 2001: Harald Welte <laforge@gnumonks.org> | |
1835 | + * - new API and handling of conntrack/nat helpers | |
1836 | + * - now capable of multiple expectations for one master | |
1837 | + * 16 Jul 2002: Harald Welte <laforge@gnumonks.org> | |
1838 | + * - add usage/reference counts to ip_conntrack_expect | |
1839 | + * - export ip_conntrack[_expect]_{find_get,put} functions | |
1840 | + * */ | |
1841 | + | |
1842 | +#include <linux/config.h> | |
1843 | +#include <linux/types.h> | |
1844 | +#include <linux/icmp.h> | |
1845 | +#include <linux/ip.h> | |
1846 | +#include <linux/netfilter.h> | |
1847 | +#include <linux/netfilter_ipv4.h> | |
1848 | +#include <linux/module.h> | |
1849 | +#include <linux/skbuff.h> | |
1850 | +#include <linux/proc_fs.h> | |
1851 | +#include <linux/vmalloc.h> | |
1852 | +#include <net/checksum.h> | |
1853 | +#include <linux/stddef.h> | |
1854 | +#include <linux/sysctl.h> | |
1855 | +#include <linux/slab.h> | |
1856 | +#include <linux/random.h> | |
1857 | +#include <linux/jhash.h> | |
1858 | +/* For ERR_PTR(). Yeah, I know... --RR */ | |
1859 | +#include <linux/fs.h> | |
1860 | + | |
1861 | +/* This rwlock protects the main hash table, protocol/helper/expected | |
1862 | + registrations, conntrack timers*/ | |
1863 | +#define ASSERT_READ_LOCK(x) MUST_BE_READ_LOCKED(&ip_conntrack_lock) | |
1864 | +#define ASSERT_WRITE_LOCK(x) MUST_BE_WRITE_LOCKED(&ip_conntrack_lock) | |
1865 | + | |
1866 | +#include <linux/netfilter_ipv4/ip_conntrack.h> | |
1867 | +#include <linux/netfilter_ipv4/ip_conntrack_protocol.h> | |
1868 | +#include <linux/netfilter_ipv4/ip_conntrack_helper.h> | |
1869 | +#include <linux/netfilter_ipv4/ip_conntrack_core.h> | |
1870 | +#include <linux/netfilter_ipv4/listhelp.h> | |
1871 | + | |
1872 | +#define IP_CONNTRACK_VERSION "2.1" | |
1873 | + | |
1874 | +#if 0 | |
1875 | +#define DEBUGP printk | |
1876 | +#else | |
1877 | +#define DEBUGP(format, args...) | |
1878 | +#endif | |
1879 | + | |
1880 | +DECLARE_RWLOCK(ip_conntrack_lock); | |
1881 | +DECLARE_RWLOCK(ip_conntrack_expect_tuple_lock); | |
1882 | + | |
1883 | +void (*ip_conntrack_destroyed)(struct ip_conntrack *conntrack) = NULL; | |
1884 | +LIST_HEAD(ip_conntrack_expect_list); | |
1885 | +LIST_HEAD(protocol_list); | |
1886 | +static LIST_HEAD(helpers); | |
1887 | +unsigned int ip_conntrack_htable_size = 0; | |
1888 | +int ip_conntrack_max; | |
1889 | +static atomic_t ip_conntrack_count = ATOMIC_INIT(0); | |
1890 | +struct list_head *ip_conntrack_hash; | |
1891 | +static kmem_cache_t *ip_conntrack_cachep; | |
1892 | + | |
1893 | +extern struct ip_conntrack_protocol ip_conntrack_generic_protocol; | |
1894 | + | |
1895 | +static inline int proto_cmpfn(const struct ip_conntrack_protocol *curr, | |
1896 | + u_int8_t protocol) | |
1897 | +{ | |
1898 | + return protocol == curr->proto; | |
1899 | +} | |
1900 | + | |
1901 | +struct ip_conntrack_protocol *__ip_ct_find_proto(u_int8_t protocol) | |
1902 | +{ | |
1903 | + struct ip_conntrack_protocol *p; | |
1904 | + | |
1905 | + MUST_BE_READ_LOCKED(&ip_conntrack_lock); | |
1906 | + p = LIST_FIND(&protocol_list, proto_cmpfn, | |
1907 | + struct ip_conntrack_protocol *, protocol); | |
1908 | + if (!p) | |
1909 | + p = &ip_conntrack_generic_protocol; | |
1910 | + | |
1911 | + return p; | |
1912 | +} | |
1913 | + | |
1914 | +struct ip_conntrack_protocol *ip_ct_find_proto(u_int8_t protocol) | |
1915 | +{ | |
1916 | + struct ip_conntrack_protocol *p; | |
1917 | + | |
1918 | + READ_LOCK(&ip_conntrack_lock); | |
1919 | + p = __ip_ct_find_proto(protocol); | |
1920 | + READ_UNLOCK(&ip_conntrack_lock); | |
1921 | + return p; | |
1922 | +} | |
1923 | + | |
1924 | +inline void | |
1925 | +ip_conntrack_put(struct ip_conntrack *ct) | |
1926 | +{ | |
1927 | + IP_NF_ASSERT(ct); | |
1928 | + IP_NF_ASSERT(ct->infos[0].master); | |
1929 | + /* nf_conntrack_put wants to go via an info struct, so feed it | |
1930 | + one at random. */ | |
1931 | + nf_conntrack_put(&ct->infos[0]); | |
1932 | +} | |
1933 | + | |
1934 | +static int ip_conntrack_hash_rnd_initted; | |
1935 | +static unsigned int ip_conntrack_hash_rnd; | |
1936 | + | |
1937 | +static u_int32_t | |
1938 | +hash_conntrack(const struct ip_conntrack_tuple *tuple) | |
1939 | +{ | |
1940 | +#if 0 | |
1941 | + dump_tuple(tuple); | |
1942 | +#endif | |
1943 | + return (jhash_3words(tuple->src.ip, | |
1944 | + (tuple->dst.ip ^ tuple->dst.protonum), | |
1945 | + (tuple->src.u.all | (tuple->dst.u.all << 16)), | |
1946 | + ip_conntrack_hash_rnd) % ip_conntrack_htable_size); | |
1947 | +} | |
1948 | + | |
1949 | +int | |
1950 | +get_tuple(const struct iphdr *iph, | |
1951 | + const struct sk_buff *skb, | |
1952 | + unsigned int dataoff, | |
1953 | + struct ip_conntrack_tuple *tuple, | |
1954 | + const struct ip_conntrack_protocol *protocol) | |
1955 | +{ | |
1956 | + /* Never happen */ | |
1957 | + if (iph->frag_off & htons(IP_OFFSET)) { | |
1958 | + printk("ip_conntrack_core: Frag of proto %u.\n", | |
1959 | + iph->protocol); | |
1960 | + return 0; | |
1961 | + } | |
1962 | + | |
1963 | + tuple->src.ip = iph->saddr; | |
1964 | + tuple->dst.ip = iph->daddr; | |
1965 | + tuple->dst.protonum = iph->protocol; | |
1966 | + | |
1967 | + return protocol->pkt_to_tuple(skb, dataoff, tuple); | |
1968 | +} | |
1969 | + | |
1970 | +static int | |
1971 | +invert_tuple(struct ip_conntrack_tuple *inverse, | |
1972 | + const struct ip_conntrack_tuple *orig, | |
1973 | + const struct ip_conntrack_protocol *protocol) | |
1974 | +{ | |
1975 | + inverse->src.ip = orig->dst.ip; | |
1976 | + inverse->dst.ip = orig->src.ip; | |
1977 | + inverse->dst.protonum = orig->dst.protonum; | |
1978 | + | |
1979 | + return protocol->invert_tuple(inverse, orig); | |
1980 | +} | |
1981 | + | |
1982 | + | |
1983 | +/* ip_conntrack_expect helper functions */ | |
1984 | + | |
1985 | +/* Compare tuple parts depending on mask. */ | |
1986 | +static inline int expect_cmp(const struct ip_conntrack_expect *i, | |
1987 | + const struct ip_conntrack_tuple *tuple) | |
1988 | +{ | |
1989 | + MUST_BE_READ_LOCKED(&ip_conntrack_expect_tuple_lock); | |
1990 | + return ip_ct_tuple_mask_cmp(tuple, &i->tuple, &i->mask); | |
1991 | +} | |
1992 | + | |
1993 | +static void | |
1994 | +destroy_expect(struct ip_conntrack_expect *exp) | |
1995 | +{ | |
1996 | + DEBUGP("destroy_expect(%p) use=%d\n", exp, atomic_read(&exp->use)); | |
1997 | + IP_NF_ASSERT(atomic_read(&exp->use)); | |
1998 | + IP_NF_ASSERT(!timer_pending(&exp->timeout)); | |
1999 | + | |
2000 | + kfree(exp); | |
2001 | +} | |
2002 | + | |
2003 | + | |
2004 | +inline void ip_conntrack_expect_put(struct ip_conntrack_expect *exp) | |
2005 | +{ | |
2006 | + IP_NF_ASSERT(exp); | |
2007 | + | |
2008 | + if (atomic_dec_and_test(&exp->use)) { | |
2009 | + /* usage count dropped to zero */ | |
2010 | + destroy_expect(exp); | |
2011 | + } | |
2012 | +} | |
2013 | + | |
2014 | +static inline struct ip_conntrack_expect * | |
2015 | +__ip_ct_expect_find(const struct ip_conntrack_tuple *tuple) | |
2016 | +{ | |
2017 | + MUST_BE_READ_LOCKED(&ip_conntrack_lock); | |
2018 | + MUST_BE_READ_LOCKED(&ip_conntrack_expect_tuple_lock); | |
2019 | + return LIST_FIND(&ip_conntrack_expect_list, expect_cmp, | |
2020 | + struct ip_conntrack_expect *, tuple); | |
2021 | +} | |
2022 | + | |
2023 | +/* Find a expectation corresponding to a tuple. */ | |
2024 | +struct ip_conntrack_expect * | |
2025 | +ip_conntrack_expect_find_get(const struct ip_conntrack_tuple *tuple) | |
2026 | +{ | |
2027 | + struct ip_conntrack_expect *exp; | |
2028 | + | |
2029 | + READ_LOCK(&ip_conntrack_lock); | |
2030 | + READ_LOCK(&ip_conntrack_expect_tuple_lock); | |
2031 | + exp = __ip_ct_expect_find(tuple); | |
2032 | + if (exp) | |
2033 | + atomic_inc(&exp->use); | |
2034 | + READ_UNLOCK(&ip_conntrack_expect_tuple_lock); | |
2035 | + READ_UNLOCK(&ip_conntrack_lock); | |
2036 | + | |
2037 | + return exp; | |
2038 | +} | |
2039 | + | |
2040 | +/* remove one specific expectation from all lists and drop refcount, | |
2041 | + * does _NOT_ delete the timer. */ | |
2042 | +static void __unexpect_related(struct ip_conntrack_expect *expect) | |
2043 | +{ | |
2044 | + DEBUGP("unexpect_related(%p)\n", expect); | |
2045 | + MUST_BE_WRITE_LOCKED(&ip_conntrack_lock); | |
2046 | + | |
2047 | + /* we're not allowed to unexpect a confirmed expectation! */ | |
2048 | + IP_NF_ASSERT(!expect->sibling); | |
2049 | + | |
2050 | + /* delete from global and local lists */ | |
2051 | + list_del(&expect->list); | |
2052 | + list_del(&expect->expected_list); | |
2053 | + | |
2054 | + /* decrement expect-count of master conntrack */ | |
2055 | + if (expect->expectant) | |
2056 | + expect->expectant->expecting--; | |
2057 | + | |
2058 | + ip_conntrack_expect_put(expect); | |
2059 | +} | |
2060 | + | |
2061 | +/* remove one specific expecatation from all lists, drop refcount | |
2062 | + * and expire timer. | |
2063 | + * This function can _NOT_ be called for confirmed expects! */ | |
2064 | +static void unexpect_related(struct ip_conntrack_expect *expect) | |
2065 | +{ | |
2066 | + IP_NF_ASSERT(expect->expectant); | |
2067 | + IP_NF_ASSERT(expect->expectant->helper); | |
2068 | + /* if we are supposed to have a timer, but we can't delete | |
2069 | + * it: race condition. __unexpect_related will | |
2070 | + * be calledd by timeout function */ | |
2071 | + if (expect->expectant->helper->timeout | |
2072 | + && !del_timer(&expect->timeout)) | |
2073 | + return; | |
2074 | + | |
2075 | + __unexpect_related(expect); | |
2076 | +} | |
2077 | + | |
2078 | +/* delete all unconfirmed expectations for this conntrack */ | |
2079 | +static void remove_expectations(struct ip_conntrack *ct, int drop_refcount) | |
2080 | +{ | |
2081 | + struct list_head *exp_entry, *next; | |
2082 | + struct ip_conntrack_expect *exp; | |
2083 | + | |
2084 | + DEBUGP("remove_expectations(%p)\n", ct); | |
2085 | + | |
2086 | + list_for_each_safe(exp_entry, next, &ct->sibling_list) { | |
2087 | + exp = list_entry(exp_entry, struct ip_conntrack_expect, | |
2088 | + expected_list); | |
2089 | + | |
2090 | + /* we skip established expectations, as we want to delete | |
2091 | + * the un-established ones only */ | |
2092 | + if (exp->sibling) { | |
2093 | + DEBUGP("remove_expectations: skipping established %p of %p\n", exp->sibling, ct); | |
2094 | + if (drop_refcount) { | |
2095 | + /* Indicate that this expectations parent is dead */ | |
2096 | + ip_conntrack_put(exp->expectant); | |
2097 | + exp->expectant = NULL; | |
2098 | + } | |
2099 | + continue; | |
2100 | + } | |
2101 | + | |
2102 | + IP_NF_ASSERT(list_inlist(&ip_conntrack_expect_list, exp)); | |
2103 | + IP_NF_ASSERT(exp->expectant == ct); | |
2104 | + | |
2105 | + /* delete expectation from global and private lists */ | |
2106 | + unexpect_related(exp); | |
2107 | + } | |
2108 | +} | |
2109 | + | |
2110 | +static void | |
2111 | +clean_from_lists(struct ip_conntrack *ct) | |
2112 | +{ | |
2113 | + unsigned int ho, hr; | |
2114 | + | |
2115 | + DEBUGP("clean_from_lists(%p)\n", ct); | |
2116 | + MUST_BE_WRITE_LOCKED(&ip_conntrack_lock); | |
2117 | + | |
2118 | + ho = hash_conntrack(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); | |
2119 | + hr = hash_conntrack(&ct->tuplehash[IP_CT_DIR_REPLY].tuple); | |
2120 | + LIST_DELETE(&ip_conntrack_hash[ho], &ct->tuplehash[IP_CT_DIR_ORIGINAL]); | |
2121 | + LIST_DELETE(&ip_conntrack_hash[hr], &ct->tuplehash[IP_CT_DIR_REPLY]); | |
2122 | + | |
2123 | + /* Destroy all un-established, pending expectations */ | |
2124 | + remove_expectations(ct, 1); | |
2125 | +} | |
2126 | + | |
2127 | +static void | |
2128 | +destroy_conntrack(struct nf_conntrack *nfct) | |
2129 | +{ | |
2130 | + struct ip_conntrack *ct = (struct ip_conntrack *)nfct, *master = NULL; | |
2131 | + struct ip_conntrack_protocol *proto; | |
2132 | + | |
2133 | + DEBUGP("destroy_conntrack(%p)\n", ct); | |
2134 | + IP_NF_ASSERT(atomic_read(&nfct->use) == 0); | |
2135 | + IP_NF_ASSERT(!timer_pending(&ct->timeout)); | |
2136 | + | |
2137 | + /* To make sure we don't get any weird locking issues here: | |
2138 | + * destroy_conntrack() MUST NOT be called with a write lock | |
2139 | + * to ip_conntrack_lock!!! -HW */ | |
2140 | + proto = ip_ct_find_proto(ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.protonum); | |
2141 | + if (proto && proto->destroy) | |
2142 | + proto->destroy(ct); | |
2143 | + | |
2144 | + if (ip_conntrack_destroyed) | |
2145 | + ip_conntrack_destroyed(ct); | |
2146 | + | |
2147 | + WRITE_LOCK(&ip_conntrack_lock); | |
2148 | + /* Delete us from our own list to prevent corruption later */ | |
2149 | + list_del(&ct->sibling_list); | |
2150 | + | |
2151 | + /* Delete our master expectation */ | |
2152 | + if (ct->master) { | |
2153 | + if (ct->master->expectant) { | |
2154 | + /* can't call __unexpect_related here, | |
2155 | + * since it would screw up expect_list */ | |
2156 | + list_del(&ct->master->expected_list); | |
2157 | + master = ct->master->expectant; | |
2158 | + } | |
2159 | + kfree(ct->master); | |
2160 | + } | |
2161 | + WRITE_UNLOCK(&ip_conntrack_lock); | |
2162 | + | |
2163 | + if (master) | |
2164 | + ip_conntrack_put(master); | |
2165 | + | |
2166 | + DEBUGP("destroy_conntrack: returning ct=%p to slab\n", ct); | |
2167 | + kmem_cache_free(ip_conntrack_cachep, ct); | |
2168 | + atomic_dec(&ip_conntrack_count); | |
2169 | +} | |
2170 | + | |
2171 | +static void death_by_timeout(unsigned long ul_conntrack) | |
2172 | +{ | |
2173 | + struct ip_conntrack *ct = (void *)ul_conntrack; | |
2174 | + | |
2175 | + WRITE_LOCK(&ip_conntrack_lock); | |
2176 | + clean_from_lists(ct); | |
2177 | + WRITE_UNLOCK(&ip_conntrack_lock); | |
2178 | + ip_conntrack_put(ct); | |
2179 | +} | |
2180 | + | |
2181 | +static inline int | |
2182 | +conntrack_tuple_cmp(const struct ip_conntrack_tuple_hash *i, | |
2183 | + const struct ip_conntrack_tuple *tuple, | |
2184 | + const struct ip_conntrack *ignored_conntrack) | |
2185 | +{ | |
2186 | + MUST_BE_READ_LOCKED(&ip_conntrack_lock); | |
2187 | + return i->ctrack != ignored_conntrack | |
2188 | + && ip_ct_tuple_equal(tuple, &i->tuple); | |
2189 | +} | |
2190 | + | |
2191 | +static struct ip_conntrack_tuple_hash * | |
2192 | +__ip_conntrack_find(const struct ip_conntrack_tuple *tuple, | |
2193 | + const struct ip_conntrack *ignored_conntrack) | |
2194 | +{ | |
2195 | + struct ip_conntrack_tuple_hash *h; | |
2196 | + unsigned int hash = hash_conntrack(tuple); | |
2197 | + | |
2198 | + MUST_BE_READ_LOCKED(&ip_conntrack_lock); | |
2199 | + h = LIST_FIND(&ip_conntrack_hash[hash], | |
2200 | + conntrack_tuple_cmp, | |
2201 | + struct ip_conntrack_tuple_hash *, | |
2202 | + tuple, ignored_conntrack); | |
2203 | + return h; | |
2204 | +} | |
2205 | + | |
2206 | +/* Find a connection corresponding to a tuple. */ | |
2207 | +struct ip_conntrack_tuple_hash * | |
2208 | +ip_conntrack_find_get(const struct ip_conntrack_tuple *tuple, | |
2209 | + const struct ip_conntrack *ignored_conntrack) | |
2210 | +{ | |
2211 | + struct ip_conntrack_tuple_hash *h; | |
2212 | + | |
2213 | + READ_LOCK(&ip_conntrack_lock); | |
2214 | + h = __ip_conntrack_find(tuple, ignored_conntrack); | |
2215 | + if (h) | |
2216 | + atomic_inc(&h->ctrack->ct_general.use); | |
2217 | + READ_UNLOCK(&ip_conntrack_lock); | |
2218 | + | |
2219 | + return h; | |
2220 | +} | |
2221 | + | |
2222 | +static inline struct ip_conntrack * | |
2223 | +__ip_conntrack_get(struct nf_ct_info *nfct, enum ip_conntrack_info *ctinfo) | |
2224 | +{ | |
2225 | + struct ip_conntrack *ct | |
2226 | + = (struct ip_conntrack *)nfct->master; | |
2227 | + | |
2228 | + /* ctinfo is the index of the nfct inside the conntrack */ | |
2229 | + *ctinfo = nfct - ct->infos; | |
2230 | + IP_NF_ASSERT(*ctinfo >= 0 && *ctinfo < IP_CT_NUMBER); | |
2231 | + return ct; | |
2232 | +} | |
2233 | + | |
2234 | +/* Return conntrack and conntrack_info given skb->nfct->master */ | |
2235 | +struct ip_conntrack * | |
2236 | +ip_conntrack_get(struct sk_buff *skb, enum ip_conntrack_info *ctinfo) | |
2237 | +{ | |
2238 | + if (skb->nfct) | |
2239 | + return __ip_conntrack_get(skb->nfct, ctinfo); | |
2240 | + return NULL; | |
2241 | +} | |
2242 | + | |
2243 | +/* Confirm a connection given skb->nfct; places it in hash table */ | |
2244 | +int | |
2245 | +__ip_conntrack_confirm(struct nf_ct_info *nfct) | |
2246 | +{ | |
2247 | + unsigned int hash, repl_hash; | |
2248 | + struct ip_conntrack *ct; | |
2249 | + enum ip_conntrack_info ctinfo; | |
2250 | + | |
2251 | + ct = __ip_conntrack_get(nfct, &ctinfo); | |
2252 | + | |
2253 | + /* ipt_REJECT uses ip_conntrack_attach to attach related | |
2254 | + ICMP/TCP RST packets in other direction. Actual packet | |
2255 | + which created connection will be IP_CT_NEW or for an | |
2256 | + expected connection, IP_CT_RELATED. */ | |
2257 | + if (CTINFO2DIR(ctinfo) != IP_CT_DIR_ORIGINAL) | |
2258 | + return NF_ACCEPT; | |
2259 | + | |
2260 | + hash = hash_conntrack(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); | |
2261 | + repl_hash = hash_conntrack(&ct->tuplehash[IP_CT_DIR_REPLY].tuple); | |
2262 | + | |
2263 | + /* We're not in hash table, and we refuse to set up related | |
2264 | + connections for unconfirmed conns. But packet copies and | |
2265 | + REJECT will give spurious warnings here. */ | |
2266 | + /* IP_NF_ASSERT(atomic_read(&ct->ct_general.use) == 1); */ | |
2267 | + | |
2268 | + /* No external references means noone else could have | |
2269 | + confirmed us. */ | |
2270 | + IP_NF_ASSERT(!is_confirmed(ct)); | |
2271 | + DEBUGP("Confirming conntrack %p\n", ct); | |
2272 | + | |
2273 | + WRITE_LOCK(&ip_conntrack_lock); | |
2274 | + /* See if there's one in the list already, including reverse: | |
2275 | + NAT could have grabbed it without realizing, since we're | |
2276 | + not in the hash. If there is, we lost race. */ | |
2277 | + if (!LIST_FIND(&ip_conntrack_hash[hash], | |
2278 | + conntrack_tuple_cmp, | |
2279 | + struct ip_conntrack_tuple_hash *, | |
2280 | + &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple, NULL) | |
2281 | + && !LIST_FIND(&ip_conntrack_hash[repl_hash], | |
2282 | + conntrack_tuple_cmp, | |
2283 | + struct ip_conntrack_tuple_hash *, | |
2284 | + &ct->tuplehash[IP_CT_DIR_REPLY].tuple, NULL)) { | |
2285 | + list_prepend(&ip_conntrack_hash[hash], | |
2286 | + &ct->tuplehash[IP_CT_DIR_ORIGINAL]); | |
2287 | + list_prepend(&ip_conntrack_hash[repl_hash], | |
2288 | + &ct->tuplehash[IP_CT_DIR_REPLY]); | |
2289 | + /* Timer relative to confirmation time, not original | |
2290 | + setting time, otherwise we'd get timer wrap in | |
2291 | + weird delay cases. */ | |
2292 | + ct->timeout.expires += jiffies; | |
2293 | + add_timer(&ct->timeout); | |
2294 | + atomic_inc(&ct->ct_general.use); | |
2295 | + set_bit(IPS_CONFIRMED_BIT, &ct->status); | |
2296 | + WRITE_UNLOCK(&ip_conntrack_lock); | |
2297 | + return NF_ACCEPT; | |
2298 | + } | |
2299 | + | |
2300 | + WRITE_UNLOCK(&ip_conntrack_lock); | |
2301 | + return NF_DROP; | |
2302 | +} | |
2303 | + | |
2304 | +/* Returns true if a connection correspondings to the tuple (required | |
2305 | + for NAT). */ | |
2306 | +int | |
2307 | +ip_conntrack_tuple_taken(const struct ip_conntrack_tuple *tuple, | |
2308 | + const struct ip_conntrack *ignored_conntrack) | |
2309 | +{ | |
2310 | + struct ip_conntrack_tuple_hash *h; | |
2311 | + | |
2312 | + READ_LOCK(&ip_conntrack_lock); | |
2313 | + h = __ip_conntrack_find(tuple, ignored_conntrack); | |
2314 | + READ_UNLOCK(&ip_conntrack_lock); | |
2315 | + | |
2316 | + return h != NULL; | |
2317 | +} | |
2318 | + | |
2319 | +/* Returns conntrack if it dealt with ICMP, and filled in skb fields */ | |
2320 | +struct ip_conntrack * | |
2321 | +icmp_error_track(struct sk_buff *skb, | |
2322 | + enum ip_conntrack_info *ctinfo, | |
2323 | + unsigned int hooknum) | |
2324 | +{ | |
2325 | + struct ip_conntrack_tuple innertuple, origtuple; | |
2326 | + struct { | |
2327 | + struct icmphdr icmp; | |
2328 | + struct iphdr ip; | |
2329 | + } inside; | |
2330 | + struct ip_conntrack_protocol *innerproto; | |
2331 | + struct ip_conntrack_tuple_hash *h; | |
2332 | + int dataoff; | |
2333 | + | |
2334 | + IP_NF_ASSERT(skb->nfct == NULL); | |
2335 | + | |
2336 | + /* Not enough header? */ | |
2337 | + if (skb_copy_bits(skb, skb->nh.iph->ihl*4, &inside, sizeof(inside))!=0) | |
2338 | + return NULL; | |
2339 | + | |
2340 | + if (inside.icmp.type != ICMP_DEST_UNREACH | |
2341 | + && inside.icmp.type != ICMP_SOURCE_QUENCH | |
2342 | + && inside.icmp.type != ICMP_TIME_EXCEEDED | |
2343 | + && inside.icmp.type != ICMP_PARAMETERPROB | |
2344 | + && inside.icmp.type != ICMP_REDIRECT) | |
2345 | + return NULL; | |
2346 | + | |
2347 | + /* Ignore ICMP's containing fragments (shouldn't happen) */ | |
2348 | + if (inside.ip.frag_off & htons(IP_OFFSET)) { | |
2349 | + DEBUGP("icmp_error_track: fragment of proto %u\n", | |
2350 | + inside.ip.protocol); | |
2351 | + return NULL; | |
2352 | + } | |
2353 | + | |
2354 | + innerproto = ip_ct_find_proto(inside.ip.protocol); | |
2355 | + dataoff = skb->nh.iph->ihl*4 + sizeof(inside.icmp) + inside.ip.ihl*4; | |
2356 | + /* Are they talking about one of our connections? */ | |
2357 | + if (!get_tuple(&inside.ip, skb, dataoff, &origtuple, innerproto)) { | |
2358 | + DEBUGP("icmp_error: ! get_tuple p=%u", inside.ip.protocol); | |
2359 | + return NULL; | |
2360 | + } | |
2361 | + | |
2362 | + /* Ordinarily, we'd expect the inverted tupleproto, but it's | |
2363 | + been preserved inside the ICMP. */ | |
2364 | + if (!invert_tuple(&innertuple, &origtuple, innerproto)) { | |
2365 | + DEBUGP("icmp_error_track: Can't invert tuple\n"); | |
2366 | + return NULL; | |
2367 | + } | |
2368 | + | |
2369 | + *ctinfo = IP_CT_RELATED; | |
2370 | + | |
2371 | + h = ip_conntrack_find_get(&innertuple, NULL); | |
2372 | + if (!h) { | |
2373 | + /* Locally generated ICMPs will match inverted if they | |
2374 | + haven't been SNAT'ed yet */ | |
2375 | + /* FIXME: NAT code has to handle half-done double NAT --RR */ | |
2376 | + if (hooknum == NF_IP_LOCAL_OUT) | |
2377 | + h = ip_conntrack_find_get(&origtuple, NULL); | |
2378 | + | |
2379 | + if (!h) { | |
2380 | + DEBUGP("icmp_error_track: no match\n"); | |
2381 | + return NULL; | |
2382 | + } | |
2383 | + /* Reverse direction from that found */ | |
2384 | + if (DIRECTION(h) != IP_CT_DIR_REPLY) | |
2385 | + *ctinfo += IP_CT_IS_REPLY; | |
2386 | + } else { | |
2387 | + if (DIRECTION(h) == IP_CT_DIR_REPLY) | |
2388 | + *ctinfo += IP_CT_IS_REPLY; | |
2389 | + } | |
2390 | + | |
2391 | + /* Update skb to refer to this connection */ | |
2392 | + skb->nfct = &h->ctrack->infos[*ctinfo]; | |
2393 | + return h->ctrack; | |
2394 | +} | |
2395 | + | |
2396 | +/* There's a small race here where we may free a just-assured | |
2397 | + connection. Too bad: we're in trouble anyway. */ | |
2398 | +static inline int unreplied(const struct ip_conntrack_tuple_hash *i) | |
2399 | +{ | |
2400 | + return !(test_bit(IPS_ASSURED_BIT, &i->ctrack->status)); | |
2401 | +} | |
2402 | + | |
2403 | +static int early_drop(struct list_head *chain) | |
2404 | +{ | |
2405 | + /* Traverse backwards: gives us oldest, which is roughly LRU */ | |
2406 | + struct ip_conntrack_tuple_hash *h; | |
2407 | + int dropped = 0; | |
2408 | + | |
2409 | + READ_LOCK(&ip_conntrack_lock); | |
2410 | + h = LIST_FIND_B(chain, unreplied, struct ip_conntrack_tuple_hash *); | |
2411 | + if (h) | |
2412 | + atomic_inc(&h->ctrack->ct_general.use); | |
2413 | + READ_UNLOCK(&ip_conntrack_lock); | |
2414 | + | |
2415 | + if (!h) | |
2416 | + return dropped; | |
2417 | + | |
2418 | + if (del_timer(&h->ctrack->timeout)) { | |
2419 | + death_by_timeout((unsigned long)h->ctrack); | |
2420 | + dropped = 1; | |
2421 | + } | |
2422 | + ip_conntrack_put(h->ctrack); | |
2423 | + return dropped; | |
2424 | +} | |
2425 | + | |
2426 | +static inline int helper_cmp(const struct ip_conntrack_helper *i, | |
2427 | + const struct ip_conntrack_tuple *rtuple) | |
2428 | +{ | |
2429 | + return ip_ct_tuple_mask_cmp(rtuple, &i->tuple, &i->mask); | |
2430 | +} | |
2431 | + | |
2432 | +struct ip_conntrack_helper *ip_ct_find_helper(const struct ip_conntrack_tuple *tuple) | |
2433 | +{ | |
2434 | + return LIST_FIND(&helpers, helper_cmp, | |
2435 | + struct ip_conntrack_helper *, | |
2436 | + tuple); | |
2437 | +} | |
2438 | + | |
2439 | +/* Allocate a new conntrack: we return -ENOMEM if classification | |
2440 | + failed due to stress. Otherwise it really is unclassifiable. */ | |
2441 | +static struct ip_conntrack_tuple_hash * | |
2442 | +init_conntrack(const struct ip_conntrack_tuple *tuple, | |
2443 | + struct ip_conntrack_protocol *protocol, | |
2444 | + struct sk_buff *skb) | |
2445 | +{ | |
2446 | + struct ip_conntrack *conntrack; | |
2447 | + struct ip_conntrack_tuple repl_tuple; | |
2448 | + size_t hash; | |
2449 | + struct ip_conntrack_expect *expected; | |
2450 | + int i; | |
2451 | + static unsigned int drop_next; | |
2452 | + | |
2453 | + if (!ip_conntrack_hash_rnd_initted) { | |
2454 | + get_random_bytes(&ip_conntrack_hash_rnd, 4); | |
2455 | + ip_conntrack_hash_rnd_initted = 1; | |
2456 | + } | |
2457 | + | |
2458 | + hash = hash_conntrack(tuple); | |
2459 | + | |
2460 | + if (ip_conntrack_max && | |
2461 | + atomic_read(&ip_conntrack_count) >= ip_conntrack_max) { | |
2462 | + /* Try dropping from random chain, or else from the | |
2463 | + chain about to put into (in case they're trying to | |
2464 | + bomb one hash chain). */ | |
2465 | + unsigned int next = (drop_next++)%ip_conntrack_htable_size; | |
2466 | + | |
2467 | + if (!early_drop(&ip_conntrack_hash[next]) | |
2468 | + && !early_drop(&ip_conntrack_hash[hash])) { | |
2469 | + if (net_ratelimit()) | |
2470 | + printk(KERN_WARNING | |
2471 | + "ip_conntrack: table full, dropping" | |
2472 | + " packet.\n"); | |
2473 | + return ERR_PTR(-ENOMEM); | |
2474 | + } | |
2475 | + } | |
2476 | + | |
2477 | + if (!invert_tuple(&repl_tuple, tuple, protocol)) { | |
2478 | + DEBUGP("Can't invert tuple.\n"); | |
2479 | + return NULL; | |
2480 | + } | |
2481 | + | |
2482 | + conntrack = kmem_cache_alloc(ip_conntrack_cachep, GFP_ATOMIC); | |
2483 | + if (!conntrack) { | |
2484 | + DEBUGP("Can't allocate conntrack.\n"); | |
2485 | + return ERR_PTR(-ENOMEM); | |
2486 | + } | |
2487 | + | |
2488 | + memset(conntrack, 0, sizeof(*conntrack)); | |
2489 | + atomic_set(&conntrack->ct_general.use, 1); | |
2490 | + conntrack->ct_general.destroy = destroy_conntrack; | |
2491 | + conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple = *tuple; | |
2492 | + conntrack->tuplehash[IP_CT_DIR_ORIGINAL].ctrack = conntrack; | |
2493 | + conntrack->tuplehash[IP_CT_DIR_REPLY].tuple = repl_tuple; | |
2494 | + conntrack->tuplehash[IP_CT_DIR_REPLY].ctrack = conntrack; | |
2495 | + for (i=0; i < IP_CT_NUMBER; i++) | |
2496 | + conntrack->infos[i].master = &conntrack->ct_general; | |
2497 | + | |
2498 | + if (!protocol->new(conntrack, skb)) { | |
2499 | + kmem_cache_free(ip_conntrack_cachep, conntrack); | |
2500 | + return NULL; | |
2501 | + } | |
2502 | + /* Don't set timer yet: wait for confirmation */ | |
2503 | + init_timer(&conntrack->timeout); | |
2504 | + conntrack->timeout.data = (unsigned long)conntrack; | |
2505 | + conntrack->timeout.function = death_by_timeout; | |
2506 | + | |
2507 | + INIT_LIST_HEAD(&conntrack->sibling_list); | |
2508 | + | |
2509 | + WRITE_LOCK(&ip_conntrack_lock); | |
2510 | + /* Need finding and deleting of expected ONLY if we win race */ | |
2511 | + READ_LOCK(&ip_conntrack_expect_tuple_lock); | |
2512 | + expected = LIST_FIND(&ip_conntrack_expect_list, expect_cmp, | |
2513 | + struct ip_conntrack_expect *, tuple); | |
2514 | + READ_UNLOCK(&ip_conntrack_expect_tuple_lock); | |
2515 | + | |
2516 | + if (expected) { | |
2517 | + /* If master is not in hash table yet (ie. packet hasn't left | |
2518 | + this machine yet), how can other end know about expected? | |
2519 | + Hence these are not the droids you are looking for (if | |
2520 | + master ct never got confirmed, we'd hold a reference to it | |
2521 | + and weird things would happen to future packets). */ | |
2522 | + if (!is_confirmed(expected->expectant)) { | |
2523 | + | |
2524 | + conntrack->helper = ip_ct_find_helper(&repl_tuple); | |
2525 | + goto end; | |
2526 | + } | |
2527 | + | |
2528 | + /* Expectation is dying... */ | |
2529 | + if (expected->expectant->helper->timeout | |
2530 | + && ! del_timer(&expected->timeout)) { | |
2531 | + goto end; | |
2532 | + } | |
2533 | + | |
2534 | + DEBUGP("conntrack: expectation arrives ct=%p exp=%p\n", | |
2535 | + conntrack, expected); | |
2536 | + /* Welcome, Mr. Bond. We've been expecting you... */ | |
2537 | + IP_NF_ASSERT(master_ct(conntrack)); | |
2538 | + __set_bit(IPS_EXPECTED_BIT, &conntrack->status); | |
2539 | + conntrack->master = expected; | |
2540 | + expected->sibling = conntrack; | |
2541 | + LIST_DELETE(&ip_conntrack_expect_list, expected); | |
2542 | + expected->expectant->expecting--; | |
2543 | + nf_conntrack_get(&master_ct(conntrack)->infos[0]); | |
2544 | + | |
2545 | + /* this is a braindead... --pablo */ | |
2546 | + atomic_inc(&ip_conntrack_count); | |
2547 | + WRITE_UNLOCK(&ip_conntrack_lock); | |
2548 | + | |
2549 | + if (expected->expectfn) | |
2550 | + expected->expectfn(conntrack); | |
2551 | + | |
2552 | + goto ret; | |
2553 | + } else | |
2554 | + conntrack->helper = ip_ct_find_helper(&repl_tuple); | |
2555 | + | |
2556 | +end: atomic_inc(&ip_conntrack_count); | |
2557 | + WRITE_UNLOCK(&ip_conntrack_lock); | |
2558 | + | |
2559 | +ret: return &conntrack->tuplehash[IP_CT_DIR_ORIGINAL]; | |
2560 | +} | |
2561 | + | |
2562 | +/* On success, returns conntrack ptr, sets skb->nfct and ctinfo */ | |
2563 | +static inline struct ip_conntrack * | |
2564 | +resolve_normal_ct(struct sk_buff *skb, | |
2565 | + struct ip_conntrack_protocol *proto, | |
2566 | + int *set_reply, | |
2567 | + unsigned int hooknum, | |
2568 | + enum ip_conntrack_info *ctinfo) | |
2569 | +{ | |
2570 | + struct ip_conntrack_tuple tuple; | |
2571 | + struct ip_conntrack_tuple_hash *h; | |
2572 | + | |
2573 | + IP_NF_ASSERT((skb->nh.iph->frag_off & htons(IP_OFFSET)) == 0); | |
2574 | + | |
2575 | + if (!get_tuple(skb->nh.iph, skb, skb->nh.iph->ihl*4, &tuple, proto)) | |
2576 | + return NULL; | |
2577 | + | |
2578 | + /* look for tuple match */ | |
2579 | + h = ip_conntrack_find_get(&tuple, NULL); | |
2580 | + if (!h) { | |
2581 | + h = init_conntrack(&tuple, proto, skb); | |
2582 | + if (!h) | |
2583 | + return NULL; | |
2584 | + if (IS_ERR(h)) | |
2585 | + return (void *)h; | |
2586 | + } | |
2587 | + | |
2588 | + /* It exists; we have (non-exclusive) reference. */ | |
2589 | + if (DIRECTION(h) == IP_CT_DIR_REPLY) { | |
2590 | + *ctinfo = IP_CT_ESTABLISHED + IP_CT_IS_REPLY; | |
2591 | + /* Please set reply bit if this packet OK */ | |
2592 | + *set_reply = 1; | |
2593 | + } else { | |
2594 | + /* Once we've had two way comms, always ESTABLISHED. */ | |
2595 | + if (test_bit(IPS_SEEN_REPLY_BIT, &h->ctrack->status)) { | |
2596 | + DEBUGP("ip_conntrack_in: normal packet for %p\n", | |
2597 | + h->ctrack); | |
2598 | + *ctinfo = IP_CT_ESTABLISHED; | |
2599 | + } else if (test_bit(IPS_EXPECTED_BIT, &h->ctrack->status)) { | |
2600 | + DEBUGP("ip_conntrack_in: related packet for %p\n", | |
2601 | + h->ctrack); | |
2602 | + *ctinfo = IP_CT_RELATED; | |
2603 | + } else { | |
2604 | + DEBUGP("ip_conntrack_in: new packet for %p\n", | |
2605 | + h->ctrack); | |
2606 | + *ctinfo = IP_CT_NEW; | |
2607 | + } | |
2608 | + *set_reply = 0; | |
2609 | + } | |
2610 | + skb->nfct = &h->ctrack->infos[*ctinfo]; | |
2611 | + return h->ctrack; | |
2612 | +} | |
2613 | + | |
2614 | +/* Netfilter hook itself. */ | |
2615 | +unsigned int ip_conntrack_in(unsigned int hooknum, | |
2616 | + struct sk_buff **pskb, | |
2617 | + const struct net_device *in, | |
2618 | + const struct net_device *out, | |
2619 | + int (*okfn)(struct sk_buff *)) | |
2620 | +{ | |
2621 | + struct ip_conntrack *ct; | |
2622 | + enum ip_conntrack_info ctinfo; | |
2623 | + struct ip_conntrack_protocol *proto; | |
2624 | + int set_reply; | |
2625 | + int ret; | |
2626 | + | |
2627 | + /* FIXME: Do this right please. --RR */ | |
2628 | + (*pskb)->nfcache |= NFC_UNKNOWN; | |
2629 | + | |
2630 | +/* Doesn't cover locally-generated broadcast, so not worth it. */ | |
2631 | +#if 0 | |
2632 | + /* Ignore broadcast: no `connection'. */ | |
2633 | + if ((*pskb)->pkt_type == PACKET_BROADCAST) { | |
2634 | + printk("Broadcast packet!\n"); | |
2635 | + return NF_ACCEPT; | |
2636 | + } else if (((*pskb)->nh.iph->daddr & htonl(0x000000FF)) | |
2637 | + == htonl(0x000000FF)) { | |
2638 | + printk("Should bcast: %u.%u.%u.%u->%u.%u.%u.%u (sk=%p, ptype=%u)\n", | |
2639 | + NIPQUAD((*pskb)->nh.iph->saddr), | |
2640 | + NIPQUAD((*pskb)->nh.iph->daddr), | |
2641 | + (*pskb)->sk, (*pskb)->pkt_type); | |
2642 | + } | |
2643 | +#endif | |
2644 | + | |
2645 | + /* Previously seen (loopback)? Ignore. Do this before | |
2646 | + fragment check. */ | |
2647 | + if ((*pskb)->nfct) | |
2648 | + return NF_ACCEPT; | |
2649 | + | |
2650 | + /* Gather fragments. */ | |
2651 | + if ((*pskb)->nh.iph->frag_off & htons(IP_MF|IP_OFFSET)) { | |
2652 | + *pskb = ip_ct_gather_frags(*pskb); | |
2653 | + if (!*pskb) | |
2654 | + return NF_STOLEN; | |
2655 | + } | |
2656 | + | |
2657 | + proto = ip_ct_find_proto((*pskb)->nh.iph->protocol); | |
2658 | + | |
2659 | + /* It may be an icmp error... */ | |
2660 | + if ((*pskb)->nh.iph->protocol == IPPROTO_ICMP | |
2661 | + && icmp_error_track(*pskb, &ctinfo, hooknum)) | |
2662 | + return NF_ACCEPT; | |
2663 | + | |
2664 | + if (!(ct = resolve_normal_ct(*pskb, proto,&set_reply,hooknum,&ctinfo))) | |
2665 | + /* Not valid part of a connection */ | |
2666 | + return NF_ACCEPT; | |
2667 | + | |
2668 | + if (IS_ERR(ct)) | |
2669 | + /* Too stressed to deal. */ | |
2670 | + return NF_DROP; | |
2671 | + | |
2672 | + IP_NF_ASSERT((*pskb)->nfct); | |
2673 | + | |
2674 | + ret = proto->packet(ct, *pskb, ctinfo); | |
2675 | + if (ret == -1) { | |
2676 | + /* Invalid */ | |
2677 | + nf_conntrack_put((*pskb)->nfct); | |
2678 | + (*pskb)->nfct = NULL; | |
2679 | + return NF_ACCEPT; | |
2680 | + } | |
2681 | + | |
2682 | + if (ret != NF_DROP && ct->helper) { | |
2683 | + ret = ct->helper->help(*pskb, ct, ctinfo); | |
2684 | + if (ret == -1) { | |
2685 | + /* Invalid */ | |
2686 | + nf_conntrack_put((*pskb)->nfct); | |
2687 | + (*pskb)->nfct = NULL; | |
2688 | + return NF_ACCEPT; | |
2689 | + } | |
2690 | + } | |
2691 | + if (set_reply) | |
2692 | + set_bit(IPS_SEEN_REPLY_BIT, &ct->status); | |
2693 | + | |
2694 | + return ret; | |
2695 | +} | |
2696 | + | |
2697 | +int invert_tuplepr(struct ip_conntrack_tuple *inverse, | |
2698 | + const struct ip_conntrack_tuple *orig) | |
2699 | +{ | |
2700 | + return invert_tuple(inverse, orig, ip_ct_find_proto(orig->dst.protonum)); | |
2701 | +} | |
2702 | + | |
2703 | +static inline int resent_expect(const struct ip_conntrack_expect *i, | |
2704 | + const struct ip_conntrack_tuple *tuple, | |
2705 | + const struct ip_conntrack_tuple *mask) | |
2706 | +{ | |
2707 | + DEBUGP("resent_expect\n"); | |
2708 | + DEBUGP(" tuple: "); DUMP_TUPLE(&i->tuple); | |
2709 | + DEBUGP("ct_tuple: "); DUMP_TUPLE(&i->ct_tuple); | |
2710 | + DEBUGP("test tuple: "); DUMP_TUPLE(tuple); | |
2711 | + return (((i->ct_tuple.dst.protonum == 0 && ip_ct_tuple_equal(&i->tuple, tuple)) | |
2712 | + || (i->ct_tuple.dst.protonum && ip_ct_tuple_equal(&i->ct_tuple, tuple))) | |
2713 | + && ip_ct_tuple_equal(&i->mask, mask)); | |
2714 | +} | |
2715 | + | |
2716 | +/* Would two expected things clash? */ | |
2717 | +static inline int expect_clash(const struct ip_conntrack_expect *i, | |
2718 | + const struct ip_conntrack_tuple *tuple, | |
2719 | + const struct ip_conntrack_tuple *mask) | |
2720 | +{ | |
2721 | + /* Part covered by intersection of masks must be unequal, | |
2722 | + otherwise they clash */ | |
2723 | + struct ip_conntrack_tuple intersect_mask | |
2724 | + = { { i->mask.src.ip & mask->src.ip, | |
2725 | + { i->mask.src.u.all & mask->src.u.all } }, | |
2726 | + { i->mask.dst.ip & mask->dst.ip, | |
2727 | + { i->mask.dst.u.all & mask->dst.u.all }, | |
2728 | + i->mask.dst.protonum & mask->dst.protonum } }; | |
2729 | + | |
2730 | + return ip_ct_tuple_mask_cmp(&i->tuple, tuple, &intersect_mask); | |
2731 | +} | |
2732 | + | |
2733 | +inline void ip_conntrack_unexpect_related(struct ip_conntrack_expect *expect) | |
2734 | +{ | |
2735 | + WRITE_LOCK(&ip_conntrack_lock); | |
2736 | + unexpect_related(expect); | |
2737 | + WRITE_UNLOCK(&ip_conntrack_lock); | |
2738 | +} | |
2739 | + | |
2740 | +static void expectation_timed_out(unsigned long ul_expect) | |
2741 | +{ | |
2742 | + struct ip_conntrack_expect *expect = (void *) ul_expect; | |
2743 | + | |
2744 | + DEBUGP("expectation %p timed out\n", expect); | |
2745 | + WRITE_LOCK(&ip_conntrack_lock); | |
2746 | + __unexpect_related(expect); | |
2747 | + WRITE_UNLOCK(&ip_conntrack_lock); | |
2748 | +} | |
2749 | + | |
2750 | +/* Add a related connection. */ | |
2751 | +int ip_conntrack_expect_related(struct ip_conntrack *related_to, | |
2752 | + struct ip_conntrack_expect *expect) | |
2753 | +{ | |
2754 | + struct ip_conntrack_expect *old, *new; | |
2755 | + int ret = 0; | |
2756 | + | |
2757 | + WRITE_LOCK(&ip_conntrack_lock); | |
2758 | + /* Because of the write lock, no reader can walk the lists, | |
2759 | + * so there is no need to use the tuple lock too */ | |
2760 | + | |
2761 | + DEBUGP("ip_conntrack_expect_related %p\n", related_to); | |
2762 | + DEBUGP("tuple: "); DUMP_TUPLE(&expect->tuple); | |
2763 | + DEBUGP("mask: "); DUMP_TUPLE(&expect->mask); | |
2764 | + | |
2765 | + old = LIST_FIND(&ip_conntrack_expect_list, resent_expect, | |
2766 | + struct ip_conntrack_expect *, &expect->tuple, | |
2767 | + &expect->mask); | |
2768 | + if (old) { | |
2769 | + /* Helper private data may contain offsets but no pointers | |
2770 | + pointing into the payload - otherwise we should have to copy | |
2771 | + the data filled out by the helper over the old one */ | |
2772 | + DEBUGP("expect_related: resent packet\n"); | |
2773 | + if (related_to->helper->timeout) { | |
2774 | + if (!del_timer(&old->timeout)) { | |
2775 | + /* expectation is dying. Fall through */ | |
2776 | + old = NULL; | |
2777 | + } else { | |
2778 | + old->timeout.expires = jiffies + | |
2779 | + related_to->helper->timeout * HZ; | |
2780 | + add_timer(&old->timeout); | |
2781 | + } | |
2782 | + } | |
2783 | + | |
2784 | + if (old) { | |
2785 | + WRITE_UNLOCK(&ip_conntrack_lock); | |
2786 | + return -EEXIST; | |
2787 | + } | |
2788 | + } else if (related_to->helper->max_expected && | |
2789 | + related_to->expecting >= related_to->helper->max_expected) { | |
2790 | + struct list_head *cur_item; | |
2791 | + /* old == NULL */ | |
2792 | + if (!(related_to->helper->flags & | |
2793 | + IP_CT_HELPER_F_REUSE_EXPECT)) { | |
2794 | + WRITE_UNLOCK(&ip_conntrack_lock); | |
2795 | + if (net_ratelimit()) | |
2796 | + printk(KERN_WARNING | |
2797 | + "ip_conntrack: max number of expected " | |
2798 | + "connections %i of %s reached for " | |
2799 | + "%u.%u.%u.%u->%u.%u.%u.%u\n", | |
2800 | + related_to->helper->max_expected, | |
2801 | + related_to->helper->name, | |
2802 | + NIPQUAD(related_to->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip), | |
2803 | + NIPQUAD(related_to->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip)); | |
2804 | + return -EPERM; | |
2805 | + } | |
2806 | + DEBUGP("ip_conntrack: max number of expected " | |
2807 | + "connections %i of %s reached for " | |
2808 | + "%u.%u.%u.%u->%u.%u.%u.%u, reusing\n", | |
2809 | + related_to->helper->max_expected, | |
2810 | + related_to->helper->name, | |
2811 | + NIPQUAD(related_to->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip), | |
2812 | + NIPQUAD(related_to->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip)); | |
2813 | + | |
2814 | + /* choose the the oldest expectation to evict */ | |
2815 | + list_for_each(cur_item, &related_to->sibling_list) { | |
2816 | + struct ip_conntrack_expect *cur; | |
2817 | + | |
2818 | + cur = list_entry(cur_item, | |
2819 | + struct ip_conntrack_expect, | |
2820 | + expected_list); | |
2821 | + if (cur->sibling == NULL) { | |
2822 | + old = cur; | |
2823 | + break; | |
2824 | + } | |
2825 | + } | |
2826 | + | |
2827 | + /* (!old) cannot happen, since related_to->expecting is the | |
2828 | + * number of unconfirmed expects */ | |
2829 | + IP_NF_ASSERT(old); | |
2830 | + | |
2831 | + /* newnat14 does not reuse the real allocated memory | |
2832 | + * structures but rather unexpects the old and | |
2833 | + * allocates a new. unexpect_related will decrement | |
2834 | + * related_to->expecting. | |
2835 | + */ | |
2836 | + unexpect_related(old); | |
2837 | + ret = -EPERM; | |
2838 | + } else if (LIST_FIND(&ip_conntrack_expect_list, expect_clash, | |
2839 | + struct ip_conntrack_expect *, &expect->tuple, | |
2840 | + &expect->mask)) { | |
2841 | + WRITE_UNLOCK(&ip_conntrack_lock); | |
2842 | + DEBUGP("expect_related: busy!\n"); | |
2843 | + return -EBUSY; | |
2844 | + } | |
2845 | + | |
2846 | + new = (struct ip_conntrack_expect *) | |
2847 | + kmalloc(sizeof(struct ip_conntrack_expect), GFP_ATOMIC); | |
2848 | + if (!new) { | |
2849 | + WRITE_UNLOCK(&ip_conntrack_lock); | |
2850 | + DEBUGP("expect_relaed: OOM allocating expect\n"); | |
2851 | + return -ENOMEM; | |
2852 | + } | |
2853 | + | |
2854 | + DEBUGP("new expectation %p of conntrack %p\n", new, related_to); | |
2855 | + memcpy(new, expect, sizeof(*expect)); | |
2856 | + new->expectant = related_to; | |
2857 | + new->sibling = NULL; | |
2858 | + atomic_set(&new->use, 1); | |
2859 | + | |
2860 | + /* add to expected list for this connection */ | |
2861 | + list_add(&new->expected_list, &related_to->sibling_list); | |
2862 | + /* add to global list of expectations */ | |
2863 | + list_prepend(&ip_conntrack_expect_list, &new->list); | |
2864 | + /* add and start timer if required */ | |
2865 | + if (related_to->helper->timeout) { | |
2866 | + init_timer(&new->timeout); | |
2867 | + new->timeout.data = (unsigned long)new; | |
2868 | + new->timeout.function = expectation_timed_out; | |
2869 | + new->timeout.expires = jiffies + | |
2870 | + related_to->helper->timeout * HZ; | |
2871 | + add_timer(&new->timeout); | |
2872 | + } | |
2873 | + related_to->expecting++; | |
2874 | + | |
2875 | + WRITE_UNLOCK(&ip_conntrack_lock); | |
2876 | + | |
2877 | + return ret; | |
2878 | +} | |
2879 | + | |
2880 | +/* Change tuple in an existing expectation */ | |
2881 | +int ip_conntrack_change_expect(struct ip_conntrack_expect *expect, | |
2882 | + struct ip_conntrack_tuple *newtuple) | |
2883 | +{ | |
2884 | + int ret; | |
2885 | + | |
2886 | + MUST_BE_READ_LOCKED(&ip_conntrack_lock); | |
2887 | + WRITE_LOCK(&ip_conntrack_expect_tuple_lock); | |
2888 | + | |
2889 | + DEBUGP("change_expect:\n"); | |
2890 | + DEBUGP("exp tuple: "); DUMP_TUPLE(&expect->tuple); | |
2891 | + DEBUGP("exp mask: "); DUMP_TUPLE(&expect->mask); | |
2892 | + DEBUGP("newtuple: "); DUMP_TUPLE(newtuple); | |
2893 | + if (expect->ct_tuple.dst.protonum == 0) { | |
2894 | + /* Never seen before */ | |
2895 | + DEBUGP("change expect: never seen before\n"); | |
2896 | + if (!ip_ct_tuple_equal(&expect->tuple, newtuple) | |
2897 | + && LIST_FIND(&ip_conntrack_expect_list, expect_clash, | |
2898 | + struct ip_conntrack_expect *, newtuple, &expect->mask)) { | |
2899 | + /* Force NAT to find an unused tuple */ | |
2900 | + ret = -1; | |
2901 | + } else { | |
2902 | + memcpy(&expect->ct_tuple, &expect->tuple, sizeof(expect->tuple)); | |
2903 | + memcpy(&expect->tuple, newtuple, sizeof(expect->tuple)); | |
2904 | + ret = 0; | |
2905 | + } | |
2906 | + } else { | |
2907 | + /* Resent packet */ | |
2908 | + DEBUGP("change expect: resent packet\n"); | |
2909 | + if (ip_ct_tuple_equal(&expect->tuple, newtuple)) { | |
2910 | + ret = 0; | |
2911 | + } else { | |
2912 | + /* Force NAT to choose again the same port */ | |
2913 | + ret = -1; | |
2914 | + } | |
2915 | + } | |
2916 | + WRITE_UNLOCK(&ip_conntrack_expect_tuple_lock); | |
2917 | + | |
2918 | + return ret; | |
2919 | +} | |
2920 | + | |
2921 | +/* Alter reply tuple (maybe alter helper). If it's already taken, | |
2922 | + return 0 and don't do alteration. */ | |
2923 | +int ip_conntrack_alter_reply(struct ip_conntrack *conntrack, | |
2924 | + const struct ip_conntrack_tuple *newreply) | |
2925 | +{ | |
2926 | + WRITE_LOCK(&ip_conntrack_lock); | |
2927 | + if (__ip_conntrack_find(newreply, conntrack)) { | |
2928 | + WRITE_UNLOCK(&ip_conntrack_lock); | |
2929 | + return 0; | |
2930 | + } | |
2931 | + /* Should be unconfirmed, so not in hash table yet */ | |
2932 | + IP_NF_ASSERT(!is_confirmed(conntrack)); | |
2933 | + | |
2934 | + DEBUGP("Altering reply tuple of %p to ", conntrack); | |
2935 | + DUMP_TUPLE(newreply); | |
2936 | + | |
2937 | + conntrack->tuplehash[IP_CT_DIR_REPLY].tuple = *newreply; | |
2938 | + if (!conntrack->master) | |
2939 | + conntrack->helper = LIST_FIND(&helpers, helper_cmp, | |
2940 | + struct ip_conntrack_helper *, | |
2941 | + newreply); | |
2942 | + WRITE_UNLOCK(&ip_conntrack_lock); | |
2943 | + | |
2944 | + return 1; | |
2945 | +} | |
2946 | + | |
2947 | +int ip_conntrack_helper_register(struct ip_conntrack_helper *me) | |
2948 | +{ | |
2949 | + WRITE_LOCK(&ip_conntrack_lock); | |
2950 | + list_prepend(&helpers, me); | |
2951 | + WRITE_UNLOCK(&ip_conntrack_lock); | |
2952 | + | |
2953 | + return 0; | |
2954 | +} | |
2955 | + | |
2956 | +static inline int unhelp(struct ip_conntrack_tuple_hash *i, | |
2957 | + const struct ip_conntrack_helper *me) | |
2958 | +{ | |
2959 | + if (i->ctrack->helper == me) { | |
2960 | + /* Get rid of any expected. */ | |
2961 | + remove_expectations(i->ctrack, 0); | |
2962 | + /* And *then* set helper to NULL */ | |
2963 | + i->ctrack->helper = NULL; | |
2964 | + } | |
2965 | + return 0; | |
2966 | +} | |
2967 | + | |
2968 | +void ip_conntrack_helper_unregister(struct ip_conntrack_helper *me) | |
2969 | +{ | |
2970 | + unsigned int i; | |
2971 | + | |
2972 | + /* Need write lock here, to delete helper. */ | |
2973 | + WRITE_LOCK(&ip_conntrack_lock); | |
2974 | + LIST_DELETE(&helpers, me); | |
2975 | + | |
2976 | + /* Get rid of expecteds, set helpers to NULL. */ | |
2977 | + for (i = 0; i < ip_conntrack_htable_size; i++) | |
2978 | + LIST_FIND_W(&ip_conntrack_hash[i], unhelp, | |
2979 | + struct ip_conntrack_tuple_hash *, me); | |
2980 | + WRITE_UNLOCK(&ip_conntrack_lock); | |
2981 | + | |
2982 | + /* Someone could be still looking at the helper in a bh. */ | |
2983 | + synchronize_net(); | |
2984 | +} | |
2985 | + | |
2986 | +/* Refresh conntrack for this many jiffies. */ | |
2987 | +void ip_ct_refresh(struct ip_conntrack *ct, unsigned long extra_jiffies) | |
2988 | +{ | |
2989 | + IP_NF_ASSERT(ct->timeout.data == (unsigned long)ct); | |
2990 | + | |
2991 | + WRITE_LOCK(&ip_conntrack_lock); | |
2992 | + /* If not in hash table, timer will not be active yet */ | |
2993 | + if (!is_confirmed(ct)) | |
2994 | + ct->timeout.expires = extra_jiffies; | |
2995 | + else { | |
2996 | + /* Need del_timer for race avoidance (may already be dying). */ | |
2997 | + if (del_timer(&ct->timeout)) { | |
2998 | + ct->timeout.expires = jiffies + extra_jiffies; | |
2999 | + add_timer(&ct->timeout); | |
3000 | + } | |
3001 | + } | |
3002 | + WRITE_UNLOCK(&ip_conntrack_lock); | |
3003 | +} | |
3004 | + | |
3005 | +/* Returns new sk_buff, or NULL */ | |
3006 | +struct sk_buff * | |
3007 | +ip_ct_gather_frags(struct sk_buff *skb) | |
3008 | +{ | |
3009 | + struct sock *sk = skb->sk; | |
3010 | +#ifdef CONFIG_NETFILTER_DEBUG | |
3011 | + unsigned int olddebug = skb->nf_debug; | |
3012 | +#endif | |
3013 | + if (sk) { | |
3014 | + sock_hold(sk); | |
3015 | + skb_orphan(skb); | |
3016 | + } | |
3017 | + | |
3018 | + local_bh_disable(); | |
3019 | + skb = ip_defrag(skb); | |
3020 | + local_bh_enable(); | |
3021 | + | |
3022 | + if (!skb) { | |
3023 | + if (sk) | |
3024 | + sock_put(sk); | |
3025 | + return skb; | |
3026 | + } | |
3027 | + | |
3028 | + if (sk) { | |
3029 | + skb_set_owner_w(skb, sk); | |
3030 | + sock_put(sk); | |
3031 | + } | |
3032 | + | |
3033 | + ip_send_check(skb->nh.iph); | |
3034 | + skb->nfcache |= NFC_ALTERED; | |
3035 | +#ifdef CONFIG_NETFILTER_DEBUG | |
3036 | + /* Packet path as if nothing had happened. */ | |
3037 | + skb->nf_debug = olddebug; | |
3038 | +#endif | |
3039 | + return skb; | |
3040 | +} | |
3041 | + | |
3042 | +/* Used by ipt_REJECT. */ | |
3043 | +static void ip_conntrack_attach(struct sk_buff *nskb, struct nf_ct_info *nfct) | |
3044 | +{ | |
3045 | + struct ip_conntrack *ct; | |
3046 | + enum ip_conntrack_info ctinfo; | |
3047 | + | |
3048 | + ct = __ip_conntrack_get(nfct, &ctinfo); | |
3049 | + | |
3050 | + /* This ICMP is in reverse direction to the packet which | |
3051 | + caused it */ | |
3052 | + if (CTINFO2DIR(ctinfo) == IP_CT_DIR_ORIGINAL) | |
3053 | + ctinfo = IP_CT_RELATED + IP_CT_IS_REPLY; | |
3054 | + else | |
3055 | + ctinfo = IP_CT_RELATED; | |
3056 | + | |
3057 | + /* Attach new skbuff, and increment count */ | |
3058 | + nskb->nfct = &ct->infos[ctinfo]; | |
3059 | + atomic_inc(&ct->ct_general.use); | |
3060 | +} | |
3061 | + | |
3062 | +static inline int | |
3063 | +do_kill(const struct ip_conntrack_tuple_hash *i, | |
3064 | + int (*kill)(const struct ip_conntrack *i, void *data), | |
3065 | + void *data) | |
3066 | +{ | |
3067 | + return kill(i->ctrack, data); | |
3068 | +} | |
3069 | + | |
3070 | +/* Bring out ya dead! */ | |
3071 | +static struct ip_conntrack_tuple_hash * | |
3072 | +get_next_corpse(int (*kill)(const struct ip_conntrack *i, void *data), | |
3073 | + void *data, unsigned int *bucket) | |
3074 | +{ | |
3075 | + struct ip_conntrack_tuple_hash *h = NULL; | |
3076 | + | |
3077 | + READ_LOCK(&ip_conntrack_lock); | |
3078 | + for (; !h && *bucket < ip_conntrack_htable_size; (*bucket)++) { | |
3079 | + h = LIST_FIND(&ip_conntrack_hash[*bucket], do_kill, | |
3080 | + struct ip_conntrack_tuple_hash *, kill, data); | |
3081 | + } | |
3082 | + if (h) | |
3083 | + atomic_inc(&h->ctrack->ct_general.use); | |
3084 | + READ_UNLOCK(&ip_conntrack_lock); | |
3085 | + | |
3086 | + return h; | |
3087 | +} | |
3088 | + | |
3089 | +void | |
3090 | +ip_ct_selective_cleanup(int (*kill)(const struct ip_conntrack *i, void *data), | |
3091 | + void *data) | |
3092 | +{ | |
3093 | + struct ip_conntrack_tuple_hash *h; | |
3094 | + unsigned int bucket = 0; | |
3095 | + | |
3096 | + while ((h = get_next_corpse(kill, data, &bucket)) != NULL) { | |
3097 | + /* Time to push up daises... */ | |
3098 | + if (del_timer(&h->ctrack->timeout)) | |
3099 | + death_by_timeout((unsigned long)h->ctrack); | |
3100 | + /* ... else the timer will get him soon. */ | |
3101 | + | |
3102 | + ip_conntrack_put(h->ctrack); | |
3103 | + } | |
3104 | +} | |
3105 | + | |
3106 | +/* Fast function for those who don't want to parse /proc (and I don't | |
3107 | + blame them). */ | |
3108 | +/* Reversing the socket's dst/src point of view gives us the reply | |
3109 | + mapping. */ | |
3110 | +static int | |
3111 | +getorigdst(struct sock *sk, int optval, void *user, int *len) | |
3112 | +{ | |
3113 | + struct inet_opt *inet = inet_sk(sk); | |
3114 | + struct ip_conntrack_tuple_hash *h; | |
3115 | + struct ip_conntrack_tuple tuple; | |
3116 | + | |
3117 | + IP_CT_TUPLE_U_BLANK(&tuple); | |
3118 | + tuple.src.ip = inet->rcv_saddr; | |
3119 | + tuple.src.u.tcp.port = inet->sport; | |
3120 | + tuple.dst.ip = inet->daddr; | |
3121 | + tuple.dst.u.tcp.port = inet->dport; | |
3122 | + tuple.dst.protonum = IPPROTO_TCP; | |
3123 | + | |
3124 | + /* We only do TCP at the moment: is there a better way? */ | |
3125 | + if (strcmp(sk->sk_prot->name, "TCP")) { | |
3126 | + DEBUGP("SO_ORIGINAL_DST: Not a TCP socket\n"); | |
3127 | + return -ENOPROTOOPT; | |
3128 | + } | |
3129 | + | |
3130 | + if ((unsigned int) *len < sizeof(struct sockaddr_in)) { | |
3131 | + DEBUGP("SO_ORIGINAL_DST: len %u not %u\n", | |
3132 | + *len, sizeof(struct sockaddr_in)); | |
3133 | + return -EINVAL; | |
3134 | + } | |
3135 | + | |
3136 | + h = ip_conntrack_find_get(&tuple, NULL); | |
3137 | + if (h) { | |
3138 | + struct sockaddr_in sin; | |
3139 | + | |
3140 | + sin.sin_family = AF_INET; | |
3141 | + sin.sin_port = h->ctrack->tuplehash[IP_CT_DIR_ORIGINAL] | |
3142 | + .tuple.dst.u.tcp.port; | |
3143 | + sin.sin_addr.s_addr = h->ctrack->tuplehash[IP_CT_DIR_ORIGINAL] | |
3144 | + .tuple.dst.ip; | |
3145 | + | |
3146 | + DEBUGP("SO_ORIGINAL_DST: %u.%u.%u.%u %u\n", | |
3147 | + NIPQUAD(sin.sin_addr.s_addr), ntohs(sin.sin_port)); | |
3148 | + ip_conntrack_put(h->ctrack); | |
3149 | + if (copy_to_user(user, &sin, sizeof(sin)) != 0) | |
3150 | + return -EFAULT; | |
3151 | + else | |
3152 | + return 0; | |
3153 | + } | |
3154 | + DEBUGP("SO_ORIGINAL_DST: Can't find %u.%u.%u.%u/%u-%u.%u.%u.%u/%u.\n", | |
3155 | + NIPQUAD(tuple.src.ip), ntohs(tuple.src.u.tcp.port), | |
3156 | + NIPQUAD(tuple.dst.ip), ntohs(tuple.dst.u.tcp.port)); | |
3157 | + return -ENOENT; | |
3158 | +} | |
3159 | + | |
3160 | +static struct nf_sockopt_ops so_getorigdst = { | |
3161 | + .pf = PF_INET, | |
3162 | + .get_optmin = SO_ORIGINAL_DST, | |
3163 | + .get_optmax = SO_ORIGINAL_DST+1, | |
3164 | + .get = &getorigdst, | |
3165 | +}; | |
3166 | + | |
3167 | +static int kill_all(const struct ip_conntrack *i, void *data) | |
3168 | +{ | |
3169 | + return 1; | |
3170 | +} | |
3171 | + | |
3172 | +/* Mishearing the voices in his head, our hero wonders how he's | |
3173 | + supposed to kill the mall. */ | |
3174 | +void ip_conntrack_cleanup(void) | |
3175 | +{ | |
3176 | + ip_ct_attach = NULL; | |
3177 | + /* This makes sure all current packets have passed through | |
3178 | + netfilter framework. Roll on, two-stage module | |
3179 | + delete... */ | |
3180 | + synchronize_net(); | |
3181 | + | |
3182 | + i_see_dead_people: | |
3183 | + ip_ct_selective_cleanup(kill_all, NULL); | |
3184 | + if (atomic_read(&ip_conntrack_count) != 0) { | |
3185 | + schedule(); | |
3186 | + goto i_see_dead_people; | |
3187 | + } | |
3188 | + | |
3189 | + kmem_cache_destroy(ip_conntrack_cachep); | |
3190 | + vfree(ip_conntrack_hash); | |
3191 | + nf_unregister_sockopt(&so_getorigdst); | |
3192 | +} | |
3193 | + | |
3194 | +static int hashsize; | |
3195 | +MODULE_PARM(hashsize, "i"); | |
3196 | + | |
3197 | +int __init ip_conntrack_init(void) | |
3198 | +{ | |
3199 | + unsigned int i; | |
3200 | + int ret; | |
3201 | + | |
3202 | + /* Idea from tcp.c: use 1/16384 of memory. On i386: 32MB | |
3203 | + * machine has 256 buckets. >= 1GB machines have 8192 buckets. */ | |
3204 | + if (hashsize) { | |
3205 | + ip_conntrack_htable_size = hashsize; | |
3206 | + } else { | |
3207 | + ip_conntrack_htable_size | |
3208 | + = (((num_physpages << PAGE_SHIFT) / 16384) | |
3209 | + / sizeof(struct list_head)); | |
3210 | + if (num_physpages > (1024 * 1024 * 1024 / PAGE_SIZE)) | |
3211 | + ip_conntrack_htable_size = 8192; | |
3212 | + if (ip_conntrack_htable_size < 16) | |
3213 | + ip_conntrack_htable_size = 16; | |
3214 | + } | |
3215 | + ip_conntrack_max = 8 * ip_conntrack_htable_size; | |
3216 | + | |
3217 | + printk("ip_conntrack version %s (%u buckets, %d max)" | |
3218 | + " - %Zd bytes per conntrack\n", IP_CONNTRACK_VERSION, | |
3219 | + ip_conntrack_htable_size, ip_conntrack_max, | |
3220 | + sizeof(struct ip_conntrack)); | |
3221 | + | |
3222 | + ret = nf_register_sockopt(&so_getorigdst); | |
3223 | + if (ret != 0) { | |
3224 | + printk(KERN_ERR "Unable to register netfilter socket option\n"); | |
3225 | + return ret; | |
3226 | + } | |
3227 | + | |
3228 | + ip_conntrack_hash = vmalloc(sizeof(struct list_head) | |
3229 | + * ip_conntrack_htable_size); | |
3230 | + if (!ip_conntrack_hash) { | |
3231 | + printk(KERN_ERR "Unable to create ip_conntrack_hash\n"); | |
3232 | + goto err_unreg_sockopt; | |
3233 | + } | |
3234 | + | |
3235 | + ip_conntrack_cachep = kmem_cache_create("ip_conntrack", | |
3236 | + sizeof(struct ip_conntrack), 0, | |
3237 | + SLAB_HWCACHE_ALIGN, NULL, NULL); | |
3238 | + if (!ip_conntrack_cachep) { | |
3239 | + printk(KERN_ERR "Unable to create ip_conntrack slab cache\n"); | |
3240 | + goto err_free_hash; | |
3241 | + } | |
3242 | + /* Don't NEED lock here, but good form anyway. */ | |
3243 | + WRITE_LOCK(&ip_conntrack_lock); | |
3244 | + /* Sew in builtin protocols. */ | |
3245 | + list_append(&protocol_list, &ip_conntrack_protocol_tcp); | |
3246 | + list_append(&protocol_list, &ip_conntrack_protocol_udp); | |
3247 | + list_append(&protocol_list, &ip_conntrack_protocol_icmp); | |
3248 | + WRITE_UNLOCK(&ip_conntrack_lock); | |
3249 | + | |
3250 | + for (i = 0; i < ip_conntrack_htable_size; i++) | |
3251 | + INIT_LIST_HEAD(&ip_conntrack_hash[i]); | |
3252 | + | |
3253 | + /* For use by ipt_REJECT */ | |
3254 | + ip_ct_attach = ip_conntrack_attach; | |
3255 | + return ret; | |
3256 | + | |
3257 | +err_free_hash: | |
3258 | + vfree(ip_conntrack_hash); | |
3259 | +err_unreg_sockopt: | |
3260 | + nf_unregister_sockopt(&so_getorigdst); | |
3261 | + | |
3262 | + return -ENOMEM; | |
3263 | +} | |
3264 | diff -Nur linux-2.6.4-rc2.org/net/ipv4/netfilter/ip_conntrack_standalone.c linux-2.6.4-rc2/net/ipv4/netfilter/ip_conntrack_standalone.c | |
3265 | --- linux-2.6.4-rc2.org/net/ipv4/netfilter/ip_conntrack_standalone.c 2004-03-04 06:16:44.000000000 +0000 | |
3266 | +++ linux-2.6.4-rc2/net/ipv4/netfilter/ip_conntrack_standalone.c 2004-03-05 07:39:43.000000000 +0000 | |
3267 | @@ -519,13 +519,20 @@ | |
3268 | return ret; | |
3269 | } | |
3270 | ||
3271 | -/* FIXME: Allow NULL functions and sub in pointers to generic for | |
3272 | - them. --RR */ | |
3273 | +/** | |
3274 | + * ip_conntrack_protocol_register - Register layer 4 protocol helper | |
3275 | + * @proto: structure describing this layer 4 protocol helper | |
3276 | + * | |
3277 | + * This function is called by layer 4 protocol helpers to register | |
3278 | + * themselves with the conntrack core. | |
3279 | + */ | |
3280 | int ip_conntrack_protocol_register(struct ip_conntrack_protocol *proto) | |
3281 | { | |
3282 | int ret = 0; | |
3283 | struct list_head *i; | |
3284 | ||
3285 | + /* FIXME: Allow NULL functions and sub in pointers to generic for | |
3286 | + them. --RR */ | |
3287 | WRITE_LOCK(&ip_conntrack_lock); | |
3288 | list_for_each(i, &protocol_list) { | |
3289 | if (((struct ip_conntrack_protocol *)i)->proto | |
3290 | @@ -542,12 +549,20 @@ | |
3291 | return ret; | |
3292 | } | |
3293 | ||
3294 | +/** | |
3295 | + * ip_conntrack_protocol_unregister - Unregister layer 4 protocol helper | |
3296 | + * @proto: structure describing this layer 4 protocol helper | |
3297 | + * | |
3298 | + * This function is called byh layer 4 protocol helpers to unregister | |
3299 | + * themselvers from the conntrack core. Please note that all conntrack | |
3300 | + * entries for this protocol are deleted from the conntrack hash table. | |
3301 | + */ | |
3302 | void ip_conntrack_protocol_unregister(struct ip_conntrack_protocol *proto) | |
3303 | { | |
3304 | WRITE_LOCK(&ip_conntrack_lock); | |
3305 | ||
3306 | - /* ip_ct_find_proto() returns proto_generic in case there is no protocol | |
3307 | - * helper. So this should be enough - HW */ | |
3308 | + /* ip_ct_find_proto() returns proto_generic in case there is no | |
3309 | + * protocol helper. So this should be enough - HW */ | |
3310 | LIST_DELETE(&protocol_list, proto); | |
3311 | WRITE_UNLOCK(&ip_conntrack_lock); | |
3312 | ||
3313 | diff -Nur linux-2.6.4-rc2.org/net/ipv4/netfilter/ip_conntrack_standalone.c.orig linux-2.6.4-rc2/net/ipv4/netfilter/ip_conntrack_standalone.c.orig | |
3314 | --- linux-2.6.4-rc2.org/net/ipv4/netfilter/ip_conntrack_standalone.c.orig 1970-01-01 00:00:00.000000000 +0000 | |
3315 | +++ linux-2.6.4-rc2/net/ipv4/netfilter/ip_conntrack_standalone.c.orig 2004-03-04 06:16:44.000000000 +0000 | |
3316 | @@ -0,0 +1,606 @@ | |
3317 | +/* This file contains all the functions required for the standalone | |
3318 | + ip_conntrack module. | |
3319 | + | |
3320 | + These are not required by the compatibility layer. | |
3321 | +*/ | |
3322 | + | |
3323 | +/* (C) 1999-2001 Paul `Rusty' Russell | |
3324 | + * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org> | |
3325 | + * | |
3326 | + * This program is free software; you can redistribute it and/or modify | |
3327 | + * it under the terms of the GNU General Public License version 2 as | |
3328 | + * published by the Free Software Foundation. | |
3329 | + */ | |
3330 | + | |
3331 | +#include <linux/config.h> | |
3332 | +#include <linux/types.h> | |
3333 | +#include <linux/ip.h> | |
3334 | +#include <linux/netfilter.h> | |
3335 | +#include <linux/netfilter_ipv4.h> | |
3336 | +#include <linux/module.h> | |
3337 | +#include <linux/skbuff.h> | |
3338 | +#include <linux/proc_fs.h> | |
3339 | +#ifdef CONFIG_SYSCTL | |
3340 | +#include <linux/sysctl.h> | |
3341 | +#endif | |
3342 | +#include <net/checksum.h> | |
3343 | + | |
3344 | +#define ASSERT_READ_LOCK(x) MUST_BE_READ_LOCKED(&ip_conntrack_lock) | |
3345 | +#define ASSERT_WRITE_LOCK(x) MUST_BE_WRITE_LOCKED(&ip_conntrack_lock) | |
3346 | + | |
3347 | +#include <linux/netfilter_ipv4/ip_conntrack.h> | |
3348 | +#include <linux/netfilter_ipv4/ip_conntrack_protocol.h> | |
3349 | +#include <linux/netfilter_ipv4/ip_conntrack_core.h> | |
3350 | +#include <linux/netfilter_ipv4/ip_conntrack_helper.h> | |
3351 | +#include <linux/netfilter_ipv4/listhelp.h> | |
3352 | + | |
3353 | +#if 0 | |
3354 | +#define DEBUGP printk | |
3355 | +#else | |
3356 | +#define DEBUGP(format, args...) | |
3357 | +#endif | |
3358 | + | |
3359 | +MODULE_LICENSE("GPL"); | |
3360 | + | |
3361 | +static int kill_proto(const struct ip_conntrack *i, void *data) | |
3362 | +{ | |
3363 | + return (i->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum == | |
3364 | + *((u_int8_t *) data)); | |
3365 | +} | |
3366 | + | |
3367 | +static unsigned int | |
3368 | +print_tuple(char *buffer, const struct ip_conntrack_tuple *tuple, | |
3369 | + struct ip_conntrack_protocol *proto) | |
3370 | +{ | |
3371 | + int len; | |
3372 | + | |
3373 | + len = sprintf(buffer, "src=%u.%u.%u.%u dst=%u.%u.%u.%u ", | |
3374 | + NIPQUAD(tuple->src.ip), NIPQUAD(tuple->dst.ip)); | |
3375 | + | |
3376 | + len += proto->print_tuple(buffer + len, tuple); | |
3377 | + | |
3378 | + return len; | |
3379 | +} | |
3380 | + | |
3381 | +/* FIXME: Don't print source proto part. --RR */ | |
3382 | +static unsigned int | |
3383 | +print_expect(char *buffer, const struct ip_conntrack_expect *expect) | |
3384 | +{ | |
3385 | + unsigned int len; | |
3386 | + | |
3387 | + if (expect->expectant->helper->timeout) | |
3388 | + len = sprintf(buffer, "EXPECTING: %lu ", | |
3389 | + timer_pending(&expect->timeout) | |
3390 | + ? (expect->timeout.expires - jiffies)/HZ : 0); | |
3391 | + else | |
3392 | + len = sprintf(buffer, "EXPECTING: - "); | |
3393 | + len += sprintf(buffer + len, "use=%u proto=%u ", | |
3394 | + atomic_read(&expect->use), expect->tuple.dst.protonum); | |
3395 | + len += print_tuple(buffer + len, &expect->tuple, | |
3396 | + __ip_ct_find_proto(expect->tuple.dst.protonum)); | |
3397 | + len += sprintf(buffer + len, "\n"); | |
3398 | + return len; | |
3399 | +} | |
3400 | + | |
3401 | +static unsigned int | |
3402 | +print_conntrack(char *buffer, struct ip_conntrack *conntrack) | |
3403 | +{ | |
3404 | + unsigned int len; | |
3405 | + struct ip_conntrack_protocol *proto | |
3406 | + = __ip_ct_find_proto(conntrack->tuplehash[IP_CT_DIR_ORIGINAL] | |
3407 | + .tuple.dst.protonum); | |
3408 | + | |
3409 | + len = sprintf(buffer, "%-8s %u %lu ", | |
3410 | + proto->name, | |
3411 | + conntrack->tuplehash[IP_CT_DIR_ORIGINAL] | |
3412 | + .tuple.dst.protonum, | |
3413 | + timer_pending(&conntrack->timeout) | |
3414 | + ? (conntrack->timeout.expires - jiffies)/HZ : 0); | |
3415 | + | |
3416 | + len += proto->print_conntrack(buffer + len, conntrack); | |
3417 | + len += print_tuple(buffer + len, | |
3418 | + &conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple, | |
3419 | + proto); | |
3420 | + if (!(test_bit(IPS_SEEN_REPLY_BIT, &conntrack->status))) | |
3421 | + len += sprintf(buffer + len, "[UNREPLIED] "); | |
3422 | + len += print_tuple(buffer + len, | |
3423 | + &conntrack->tuplehash[IP_CT_DIR_REPLY].tuple, | |
3424 | + proto); | |
3425 | + if (test_bit(IPS_ASSURED_BIT, &conntrack->status)) | |
3426 | + len += sprintf(buffer + len, "[ASSURED] "); | |
3427 | + len += sprintf(buffer + len, "use=%u ", | |
3428 | + atomic_read(&conntrack->ct_general.use)); | |
3429 | + len += sprintf(buffer + len, "\n"); | |
3430 | + | |
3431 | + return len; | |
3432 | +} | |
3433 | + | |
3434 | +/* Returns true when finished. */ | |
3435 | +static inline int | |
3436 | +conntrack_iterate(const struct ip_conntrack_tuple_hash *hash, | |
3437 | + char *buffer, off_t offset, off_t *upto, | |
3438 | + unsigned int *len, unsigned int maxlen) | |
3439 | +{ | |
3440 | + unsigned int newlen; | |
3441 | + IP_NF_ASSERT(hash->ctrack); | |
3442 | + | |
3443 | + MUST_BE_READ_LOCKED(&ip_conntrack_lock); | |
3444 | + | |
3445 | + /* Only count originals */ | |
3446 | + if (DIRECTION(hash)) | |
3447 | + return 0; | |
3448 | + | |
3449 | + if ((*upto)++ < offset) | |
3450 | + return 0; | |
3451 | + | |
3452 | + newlen = print_conntrack(buffer + *len, hash->ctrack); | |
3453 | + if (*len + newlen > maxlen) | |
3454 | + return 1; | |
3455 | + else *len += newlen; | |
3456 | + | |
3457 | + return 0; | |
3458 | +} | |
3459 | + | |
3460 | +static int | |
3461 | +list_conntracks(char *buffer, char **start, off_t offset, int length) | |
3462 | +{ | |
3463 | + unsigned int i; | |
3464 | + unsigned int len = 0; | |
3465 | + off_t upto = 0; | |
3466 | + struct list_head *e; | |
3467 | + | |
3468 | + READ_LOCK(&ip_conntrack_lock); | |
3469 | + /* Traverse hash; print originals then reply. */ | |
3470 | + for (i = 0; i < ip_conntrack_htable_size; i++) { | |
3471 | + if (LIST_FIND(&ip_conntrack_hash[i], conntrack_iterate, | |
3472 | + struct ip_conntrack_tuple_hash *, | |
3473 | + buffer, offset, &upto, &len, length)) | |
3474 | + goto finished; | |
3475 | + } | |
3476 | + | |
3477 | + /* Now iterate through expecteds. */ | |
3478 | + READ_LOCK(&ip_conntrack_expect_tuple_lock); | |
3479 | + list_for_each(e, &ip_conntrack_expect_list) { | |
3480 | + unsigned int last_len; | |
3481 | + struct ip_conntrack_expect *expect | |
3482 | + = (struct ip_conntrack_expect *)e; | |
3483 | + if (upto++ < offset) continue; | |
3484 | + | |
3485 | + last_len = len; | |
3486 | + len += print_expect(buffer + len, expect); | |
3487 | + if (len > length) { | |
3488 | + len = last_len; | |
3489 | + goto finished_expects; | |
3490 | + } | |
3491 | + } | |
3492 | + | |
3493 | + finished_expects: | |
3494 | + READ_UNLOCK(&ip_conntrack_expect_tuple_lock); | |
3495 | + finished: | |
3496 | + READ_UNLOCK(&ip_conntrack_lock); | |
3497 | + | |
3498 | + /* `start' hack - see fs/proc/generic.c line ~165 */ | |
3499 | + *start = (char *)((unsigned int)upto - offset); | |
3500 | + return len; | |
3501 | +} | |
3502 | + | |
3503 | +static unsigned int ip_confirm(unsigned int hooknum, | |
3504 | + struct sk_buff **pskb, | |
3505 | + const struct net_device *in, | |
3506 | + const struct net_device *out, | |
3507 | + int (*okfn)(struct sk_buff *)) | |
3508 | +{ | |
3509 | + /* We've seen it coming out the other side: confirm it */ | |
3510 | + return ip_conntrack_confirm(*pskb); | |
3511 | +} | |
3512 | + | |
3513 | +static unsigned int ip_refrag(unsigned int hooknum, | |
3514 | + struct sk_buff **pskb, | |
3515 | + const struct net_device *in, | |
3516 | + const struct net_device *out, | |
3517 | + int (*okfn)(struct sk_buff *)) | |
3518 | +{ | |
3519 | + struct rtable *rt = (struct rtable *)(*pskb)->dst; | |
3520 | + | |
3521 | + /* We've seen it coming out the other side: confirm */ | |
3522 | + if (ip_confirm(hooknum, pskb, in, out, okfn) != NF_ACCEPT) | |
3523 | + return NF_DROP; | |
3524 | + | |
3525 | + /* Local packets are never produced too large for their | |
3526 | + interface. We degfragment them at LOCAL_OUT, however, | |
3527 | + so we have to refragment them here. */ | |
3528 | + if ((*pskb)->len > dst_pmtu(&rt->u.dst) && | |
3529 | + !skb_shinfo(*pskb)->tso_size) { | |
3530 | + /* No hook can be after us, so this should be OK. */ | |
3531 | + ip_fragment(*pskb, okfn); | |
3532 | + return NF_STOLEN; | |
3533 | + } | |
3534 | + return NF_ACCEPT; | |
3535 | +} | |
3536 | + | |
3537 | +static unsigned int ip_conntrack_local(unsigned int hooknum, | |
3538 | + struct sk_buff **pskb, | |
3539 | + const struct net_device *in, | |
3540 | + const struct net_device *out, | |
3541 | + int (*okfn)(struct sk_buff *)) | |
3542 | +{ | |
3543 | + /* root is playing with raw sockets. */ | |
3544 | + if ((*pskb)->len < sizeof(struct iphdr) | |
3545 | + || (*pskb)->nh.iph->ihl * 4 < sizeof(struct iphdr)) { | |
3546 | + if (net_ratelimit()) | |
3547 | + printk("ipt_hook: happy cracking.\n"); | |
3548 | + return NF_ACCEPT; | |
3549 | + } | |
3550 | + return ip_conntrack_in(hooknum, pskb, in, out, okfn); | |
3551 | +} | |
3552 | + | |
3553 | +/* Connection tracking may drop packets, but never alters them, so | |
3554 | + make it the first hook. */ | |
3555 | +static struct nf_hook_ops ip_conntrack_in_ops = { | |
3556 | + .hook = ip_conntrack_in, | |
3557 | + .owner = THIS_MODULE, | |
3558 | + .pf = PF_INET, | |
3559 | + .hooknum = NF_IP_PRE_ROUTING, | |
3560 | + .priority = NF_IP_PRI_CONNTRACK, | |
3561 | +}; | |
3562 | + | |
3563 | +static struct nf_hook_ops ip_conntrack_local_out_ops = { | |
3564 | + .hook = ip_conntrack_local, | |
3565 | + .owner = THIS_MODULE, | |
3566 | + .pf = PF_INET, | |
3567 | + .hooknum = NF_IP_LOCAL_OUT, | |
3568 | + .priority = NF_IP_PRI_CONNTRACK, | |
3569 | +}; | |
3570 | + | |
3571 | +/* Refragmenter; last chance. */ | |
3572 | +static struct nf_hook_ops ip_conntrack_out_ops = { | |
3573 | + .hook = ip_refrag, | |
3574 | + .owner = THIS_MODULE, | |
3575 | + .pf = PF_INET, | |
3576 | + .hooknum = NF_IP_POST_ROUTING, | |
3577 | + .priority = NF_IP_PRI_LAST, | |
3578 | +}; | |
3579 | + | |
3580 | +static struct nf_hook_ops ip_conntrack_local_in_ops = { | |
3581 | + .hook = ip_confirm, | |
3582 | + .owner = THIS_MODULE, | |
3583 | + .pf = PF_INET, | |
3584 | + .hooknum = NF_IP_LOCAL_IN, | |
3585 | + .priority = NF_IP_PRI_LAST-1, | |
3586 | +}; | |
3587 | + | |
3588 | +/* Sysctl support */ | |
3589 | + | |
3590 | +#ifdef CONFIG_SYSCTL | |
3591 | + | |
3592 | +/* From ip_conntrack_core.c */ | |
3593 | +extern int ip_conntrack_max; | |
3594 | +extern unsigned int ip_conntrack_htable_size; | |
3595 | + | |
3596 | +/* From ip_conntrack_proto_tcp.c */ | |
3597 | +extern unsigned long ip_ct_tcp_timeout_syn_sent; | |
3598 | +extern unsigned long ip_ct_tcp_timeout_syn_recv; | |
3599 | +extern unsigned long ip_ct_tcp_timeout_established; | |
3600 | +extern unsigned long ip_ct_tcp_timeout_fin_wait; | |
3601 | +extern unsigned long ip_ct_tcp_timeout_close_wait; | |
3602 | +extern unsigned long ip_ct_tcp_timeout_last_ack; | |
3603 | +extern unsigned long ip_ct_tcp_timeout_time_wait; | |
3604 | +extern unsigned long ip_ct_tcp_timeout_close; | |
3605 | + | |
3606 | +/* From ip_conntrack_proto_udp.c */ | |
3607 | +extern unsigned long ip_ct_udp_timeout; | |
3608 | +extern unsigned long ip_ct_udp_timeout_stream; | |
3609 | + | |
3610 | +/* From ip_conntrack_proto_icmp.c */ | |
3611 | +extern unsigned long ip_ct_icmp_timeout; | |
3612 | + | |
3613 | +/* From ip_conntrack_proto_icmp.c */ | |
3614 | +extern unsigned long ip_ct_generic_timeout; | |
3615 | + | |
3616 | +static struct ctl_table_header *ip_ct_sysctl_header; | |
3617 | + | |
3618 | +static ctl_table ip_ct_sysctl_table[] = { | |
3619 | + { | |
3620 | + .ctl_name = NET_IPV4_NF_CONNTRACK_MAX, | |
3621 | + .procname = "ip_conntrack_max", | |
3622 | + .data = &ip_conntrack_max, | |
3623 | + .maxlen = sizeof(int), | |
3624 | + .mode = 0644, | |
3625 | + .proc_handler = &proc_dointvec, | |
3626 | + }, | |
3627 | + { | |
3628 | + .ctl_name = NET_IPV4_NF_CONNTRACK_BUCKETS, | |
3629 | + .procname = "ip_conntrack_buckets", | |
3630 | + .data = &ip_conntrack_htable_size, | |
3631 | + .maxlen = sizeof(unsigned int), | |
3632 | + .mode = 0444, | |
3633 | + .proc_handler = &proc_dointvec, | |
3634 | + }, | |
3635 | + { | |
3636 | + .ctl_name = NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_SYN_SENT, | |
3637 | + .procname = "ip_conntrack_tcp_timeout_syn_sent", | |
3638 | + .data = &ip_ct_tcp_timeout_syn_sent, | |
3639 | + .maxlen = sizeof(unsigned int), | |
3640 | + .mode = 0644, | |
3641 | + .proc_handler = &proc_dointvec_jiffies, | |
3642 | + }, | |
3643 | + { | |
3644 | + .ctl_name = NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_SYN_RECV, | |
3645 | + .procname = "ip_conntrack_tcp_timeout_syn_recv", | |
3646 | + .data = &ip_ct_tcp_timeout_syn_recv, | |
3647 | + .maxlen = sizeof(unsigned int), | |
3648 | + .mode = 0644, | |
3649 | + .proc_handler = &proc_dointvec_jiffies, | |
3650 | + }, | |
3651 | + { | |
3652 | + .ctl_name = NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_ESTABLISHED, | |
3653 | + .procname = "ip_conntrack_tcp_timeout_established", | |
3654 | + .data = &ip_ct_tcp_timeout_established, | |
3655 | + .maxlen = sizeof(unsigned int), | |
3656 | + .mode = 0644, | |
3657 | + .proc_handler = &proc_dointvec_jiffies, | |
3658 | + }, | |
3659 | + { | |
3660 | + .ctl_name = NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_FIN_WAIT, | |
3661 | + .procname = "ip_conntrack_tcp_timeout_fin_wait", | |
3662 | + .data = &ip_ct_tcp_timeout_fin_wait, | |
3663 | + .maxlen = sizeof(unsigned int), | |
3664 | + .mode = 0644, | |
3665 | + .proc_handler = &proc_dointvec_jiffies, | |
3666 | + }, | |
3667 | + { | |
3668 | + .ctl_name = NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_CLOSE_WAIT, | |
3669 | + .procname = "ip_conntrack_tcp_timeout_close_wait", | |
3670 | + .data = &ip_ct_tcp_timeout_close_wait, | |
3671 | + .maxlen = sizeof(unsigned int), | |
3672 | + .mode = 0644, | |
3673 | + .proc_handler = &proc_dointvec_jiffies, | |
3674 | + }, | |
3675 | + { | |
3676 | + .ctl_name = NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_LAST_ACK, | |
3677 | + .procname = "ip_conntrack_tcp_timeout_last_ack", | |
3678 | + .data = &ip_ct_tcp_timeout_last_ack, | |
3679 | + .maxlen = sizeof(unsigned int), | |
3680 | + .mode = 0644, | |
3681 | + .proc_handler = &proc_dointvec_jiffies, | |
3682 | + }, | |
3683 | + { | |
3684 | + .ctl_name = NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_TIME_WAIT, | |
3685 | + .procname = "ip_conntrack_tcp_timeout_time_wait", | |
3686 | + .data = &ip_ct_tcp_timeout_time_wait, | |
3687 | + .maxlen = sizeof(unsigned int), | |
3688 | + .mode = 0644, | |
3689 | + .proc_handler = &proc_dointvec_jiffies, | |
3690 | + }, | |
3691 | + { | |
3692 | + .ctl_name = NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_CLOSE, | |
3693 | + .procname = "ip_conntrack_tcp_timeout_close", | |
3694 | + .data = &ip_ct_tcp_timeout_close, | |
3695 | + .maxlen = sizeof(unsigned int), | |
3696 | + .mode = 0644, | |
3697 | + .proc_handler = &proc_dointvec_jiffies, | |
3698 | + }, | |
3699 | + { | |
3700 | + .ctl_name = NET_IPV4_NF_CONNTRACK_UDP_TIMEOUT, | |
3701 | + .procname = "ip_conntrack_udp_timeout", | |
3702 | + .data = &ip_ct_udp_timeout, | |
3703 | + .maxlen = sizeof(unsigned int), | |
3704 | + .mode = 0644, | |
3705 | + .proc_handler = &proc_dointvec_jiffies, | |
3706 | + }, | |
3707 | + { | |
3708 | + .ctl_name = NET_IPV4_NF_CONNTRACK_UDP_TIMEOUT_STREAM, | |
3709 | + .procname = "ip_conntrack_udp_timeout_stream", | |
3710 | + .data = &ip_ct_udp_timeout_stream, | |
3711 | + .maxlen = sizeof(unsigned int), | |
3712 | + .mode = 0644, | |
3713 | + .proc_handler = &proc_dointvec_jiffies, | |
3714 | + }, | |
3715 | + { | |
3716 | + .ctl_name = NET_IPV4_NF_CONNTRACK_ICMP_TIMEOUT, | |
3717 | + .procname = "ip_conntrack_icmp_timeout", | |
3718 | + .data = &ip_ct_icmp_timeout, | |
3719 | + .maxlen = sizeof(unsigned int), | |
3720 | + .mode = 0644, | |
3721 | + .proc_handler = &proc_dointvec_jiffies, | |
3722 | + }, | |
3723 | + { | |
3724 | + .ctl_name = NET_IPV4_NF_CONNTRACK_GENERIC_TIMEOUT, | |
3725 | + .procname = "ip_conntrack_generic_timeout", | |
3726 | + .data = &ip_ct_generic_timeout, | |
3727 | + .maxlen = sizeof(unsigned int), | |
3728 | + .mode = 0644, | |
3729 | + .proc_handler = &proc_dointvec_jiffies, | |
3730 | + }, | |
3731 | + { .ctl_name = 0 } | |
3732 | +}; | |
3733 | + | |
3734 | +#define NET_IP_CONNTRACK_MAX 2089 | |
3735 | + | |
3736 | +static ctl_table ip_ct_netfilter_table[] = { | |
3737 | + { | |
3738 | + .ctl_name = NET_IPV4_NETFILTER, | |
3739 | + .procname = "netfilter", | |
3740 | + .mode = 0555, | |
3741 | + .child = ip_ct_sysctl_table, | |
3742 | + }, | |
3743 | + { | |
3744 | + .ctl_name = NET_IP_CONNTRACK_MAX, | |
3745 | + .procname = "ip_conntrack_max", | |
3746 | + .data = &ip_conntrack_max, | |
3747 | + .maxlen = sizeof(int), | |
3748 | + .mode = 0644, | |
3749 | + .proc_handler = &proc_dointvec | |
3750 | + }, | |
3751 | + { .ctl_name = 0 } | |
3752 | +}; | |
3753 | + | |
3754 | +static ctl_table ip_ct_ipv4_table[] = { | |
3755 | + { | |
3756 | + .ctl_name = NET_IPV4, | |
3757 | + .procname = "ipv4", | |
3758 | + .mode = 0555, | |
3759 | + .child = ip_ct_netfilter_table, | |
3760 | + }, | |
3761 | + { .ctl_name = 0 } | |
3762 | +}; | |
3763 | + | |
3764 | +static ctl_table ip_ct_net_table[] = { | |
3765 | + { | |
3766 | + .ctl_name = CTL_NET, | |
3767 | + .procname = "net", | |
3768 | + .mode = 0555, | |
3769 | + .child = ip_ct_ipv4_table, | |
3770 | + }, | |
3771 | + { .ctl_name = 0 } | |
3772 | +}; | |
3773 | +#endif | |
3774 | +static int init_or_cleanup(int init) | |
3775 | +{ | |
3776 | + struct proc_dir_entry *proc; | |
3777 | + int ret = 0; | |
3778 | + | |
3779 | + if (!init) goto cleanup; | |
3780 | + | |
3781 | + ret = ip_conntrack_init(); | |
3782 | + if (ret < 0) | |
3783 | + goto cleanup_nothing; | |
3784 | + | |
3785 | + proc = proc_net_create("ip_conntrack",0,list_conntracks); | |
3786 | + if (!proc) goto cleanup_init; | |
3787 | + proc->owner = THIS_MODULE; | |
3788 | + | |
3789 | + ret = nf_register_hook(&ip_conntrack_in_ops); | |
3790 | + if (ret < 0) { | |
3791 | + printk("ip_conntrack: can't register pre-routing hook.\n"); | |
3792 | + goto cleanup_proc; | |
3793 | + } | |
3794 | + ret = nf_register_hook(&ip_conntrack_local_out_ops); | |
3795 | + if (ret < 0) { | |
3796 | + printk("ip_conntrack: can't register local out hook.\n"); | |
3797 | + goto cleanup_inops; | |
3798 | + } | |
3799 | + ret = nf_register_hook(&ip_conntrack_out_ops); | |
3800 | + if (ret < 0) { | |
3801 | + printk("ip_conntrack: can't register post-routing hook.\n"); | |
3802 | + goto cleanup_inandlocalops; | |
3803 | + } | |
3804 | + ret = nf_register_hook(&ip_conntrack_local_in_ops); | |
3805 | + if (ret < 0) { | |
3806 | + printk("ip_conntrack: can't register local in hook.\n"); | |
3807 | + goto cleanup_inoutandlocalops; | |
3808 | + } | |
3809 | +#ifdef CONFIG_SYSCTL | |
3810 | + ip_ct_sysctl_header = register_sysctl_table(ip_ct_net_table, 0); | |
3811 | + if (ip_ct_sysctl_header == NULL) { | |
3812 | + printk("ip_conntrack: can't register to sysctl.\n"); | |
3813 | + goto cleanup; | |
3814 | + } | |
3815 | +#endif | |
3816 | + | |
3817 | + return ret; | |
3818 | + | |
3819 | + cleanup: | |
3820 | +#ifdef CONFIG_SYSCTL | |
3821 | + unregister_sysctl_table(ip_ct_sysctl_header); | |
3822 | +#endif | |
3823 | + nf_unregister_hook(&ip_conntrack_local_in_ops); | |
3824 | + cleanup_inoutandlocalops: | |
3825 | + nf_unregister_hook(&ip_conntrack_out_ops); | |
3826 | + cleanup_inandlocalops: | |
3827 | + nf_unregister_hook(&ip_conntrack_local_out_ops); | |
3828 | + cleanup_inops: | |
3829 | + nf_unregister_hook(&ip_conntrack_in_ops); | |
3830 | + cleanup_proc: | |
3831 | + proc_net_remove("ip_conntrack"); | |
3832 | + cleanup_init: | |
3833 | + ip_conntrack_cleanup(); | |
3834 | + cleanup_nothing: | |
3835 | + return ret; | |
3836 | +} | |
3837 | + | |
3838 | +/* FIXME: Allow NULL functions and sub in pointers to generic for | |
3839 | + them. --RR */ | |
3840 | +int ip_conntrack_protocol_register(struct ip_conntrack_protocol *proto) | |
3841 | +{ | |
3842 | + int ret = 0; | |
3843 | + struct list_head *i; | |
3844 | + | |
3845 | + WRITE_LOCK(&ip_conntrack_lock); | |
3846 | + list_for_each(i, &protocol_list) { | |
3847 | + if (((struct ip_conntrack_protocol *)i)->proto | |
3848 | + == proto->proto) { | |
3849 | + ret = -EBUSY; | |
3850 | + goto out; | |
3851 | + } | |
3852 | + } | |
3853 | + | |
3854 | + list_prepend(&protocol_list, proto); | |
3855 | + | |
3856 | + out: | |
3857 | + WRITE_UNLOCK(&ip_conntrack_lock); | |
3858 | + return ret; | |
3859 | +} | |
3860 | + | |
3861 | +void ip_conntrack_protocol_unregister(struct ip_conntrack_protocol *proto) | |
3862 | +{ | |
3863 | + WRITE_LOCK(&ip_conntrack_lock); | |
3864 | + | |
3865 | + /* ip_ct_find_proto() returns proto_generic in case there is no protocol | |
3866 | + * helper. So this should be enough - HW */ | |
3867 | + LIST_DELETE(&protocol_list, proto); | |
3868 | + WRITE_UNLOCK(&ip_conntrack_lock); | |
3869 | + | |
3870 | + /* Somebody could be still looking at the proto in bh. */ | |
3871 | + synchronize_net(); | |
3872 | + | |
3873 | + /* Remove all contrack entries for this protocol */ | |
3874 | + ip_ct_selective_cleanup(kill_proto, &proto->proto); | |
3875 | +} | |
3876 | + | |
3877 | +static int __init init(void) | |
3878 | +{ | |
3879 | + return init_or_cleanup(1); | |
3880 | +} | |
3881 | + | |
3882 | +static void __exit fini(void) | |
3883 | +{ | |
3884 | + init_or_cleanup(0); | |
3885 | +} | |
3886 | + | |
3887 | +module_init(init); | |
3888 | +module_exit(fini); | |
3889 | + | |
3890 | +/* Some modules need us, but don't depend directly on any symbol. | |
3891 | + They should call this. */ | |
3892 | +void need_ip_conntrack(void) | |
3893 | +{ | |
3894 | +} | |
3895 | + | |
3896 | +EXPORT_SYMBOL(ip_conntrack_protocol_register); | |
3897 | +EXPORT_SYMBOL(ip_conntrack_protocol_unregister); | |
3898 | +EXPORT_SYMBOL(invert_tuplepr); | |
3899 | +EXPORT_SYMBOL(ip_conntrack_alter_reply); | |
3900 | +EXPORT_SYMBOL(ip_conntrack_destroyed); | |
3901 | +EXPORT_SYMBOL(ip_conntrack_get); | |
3902 | +EXPORT_SYMBOL(need_ip_conntrack); | |
3903 | +EXPORT_SYMBOL(ip_conntrack_helper_register); | |
3904 | +EXPORT_SYMBOL(ip_conntrack_helper_unregister); | |
3905 | +EXPORT_SYMBOL(ip_ct_selective_cleanup); | |
3906 | +EXPORT_SYMBOL(ip_ct_refresh); | |
3907 | +EXPORT_SYMBOL(ip_ct_find_proto); | |
3908 | +EXPORT_SYMBOL(__ip_ct_find_proto); | |
3909 | +EXPORT_SYMBOL(ip_ct_find_helper); | |
3910 | +EXPORT_SYMBOL(ip_conntrack_expect_related); | |
3911 | +EXPORT_SYMBOL(ip_conntrack_change_expect); | |
3912 | +EXPORT_SYMBOL(ip_conntrack_unexpect_related); | |
3913 | +EXPORT_SYMBOL_GPL(ip_conntrack_expect_find_get); | |
3914 | +EXPORT_SYMBOL_GPL(ip_conntrack_expect_put); | |
3915 | +EXPORT_SYMBOL(ip_conntrack_tuple_taken); | |
3916 | +EXPORT_SYMBOL(ip_ct_gather_frags); | |
3917 | +EXPORT_SYMBOL(ip_conntrack_htable_size); | |
3918 | +EXPORT_SYMBOL(ip_conntrack_expect_list); | |
3919 | +EXPORT_SYMBOL(ip_conntrack_lock); | |
3920 | +EXPORT_SYMBOL(ip_conntrack_hash); | |
3921 | +EXPORT_SYMBOL_GPL(ip_conntrack_find_get); | |
3922 | +EXPORT_SYMBOL_GPL(ip_conntrack_put); | |
3923 | diff -Nur linux-2.6.4-rc2.org/net/ipv4/netfilter/ip_nat_core.c linux-2.6.4-rc2/net/ipv4/netfilter/ip_nat_core.c | |
3924 | --- linux-2.6.4-rc2.org/net/ipv4/netfilter/ip_nat_core.c 2004-03-04 06:16:37.000000000 +0000 | |
3925 | +++ linux-2.6.4-rc2/net/ipv4/netfilter/ip_nat_core.c 2004-03-05 07:39:43.000000000 +0000 | |
3926 | @@ -96,9 +96,16 @@ | |
3927 | WRITE_UNLOCK(&ip_nat_lock); | |
3928 | } | |
3929 | ||
3930 | -/* We do checksum mangling, so if they were wrong before they're still | |
3931 | - * wrong. Also works for incomplete packets (eg. ICMP dest | |
3932 | - * unreachables.) */ | |
3933 | +/** | |
3934 | + * ip_nat_cheat_check - Incremental checksum change for IP/TCP checksum | |
3935 | + * @oldvalinv: bit-inverted old value of 32bit word | |
3936 | + * @newval: new value of 32bit word | |
3937 | + * @oldcheck: old checksum value | |
3938 | + * | |
3939 | + * This function implements incremental checksum mangling, so if a checksum | |
3940 | + * was wrong it will still be wrong after mangling. Also works for incomplete | |
3941 | + * packets (eg. ICMP dest unreachables). Return value is the new checksum. | |
3942 | + */ | |
3943 | u_int16_t | |
3944 | ip_nat_cheat_check(u_int32_t oldvalinv, u_int32_t newval, u_int16_t oldcheck) | |
3945 | { | |
3946 | @@ -124,7 +131,14 @@ | |
3947 | return i; | |
3948 | } | |
3949 | ||
3950 | -/* Is this tuple already taken? (not by us) */ | |
3951 | +/** | |
3952 | + * ip_nat_used_tuple - Is this tuple already in use? | |
3953 | + * @tuple: tuple to be used for this check | |
3954 | + * @ignored_conntrack: conntrack excluded from this check | |
3955 | + * | |
3956 | + * This function checks for the reply (inverted) tuple in the conntrack | |
3957 | + * hash. This is necessarry with NAT, since there is no fixed mapping. | |
3958 | + */ | |
3959 | int | |
3960 | ip_nat_used_tuple(const struct ip_conntrack_tuple *tuple, | |
3961 | const struct ip_conntrack *ignored_conntrack) | |
3962 | @@ -515,6 +529,19 @@ | |
3963 | #endif | |
3964 | }; | |
3965 | ||
3966 | +/** | |
3967 | + * ip_nat_setup_info - Set up NAT mappings for NEW packet | |
3968 | + * @conntrack: conntrack on which we operate | |
3969 | + * @mr: address/port range which is valid for this NAT mapping | |
3970 | + * @hooknum: hook at which this NAT mapping applies | |
3971 | + * | |
3972 | + * This function is called by NAT targets (SNAT,DNAT,...) and by | |
3973 | + * the NAT application helper modules. It is called for the NEW packet | |
3974 | + * of a connection in order to specify which NAT mappings shall apply to | |
3975 | + * this connection at a given hook. | |
3976 | + * | |
3977 | + * Note: The reply mappings are created automagically by this function. | |
3978 | + */ | |
3979 | unsigned int | |
3980 | ip_nat_setup_info(struct ip_conntrack *conntrack, | |
3981 | const struct ip_nat_multi_range *mr, | |
3982 | diff -Nur linux-2.6.4-rc2.org/net/ipv4/netfilter/ip_nat_helper.c linux-2.6.4-rc2/net/ipv4/netfilter/ip_nat_helper.c | |
3983 | --- linux-2.6.4-rc2.org/net/ipv4/netfilter/ip_nat_helper.c 2004-03-04 06:16:38.000000000 +0000 | |
3984 | +++ linux-2.6.4-rc2/net/ipv4/netfilter/ip_nat_helper.c 2004-03-05 07:39:43.000000000 +0000 | |
3985 | @@ -150,9 +150,19 @@ | |
3986 | return 1; | |
3987 | } | |
3988 | ||
3989 | -/* Generic function for mangling variable-length address changes inside | |
3990 | - * NATed TCP connections (like the PORT XXX,XXX,XXX,XXX,XXX,XXX | |
3991 | - * command in FTP). | |
3992 | +/** | |
3993 | + * ip_nat_mangle_tcp_packet - Mangle and potentially resize payload packet | |
3994 | + * @skb: pointer to skb of packet on which we operate | |
3995 | + * @ct: conntrack of the connection to which this packet belongs | |
3996 | + * @ctinfo: conntrack_info of the connection to which this packet belongs | |
3997 | + * @match_offset: offset in bytes where to-be-manipulated part starts | |
3998 | + * @match_len: lenght of the to-be-manipulated part | |
3999 | + * @rep_buffer: pointer to buffer containing replacement | |
4000 | + * @rep_len: length of replacement | |
4001 | + * | |
4002 | + * Generic function for mangling fixed and variable-length changes inside | |
4003 | + * NATed TCP connections (like the PORT XXX,XXX,XXX,XXX,XXX,XXX command | |
4004 | + * in FTP). | |
4005 | * | |
4006 | * Takes care about all the nasty sequence number changes, checksumming, | |
4007 | * skb enlargement, ... | |
4008 | @@ -198,16 +208,27 @@ | |
4009 | return 1; | |
4010 | } | |
4011 | ||
4012 | -/* Generic function for mangling variable-length address changes inside | |
4013 | - * NATed UDP connections (like the CONNECT DATA XXXXX MESG XXXXX INDEX XXXXX | |
4014 | - * command in the Amanda protocol) | |
4015 | +/** | |
4016 | + * ip_nat_mangle_udp_packet - Mangle and potentially resize payload packet | |
4017 | + * @skb: pointer to skb of packet on which we operate | |
4018 | + * @ct: conntrack of the connection to which this packet belongs | |
4019 | + * @ctinfo: conntrack_info of the connection to which this packet belongs | |
4020 | + * @match_offset: offset in bytes where to-be-manipulated part starts | |
4021 | + * @match_len: lenght of the to-be-manipulated part | |
4022 | + * @rep_buffer: pointer to buffer containing replacement | |
4023 | + * @rep_len: length of replacement | |
4024 | + * | |
4025 | + * Generic function for mangling fixed and variable-length changes inside | |
4026 | + * NATed TCP connections (like the CONNECT DATA XXXXX MESG XXXXX INDEX XXXXX | |
4027 | + * commad in the Amanda protocol) | |
4028 | * | |
4029 | * Takes care about all the nasty sequence number changes, checksumming, | |
4030 | * skb enlargement, ... | |
4031 | * | |
4032 | - * XXX - This function could be merged with ip_nat_mangle_tcp_packet which | |
4033 | - * should be fairly easy to do. | |
4034 | - */ | |
4035 | + * FIXME: should be unified with ip_nat_mangle_tcp_packet!! | |
4036 | + * | |
4037 | + * */ | |
4038 | + | |
4039 | int | |
4040 | ip_nat_mangle_udp_packet(struct sk_buff **pskb, | |
4041 | struct ip_conntrack *ct, | |
4042 | @@ -405,6 +426,13 @@ | |
4043 | return ip_ct_tuple_mask_cmp(tuple, &helper->tuple, &helper->mask); | |
4044 | } | |
4045 | ||
4046 | +/** | |
4047 | + * ip_nat_helper_register - Register NAT application helper | |
4048 | + * @me: structure describing the helper | |
4049 | + * | |
4050 | + * This function is called by NAT application helpers to register | |
4051 | + * themselves with the NAT core. | |
4052 | + */ | |
4053 | int ip_nat_helper_register(struct ip_nat_helper *me) | |
4054 | { | |
4055 | int ret = 0; | |
4056 | @@ -431,6 +459,13 @@ | |
4057 | return ret; | |
4058 | } | |
4059 | ||
4060 | +/** | |
4061 | + * ip_nat_helper_unregister - Unregister NAT application helper | |
4062 | + * @me: structure describing the helper | |
4063 | + * | |
4064 | + * This function is called by NAT application helpers to unregister | |
4065 | + * themselves from the NAT core. | |
4066 | + */ | |
4067 | void ip_nat_helper_unregister(struct ip_nat_helper *me) | |
4068 | { | |
4069 | WRITE_LOCK(&ip_nat_lock); | |
4070 | diff -Nur linux-2.6.4-rc2.org/net/ipv4/netfilter/ip_nat_standalone.c linux-2.6.4-rc2/net/ipv4/netfilter/ip_nat_standalone.c | |
4071 | --- linux-2.6.4-rc2.org/net/ipv4/netfilter/ip_nat_standalone.c 2004-03-04 06:16:55.000000000 +0000 | |
4072 | +++ linux-2.6.4-rc2/net/ipv4/netfilter/ip_nat_standalone.c 2004-03-05 07:39:43.000000000 +0000 | |
4073 | @@ -266,7 +266,13 @@ | |
4074 | }; | |
4075 | #endif | |
4076 | ||
4077 | -/* Protocol registration. */ | |
4078 | +/** | |
4079 | + * ip_nat_protocol_register - Register a layer 4 protocol helper | |
4080 | + * @proto: structure describing this helper | |
4081 | + * | |
4082 | + * This function is called by NAT layer 4 protocol helpers to register | |
4083 | + * themselvers with the NAT core. | |
4084 | + */ | |
4085 | int ip_nat_protocol_register(struct ip_nat_protocol *proto) | |
4086 | { | |
4087 | int ret = 0; | |
4088 | @@ -287,9 +293,16 @@ | |
4089 | return ret; | |
4090 | } | |
4091 | ||
4092 | -/* Noone stores the protocol anywhere; simply delete it. */ | |
4093 | +/** | |
4094 | + * ip_nat_protocol_unregister - Unregister a layer 4 protocol helper | |
4095 | + * @proto: structure describing the helper | |
4096 | + * | |
4097 | + * This function is called by NAT layer 4 protocol helpers to | |
4098 | + * unregister themselves from the NAT core. | |
4099 | + */ | |
4100 | void ip_nat_protocol_unregister(struct ip_nat_protocol *proto) | |
4101 | { | |
4102 | + /* Noone stores the protocol anywhere; simply delete it. */ | |
4103 | WRITE_LOCK(&ip_nat_lock); | |
4104 | LIST_DELETE(&protos, proto); | |
4105 | WRITE_UNLOCK(&ip_nat_lock); | |
4106 | diff -Nur linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_IPV4OPTSSTRIP.c linux-2.6.4-rc2/net/ipv4/netfilter/ipt_IPV4OPTSSTRIP.c | |
4107 | --- linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_IPV4OPTSSTRIP.c 1970-01-01 00:00:00.000000000 +0000 | |
4108 | +++ linux-2.6.4-rc2/net/ipv4/netfilter/ipt_IPV4OPTSSTRIP.c 2004-03-05 07:39:55.000000000 +0000 | |
4109 | @@ -0,0 +1,89 @@ | |
4110 | +/** | |
4111 | + * Strip all IP options in the IP packet header. | |
4112 | + * | |
4113 | + * (C) 2001 by Fabrice MARIE <fabrice@netfilter.org> | |
4114 | + * This software is distributed under GNU GPL v2, 1991 | |
4115 | + */ | |
4116 | + | |
4117 | +#include <linux/module.h> | |
4118 | +#include <linux/skbuff.h> | |
4119 | +#include <linux/ip.h> | |
4120 | +#include <net/checksum.h> | |
4121 | + | |
4122 | +#include <linux/netfilter_ipv4/ip_tables.h> | |
4123 | + | |
4124 | +MODULE_AUTHOR("Fabrice MARIE <fabrice@netfilter.org>"); | |
4125 | +MODULE_DESCRIPTION("Strip all options in IPv4 packets"); | |
4126 | +MODULE_LICENSE("GPL"); | |
4127 | + | |
4128 | +static unsigned int | |
4129 | +target(struct sk_buff **pskb, | |
4130 | + const struct net_device *in, | |
4131 | + const struct net_device *out, | |
4132 | + unsigned int hooknum, | |
4133 | + const void *targinfo, | |
4134 | + void *userinfo) | |
4135 | +{ | |
4136 | + struct iphdr *iph; | |
4137 | + struct sk_buff *skb; | |
4138 | + struct ip_options *opt; | |
4139 | + unsigned char *optiph; | |
4140 | + int l; | |
4141 | + | |
4142 | + if (!skb_ip_make_writable(pskb, (*pskb)->len)) | |
4143 | + return NF_DROP; | |
4144 | + | |
4145 | + skb = (*pskb); | |
4146 | + iph = (*pskb)->nh.iph; | |
4147 | + optiph = skb->nh.raw; | |
4148 | + l = ((struct ip_options *)(&(IPCB(skb)->opt)))->optlen; | |
4149 | + | |
4150 | + /* if no options in packet then nothing to clear. */ | |
4151 | + if (iph->ihl * 4 == sizeof(struct iphdr)) | |
4152 | + return IPT_CONTINUE; | |
4153 | + | |
4154 | + /* else clear all options */ | |
4155 | + memset(&(IPCB(skb)->opt), 0, sizeof(struct ip_options)); | |
4156 | + memset(optiph+sizeof(struct iphdr), IPOPT_NOOP, l); | |
4157 | + opt = &(IPCB(skb)->opt); | |
4158 | + opt->is_data = 0; | |
4159 | + opt->optlen = l; | |
4160 | + | |
4161 | + skb->nfcache |= NFC_ALTERED; | |
4162 | + | |
4163 | + return IPT_CONTINUE; | |
4164 | +} | |
4165 | + | |
4166 | +static int | |
4167 | +checkentry(const char *tablename, | |
4168 | + const struct ipt_entry *e, | |
4169 | + void *targinfo, | |
4170 | + unsigned int targinfosize, | |
4171 | + unsigned int hook_mask) | |
4172 | +{ | |
4173 | + if (strcmp(tablename, "mangle")) { | |
4174 | + printk(KERN_WARNING "IPV4OPTSSTRIP: can only be called from \"mangle\" table, not \"%s\"\n", tablename); | |
4175 | + return 0; | |
4176 | + } | |
4177 | + /* nothing else to check because no parameters */ | |
4178 | + return 1; | |
4179 | +} | |
4180 | + | |
4181 | +static struct ipt_target ipt_ipv4optsstrip_reg = { | |
4182 | + .name = "IPV4OPTSSTRIP", | |
4183 | + .target = target, | |
4184 | + .checkentry = checkentry, | |
4185 | + .me = THIS_MODULE }; | |
4186 | + | |
4187 | +static int __init init(void) | |
4188 | +{ | |
4189 | + return ipt_register_target(&ipt_ipv4optsstrip_reg); | |
4190 | +} | |
4191 | + | |
4192 | +static void __exit fini(void) | |
4193 | +{ | |
4194 | + ipt_unregister_target(&ipt_ipv4optsstrip_reg); | |
4195 | +} | |
4196 | + | |
4197 | +module_init(init); | |
4198 | +module_exit(fini); | |
4199 | diff -Nur linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_TTL.c linux-2.6.4-rc2/net/ipv4/netfilter/ipt_TTL.c | |
4200 | --- linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_TTL.c 1970-01-01 00:00:00.000000000 +0000 | |
4201 | +++ linux-2.6.4-rc2/net/ipv4/netfilter/ipt_TTL.c 2004-03-05 07:40:01.000000000 +0000 | |
4202 | @@ -0,0 +1,120 @@ | |
4203 | +/* TTL modification target for IP tables | |
4204 | + * (C) 2000 by Harald Welte <laforge@gnumonks.org> | |
4205 | + * | |
4206 | + * Version: $Revision$ | |
4207 | + * | |
4208 | + * This software is distributed under the terms of GNU GPL | |
4209 | + */ | |
4210 | + | |
4211 | +#include <linux/module.h> | |
4212 | +#include <linux/skbuff.h> | |
4213 | +#include <linux/ip.h> | |
4214 | +#include <net/checksum.h> | |
4215 | + | |
4216 | +#include <linux/netfilter_ipv4/ip_tables.h> | |
4217 | +#include <linux/netfilter_ipv4/ipt_TTL.h> | |
4218 | + | |
4219 | +MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>"); | |
4220 | +MODULE_DESCRIPTION("IP tables TTL modification module"); | |
4221 | +MODULE_LICENSE("GPL"); | |
4222 | + | |
4223 | +static unsigned int | |
4224 | +ipt_ttl_target(struct sk_buff **pskb, const struct net_device *in, | |
4225 | + const struct net_device *out, unsigned int hooknum, | |
4226 | + const void *targinfo, void *userinfo) | |
4227 | +{ | |
4228 | + struct iphdr *iph; | |
4229 | + const struct ipt_TTL_info *info = targinfo; | |
4230 | + u_int16_t diffs[2]; | |
4231 | + int new_ttl; | |
4232 | + | |
4233 | + if (!skb_ip_make_writable(pskb, (*pskb)->len)) | |
4234 | + return NF_DROP; | |
4235 | + | |
4236 | + iph = (*pskb)->nh.iph; | |
4237 | + | |
4238 | + switch (info->mode) { | |
4239 | + case IPT_TTL_SET: | |
4240 | + new_ttl = info->ttl; | |
4241 | + break; | |
4242 | + case IPT_TTL_INC: | |
4243 | + new_ttl = iph->ttl + info->ttl; | |
4244 | + if (new_ttl > 255) | |
4245 | + new_ttl = 255; | |
4246 | + break; | |
4247 | + case IPT_TTL_DEC: | |
4248 | + new_ttl = iph->ttl + info->ttl; | |
4249 | + if (new_ttl < 0) | |
4250 | + new_ttl = 0; | |
4251 | + break; | |
4252 | + default: | |
4253 | + new_ttl = iph->ttl; | |
4254 | + break; | |
4255 | + } | |
4256 | + | |
4257 | + if (new_ttl != iph->ttl) { | |
4258 | + diffs[0] = htons(((unsigned)iph->ttl) << 8) ^ 0xFFFF; | |
4259 | + iph->ttl = new_ttl; | |
4260 | + diffs[1] = htons(((unsigned)iph->ttl) << 8); | |
4261 | + iph->check = csum_fold(csum_partial((char *)diffs, | |
4262 | + sizeof(diffs), | |
4263 | + iph->check^0xFFFF)); | |
4264 | + (*pskb)->nfcache |= NFC_ALTERED; | |
4265 | + } | |
4266 | + | |
4267 | + return IPT_CONTINUE; | |
4268 | +} | |
4269 | + | |
4270 | +static int ipt_ttl_checkentry(const char *tablename, | |
4271 | + const struct ipt_entry *e, | |
4272 | + void *targinfo, | |
4273 | + unsigned int targinfosize, | |
4274 | + unsigned int hook_mask) | |
4275 | +{ | |
4276 | + struct ipt_TTL_info *info = targinfo; | |
4277 | + | |
4278 | + if (targinfosize != IPT_ALIGN(sizeof(struct ipt_TTL_info))) { | |
4279 | + printk(KERN_WARNING "TTL: targinfosize %u != %Zu\n", | |
4280 | + targinfosize, | |
4281 | + IPT_ALIGN(sizeof(struct ipt_TTL_info))); | |
4282 | + return 0; | |
4283 | + } | |
4284 | + | |
4285 | + if (strcmp(tablename, "mangle")) { | |
4286 | + printk(KERN_WARNING "TTL: can only be called from \"mangle\" table, not \"%s\"\n", tablename); | |
4287 | + return 0; | |
4288 | + } | |
4289 | + | |
4290 | + if (info->mode > IPT_TTL_MAXMODE) { | |
4291 | + printk(KERN_WARNING "TTL: invalid or unknown Mode %u\n", | |
4292 | + info->mode); | |
4293 | + return 0; | |
4294 | + } | |
4295 | + | |
4296 | + if ((info->mode != IPT_TTL_SET) && (info->ttl == 0)) { | |
4297 | + printk(KERN_WARNING "TTL: increment/decrement doesn't make sense with value 0\n"); | |
4298 | + return 0; | |
4299 | + } | |
4300 | + | |
4301 | + return 1; | |
4302 | +} | |
4303 | + | |
4304 | +static struct ipt_target ipt_TTL = { | |
4305 | + .name = "TTL", | |
4306 | + .target = ipt_ttl_target, | |
4307 | + .checkentry = ipt_ttl_checkentry, | |
4308 | + .me = THIS_MODULE | |
4309 | +}; | |
4310 | + | |
4311 | +static int __init init(void) | |
4312 | +{ | |
4313 | + return ipt_register_target(&ipt_TTL); | |
4314 | +} | |
4315 | + | |
4316 | +static void __exit fini(void) | |
4317 | +{ | |
4318 | + ipt_unregister_target(&ipt_TTL); | |
4319 | +} | |
4320 | + | |
4321 | +module_init(init); | |
4322 | +module_exit(fini); | |
4323 | diff -Nur linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_connlimit.c linux-2.6.4-rc2/net/ipv4/netfilter/ipt_connlimit.c | |
4324 | --- linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_connlimit.c 1970-01-01 00:00:00.000000000 +0000 | |
4325 | +++ linux-2.6.4-rc2/net/ipv4/netfilter/ipt_connlimit.c 2004-03-05 07:40:04.000000000 +0000 | |
4326 | @@ -0,0 +1,230 @@ | |
4327 | +/* | |
4328 | + * netfilter module to limit the number of parallel tcp | |
4329 | + * connections per IP address. | |
4330 | + * (c) 2000 Gerd Knorr <kraxel@bytesex.org> | |
4331 | + * Nov 2002: Martin Bene <martin.bene@icomedias.com>: | |
4332 | + * only ignore TIME_WAIT or gone connections | |
4333 | + * | |
4334 | + * based on ... | |
4335 | + * | |
4336 | + * Kernel module to match connection tracking information. | |
4337 | + * GPL (C) 1999 Rusty Russell (rusty@rustcorp.com.au). | |
4338 | + */ | |
4339 | +#include <linux/module.h> | |
4340 | +#include <linux/skbuff.h> | |
4341 | +#include <linux/list.h> | |
4342 | +#include <linux/netfilter_ipv4/ip_conntrack.h> | |
4343 | +#include <linux/netfilter_ipv4/ip_conntrack_core.h> | |
4344 | +#include <linux/netfilter_ipv4/ip_conntrack_tcp.h> | |
4345 | +#include <linux/netfilter_ipv4/ip_tables.h> | |
4346 | +#include <linux/netfilter_ipv4/ipt_connlimit.h> | |
4347 | + | |
4348 | +#define DEBUG 0 | |
4349 | + | |
4350 | +MODULE_LICENSE("GPL"); | |
4351 | + | |
4352 | +/* we'll save the tuples of all connections we care about */ | |
4353 | +struct ipt_connlimit_conn | |
4354 | +{ | |
4355 | + struct list_head list; | |
4356 | + struct ip_conntrack_tuple tuple; | |
4357 | +}; | |
4358 | + | |
4359 | +struct ipt_connlimit_data { | |
4360 | + spinlock_t lock; | |
4361 | + struct list_head iphash[256]; | |
4362 | +}; | |
4363 | + | |
4364 | +static int ipt_iphash(u_int32_t addr) | |
4365 | +{ | |
4366 | + int hash; | |
4367 | + | |
4368 | + hash = addr & 0xff; | |
4369 | + hash ^= (addr >> 8) & 0xff; | |
4370 | + hash ^= (addr >> 16) & 0xff; | |
4371 | + hash ^= (addr >> 24) & 0xff; | |
4372 | + return hash; | |
4373 | +} | |
4374 | + | |
4375 | +static int count_them(struct ipt_connlimit_data *data, | |
4376 | + u_int32_t addr, u_int32_t mask, | |
4377 | + struct ip_conntrack *ct) | |
4378 | +{ | |
4379 | +#if DEBUG | |
4380 | + const static char *tcp[] = { "none", "established", "syn_sent", "syn_recv", | |
4381 | + "fin_wait", "time_wait", "close", "close_wait", | |
4382 | + "last_ack", "listen" }; | |
4383 | +#endif | |
4384 | + int addit = 1, matches = 0; | |
4385 | + struct ip_conntrack_tuple tuple; | |
4386 | + struct ip_conntrack_tuple_hash *found; | |
4387 | + struct ipt_connlimit_conn *conn; | |
4388 | + struct list_head *hash,*lh; | |
4389 | + | |
4390 | + spin_lock(&data->lock); | |
4391 | + tuple = ct->tuplehash[0].tuple; | |
4392 | + hash = &data->iphash[ipt_iphash(addr & mask)]; | |
4393 | + | |
4394 | + /* check the saved connections */ | |
4395 | + for (lh = hash->next; lh != hash; lh = lh->next) { | |
4396 | + conn = list_entry(lh,struct ipt_connlimit_conn,list); | |
4397 | + found = ip_conntrack_find_get(&conn->tuple,ct); | |
4398 | + if (0 == memcmp(&conn->tuple,&tuple,sizeof(tuple)) && | |
4399 | + found != NULL && | |
4400 | + found->ctrack->proto.tcp.state != TCP_CONNTRACK_TIME_WAIT) { | |
4401 | + /* Just to be sure we have it only once in the list. | |
4402 | + We should'nt see tuples twice unless someone hooks this | |
4403 | + into a table without "-p tcp --syn" */ | |
4404 | + addit = 0; | |
4405 | + } | |
4406 | +#if DEBUG | |
4407 | + printk("ipt_connlimit [%d]: src=%u.%u.%u.%u:%d dst=%u.%u.%u.%u:%d %s\n", | |
4408 | + ipt_iphash(addr & mask), | |
4409 | + NIPQUAD(conn->tuple.src.ip), ntohs(conn->tuple.src.u.tcp.port), | |
4410 | + NIPQUAD(conn->tuple.dst.ip), ntohs(conn->tuple.dst.u.tcp.port), | |
4411 | + (NULL != found) ? tcp[found->ctrack->proto.tcp.state] : "gone"); | |
4412 | +#endif | |
4413 | + if (NULL == found) { | |
4414 | + /* this one is gone */ | |
4415 | + lh = lh->prev; | |
4416 | + list_del(lh->next); | |
4417 | + kfree(conn); | |
4418 | + continue; | |
4419 | + } | |
4420 | + if (found->ctrack->proto.tcp.state == TCP_CONNTRACK_TIME_WAIT) { | |
4421 | + /* we don't care about connections which are | |
4422 | + closed already -> ditch it */ | |
4423 | + lh = lh->prev; | |
4424 | + list_del(lh->next); | |
4425 | + kfree(conn); | |
4426 | + nf_conntrack_put(&found->ctrack->infos[0]); | |
4427 | + continue; | |
4428 | + } | |
4429 | + if ((addr & mask) == (conn->tuple.src.ip & mask)) { | |
4430 | + /* same source IP address -> be counted! */ | |
4431 | + matches++; | |
4432 | + } | |
4433 | + nf_conntrack_put(&found->ctrack->infos[0]); | |
4434 | + } | |
4435 | + if (addit) { | |
4436 | + /* save the new connection in our list */ | |
4437 | +#if DEBUG | |
4438 | + printk("ipt_connlimit [%d]: src=%u.%u.%u.%u:%d dst=%u.%u.%u.%u:%d new\n", | |
4439 | + ipt_iphash(addr & mask), | |
4440 | + NIPQUAD(tuple.src.ip), ntohs(tuple.src.u.tcp.port), | |
4441 | + NIPQUAD(tuple.dst.ip), ntohs(tuple.dst.u.tcp.port)); | |
4442 | +#endif | |
4443 | + conn = kmalloc(sizeof(*conn),GFP_ATOMIC); | |
4444 | + if (NULL == conn) | |
4445 | + return -1; | |
4446 | + memset(conn,0,sizeof(*conn)); | |
4447 | + INIT_LIST_HEAD(&conn->list); | |
4448 | + conn->tuple = tuple; | |
4449 | + list_add(&conn->list,hash); | |
4450 | + matches++; | |
4451 | + } | |
4452 | + spin_unlock(&data->lock); | |
4453 | + return matches; | |
4454 | +} | |
4455 | + | |
4456 | +static int | |
4457 | +match(const struct sk_buff *skb, | |
4458 | + const struct net_device *in, | |
4459 | + const struct net_device *out, | |
4460 | + const void *matchinfo, | |
4461 | + int offset, | |
4462 | + int *hotdrop) | |
4463 | +{ | |
4464 | + const struct ipt_connlimit_info *info = matchinfo; | |
4465 | + int connections, match; | |
4466 | + struct ip_conntrack *ct; | |
4467 | + enum ip_conntrack_info ctinfo; | |
4468 | + | |
4469 | + ct = ip_conntrack_get((struct sk_buff *)skb, &ctinfo); | |
4470 | + if (NULL == ct) { | |
4471 | + printk("ipt_connlimit: Oops: invalid ct state ?\n"); | |
4472 | + *hotdrop = 1; | |
4473 | + return 0; | |
4474 | + } | |
4475 | + connections = count_them(info->data,skb->nh.iph->saddr,info->mask,ct); | |
4476 | + if (-1 == connections) { | |
4477 | + printk("ipt_connlimit: Hmm, kmalloc failed :-(\n"); | |
4478 | + *hotdrop = 1; /* let's free some memory :-) */ | |
4479 | + return 0; | |
4480 | + } | |
4481 | + match = (info->inverse) ? (connections <= info->limit) : (connections > info->limit); | |
4482 | +#if DEBUG | |
4483 | + printk("ipt_connlimit: src=%u.%u.%u.%u mask=%u.%u.%u.%u " | |
4484 | + "connections=%d limit=%d match=%s\n", | |
4485 | + NIPQUAD(skb->nh.iph->saddr), NIPQUAD(info->mask), | |
4486 | + connections, info->limit, match ? "yes" : "no"); | |
4487 | +#endif | |
4488 | + | |
4489 | + return match; | |
4490 | +} | |
4491 | + | |
4492 | +static int check(const char *tablename, | |
4493 | + const struct ipt_ip *ip, | |
4494 | + void *matchinfo, | |
4495 | + unsigned int matchsize, | |
4496 | + unsigned int hook_mask) | |
4497 | +{ | |
4498 | + struct ipt_connlimit_info *info = matchinfo; | |
4499 | + int i; | |
4500 | + | |
4501 | + /* verify size */ | |
4502 | + if (matchsize != IPT_ALIGN(sizeof(struct ipt_connlimit_info))) | |
4503 | + return 0; | |
4504 | + | |
4505 | + /* refuse anything but tcp */ | |
4506 | + if (ip->proto != IPPROTO_TCP) | |
4507 | + return 0; | |
4508 | + | |
4509 | + /* init private data */ | |
4510 | + info->data = kmalloc(sizeof(struct ipt_connlimit_data),GFP_KERNEL); | |
4511 | + spin_lock_init(&(info->data->lock)); | |
4512 | + for (i = 0; i < 256; i++) | |
4513 | + INIT_LIST_HEAD(&(info->data->iphash[i])); | |
4514 | + | |
4515 | + return 1; | |
4516 | +} | |
4517 | + | |
4518 | +static void destroy(void *matchinfo, unsigned int matchinfosize) | |
4519 | +{ | |
4520 | + struct ipt_connlimit_info *info = matchinfo; | |
4521 | + struct ipt_connlimit_conn *conn; | |
4522 | + struct list_head *hash; | |
4523 | + int i; | |
4524 | + | |
4525 | + /* cleanup */ | |
4526 | + for (i = 0; i < 256; i++) { | |
4527 | + hash = &(info->data->iphash[i]); | |
4528 | + while (hash != hash->next) { | |
4529 | + conn = list_entry(hash->next,struct ipt_connlimit_conn,list); | |
4530 | + list_del(hash->next); | |
4531 | + kfree(conn); | |
4532 | + } | |
4533 | + } | |
4534 | + kfree(info->data); | |
4535 | +} | |
4536 | + | |
4537 | +static struct ipt_match connlimit_match = { | |
4538 | + .name = "connlimit", | |
4539 | + .match = &match, | |
4540 | + .checkentry = &check, | |
4541 | + .destroy = &destroy, | |
4542 | + .me = THIS_MODULE | |
4543 | +}; | |
4544 | + | |
4545 | +static int __init init(void) | |
4546 | +{ | |
4547 | + return ipt_register_match(&connlimit_match); | |
4548 | +} | |
4549 | + | |
4550 | +static void __exit fini(void) | |
4551 | +{ | |
4552 | + ipt_unregister_match(&connlimit_match); | |
4553 | +} | |
4554 | + | |
4555 | +module_init(init); | |
4556 | +module_exit(fini); | |
4557 | diff -Nur linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_dstlimit.c linux-2.6.4-rc2/net/ipv4/netfilter/ipt_dstlimit.c | |
4558 | --- linux-2.6.4-rc2.org/net/ipv4/netfilter/ipt_dstlimit.c 1970-01-01 00:00:00.000000000 +0000 | |
4559 | +++ linux-2.6.4-rc2/net/ipv4/netfilter/ipt_dstlimit.c 2004-03-05 07:40:06.000000000 +0000 | |
4560 | @@ -0,0 +1,690 @@ | |
4561 | +/* iptables match extension to limit the number of packets per second | |
4562 | + * seperately for each destination. | |
4563 | + * | |
4564 | + * (C) 2003 by Harald Welte <laforge@netfilter.org> | |
4565 | + * | |
4566 | + * $Id$ | |
4567 | + * | |
4568 | + * Development of this code was funded by Astaro AG, http://www.astaro.com/ | |
4569 | + * | |
4570 | + * based on ipt_limit.c by: | |
4571 |