diff options
author | Patrick McHardy <kaber@trash.net> | 2007-03-14 19:37:25 -0400 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2007-04-26 01:25:34 -0400 |
commit | 587aa64163bb14f70098f450abab9410787fce9d (patch) | |
tree | 399c00a969d9a8c7af13675583c5417282d18974 | |
parent | ce18afe57bf53477f133208856dd2b7e6b5db5e3 (diff) |
[NETFILTER]: Remove IPv4 only connection tracking/NAT
Remove the obsolete IPv4 only connection tracking/NAT as scheduled in
feature-removal-schedule.
Signed-off-by: Patrick McHardy <kaber@trash.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
80 files changed, 122 insertions, 19135 deletions
diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index 19b4c96b2a49..9817b60e70a3 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt | |||
@@ -211,15 +211,6 @@ Who: Adrian Bunk <bunk@stusta.de> | |||
211 | 211 | ||
212 | --------------------------- | 212 | --------------------------- |
213 | 213 | ||
214 | What: IPv4 only connection tracking/NAT/helpers | ||
215 | When: 2.6.22 | ||
216 | Why: The new layer 3 independant connection tracking replaces the old | ||
217 | IPv4 only version. After some stabilization of the new code the | ||
218 | old one will be removed. | ||
219 | Who: Patrick McHardy <kaber@trash.net> | ||
220 | |||
221 | --------------------------- | ||
222 | |||
223 | What: ACPI hooks (X86_SPEEDSTEP_CENTRINO_ACPI) in speedstep-centrino driver | 214 | What: ACPI hooks (X86_SPEEDSTEP_CENTRINO_ACPI) in speedstep-centrino driver |
224 | When: December 2006 | 215 | When: December 2006 |
225 | Why: Speedstep-centrino driver with ACPI hooks and acpi-cpufreq driver are | 216 | Why: Speedstep-centrino driver with ACPI hooks and acpi-cpufreq driver are |
diff --git a/include/linux/netfilter_ipv4/Kbuild b/include/linux/netfilter_ipv4/Kbuild index 180337801a86..7185792b900f 100644 --- a/include/linux/netfilter_ipv4/Kbuild +++ b/include/linux/netfilter_ipv4/Kbuild | |||
@@ -1,9 +1,3 @@ | |||
1 | header-y += ip_conntrack_helper.h | ||
2 | header-y += ip_conntrack_protocol.h | ||
3 | header-y += ip_conntrack_sctp.h | ||
4 | header-y += ip_conntrack_tcp.h | ||
5 | header-y += ip_conntrack_tftp.h | ||
6 | header-y += ip_nat_pptp.h | ||
7 | header-y += ipt_addrtype.h | 1 | header-y += ipt_addrtype.h |
8 | header-y += ipt_ah.h | 2 | header-y += ipt_ah.h |
9 | header-y += ipt_CLASSIFY.h | 3 | header-y += ipt_CLASSIFY.h |
@@ -49,13 +43,5 @@ header-y += ipt_ttl.h | |||
49 | header-y += ipt_TTL.h | 43 | header-y += ipt_TTL.h |
50 | header-y += ipt_ULOG.h | 44 | header-y += ipt_ULOG.h |
51 | 45 | ||
52 | unifdef-y += ip_conntrack.h | ||
53 | unifdef-y += ip_conntrack_h323.h | ||
54 | unifdef-y += ip_conntrack_irc.h | ||
55 | unifdef-y += ip_conntrack_pptp.h | ||
56 | unifdef-y += ip_conntrack_proto_gre.h | ||
57 | unifdef-y += ip_conntrack_tuple.h | ||
58 | unifdef-y += ip_nat.h | ||
59 | unifdef-y += ip_nat_rule.h | ||
60 | unifdef-y += ip_queue.h | 46 | unifdef-y += ip_queue.h |
61 | unifdef-y += ip_tables.h | 47 | unifdef-y += ip_tables.h |
diff --git a/include/linux/netfilter_ipv4/ip_conntrack.h b/include/linux/netfilter_ipv4/ip_conntrack.h deleted file mode 100644 index da9274e6bf12..000000000000 --- a/include/linux/netfilter_ipv4/ip_conntrack.h +++ /dev/null | |||
@@ -1,402 +0,0 @@ | |||
1 | #ifndef _IP_CONNTRACK_H | ||
2 | #define _IP_CONNTRACK_H | ||
3 | |||
4 | #include <linux/netfilter/nf_conntrack_common.h> | ||
5 | |||
6 | #ifdef __KERNEL__ | ||
7 | #include <linux/netfilter_ipv4/ip_conntrack_tuple.h> | ||
8 | #include <linux/bitops.h> | ||
9 | #include <linux/compiler.h> | ||
10 | #include <asm/atomic.h> | ||
11 | |||
12 | #include <linux/timer.h> | ||
13 | #include <linux/netfilter_ipv4/ip_conntrack_tcp.h> | ||
14 | #include <linux/netfilter_ipv4/ip_conntrack_icmp.h> | ||
15 | #include <linux/netfilter_ipv4/ip_conntrack_proto_gre.h> | ||
16 | #include <linux/netfilter_ipv4/ip_conntrack_sctp.h> | ||
17 | |||
18 | /* per conntrack: protocol private data */ | ||
19 | union ip_conntrack_proto { | ||
20 | /* insert conntrack proto private data here */ | ||
21 | struct ip_ct_gre gre; | ||
22 | struct ip_ct_sctp sctp; | ||
23 | struct ip_ct_tcp tcp; | ||
24 | struct ip_ct_icmp icmp; | ||
25 | }; | ||
26 | |||
27 | union ip_conntrack_expect_proto { | ||
28 | /* insert expect proto private data here */ | ||
29 | }; | ||
30 | |||
31 | /* Add protocol helper include file here */ | ||
32 | #include <linux/netfilter_ipv4/ip_conntrack_h323.h> | ||
33 | #include <linux/netfilter_ipv4/ip_conntrack_pptp.h> | ||
34 | #include <linux/netfilter_ipv4/ip_conntrack_amanda.h> | ||
35 | #include <linux/netfilter_ipv4/ip_conntrack_ftp.h> | ||
36 | #include <linux/netfilter_ipv4/ip_conntrack_irc.h> | ||
37 | |||
38 | /* per conntrack: application helper private data */ | ||
39 | union ip_conntrack_help { | ||
40 | /* insert conntrack helper private data (master) here */ | ||
41 | struct ip_ct_h323_master ct_h323_info; | ||
42 | struct ip_ct_pptp_master ct_pptp_info; | ||
43 | struct ip_ct_ftp_master ct_ftp_info; | ||
44 | struct ip_ct_irc_master ct_irc_info; | ||
45 | }; | ||
46 | |||
47 | #ifdef CONFIG_IP_NF_NAT_NEEDED | ||
48 | #include <linux/netfilter_ipv4/ip_nat.h> | ||
49 | #include <linux/netfilter_ipv4/ip_nat_pptp.h> | ||
50 | |||
51 | /* per conntrack: nat application helper private data */ | ||
52 | union ip_conntrack_nat_help { | ||
53 | /* insert nat helper private data here */ | ||
54 | struct ip_nat_pptp nat_pptp_info; | ||
55 | }; | ||
56 | #endif | ||
57 | |||
58 | #include <linux/types.h> | ||
59 | #include <linux/skbuff.h> | ||
60 | |||
61 | #ifdef CONFIG_NETFILTER_DEBUG | ||
62 | #define IP_NF_ASSERT(x) \ | ||
63 | do { \ | ||
64 | if (!(x)) \ | ||
65 | /* Wooah! I'm tripping my conntrack in a frenzy of \ | ||
66 | netplay... */ \ | ||
67 | printk("NF_IP_ASSERT: %s:%i(%s)\n", \ | ||
68 | __FILE__, __LINE__, __FUNCTION__); \ | ||
69 | } while(0) | ||
70 | #else | ||
71 | #define IP_NF_ASSERT(x) | ||
72 | #endif | ||
73 | |||
74 | struct ip_conntrack_helper; | ||
75 | |||
76 | struct ip_conntrack | ||
77 | { | ||
78 | /* Usage count in here is 1 for hash table/destruct timer, 1 per skb, | ||
79 | plus 1 for any connection(s) we are `master' for */ | ||
80 | struct nf_conntrack ct_general; | ||
81 | |||
82 | /* Have we seen traffic both ways yet? (bitset) */ | ||
83 | unsigned long status; | ||
84 | |||
85 | /* Timer function; drops refcnt when it goes off. */ | ||
86 | struct timer_list timeout; | ||
87 | |||
88 | #ifdef CONFIG_IP_NF_CT_ACCT | ||
89 | /* Accounting Information (same cache line as other written members) */ | ||
90 | struct ip_conntrack_counter counters[IP_CT_DIR_MAX]; | ||
91 | #endif | ||
92 | /* If we were expected by an expectation, this will be it */ | ||
93 | struct ip_conntrack *master; | ||
94 | |||
95 | /* Current number of expected connections */ | ||
96 | unsigned int expecting; | ||
97 | |||
98 | /* Unique ID that identifies this conntrack*/ | ||
99 | unsigned int id; | ||
100 | |||
101 | /* Helper, if any. */ | ||
102 | struct ip_conntrack_helper *helper; | ||
103 | |||
104 | /* Storage reserved for other modules: */ | ||
105 | union ip_conntrack_proto proto; | ||
106 | |||
107 | union ip_conntrack_help help; | ||
108 | |||
109 | #ifdef CONFIG_IP_NF_NAT_NEEDED | ||
110 | struct { | ||
111 | struct ip_nat_info info; | ||
112 | union ip_conntrack_nat_help help; | ||
113 | #if defined(CONFIG_IP_NF_TARGET_MASQUERADE) || \ | ||
114 | defined(CONFIG_IP_NF_TARGET_MASQUERADE_MODULE) | ||
115 | int masq_index; | ||
116 | #endif | ||
117 | } nat; | ||
118 | #endif /* CONFIG_IP_NF_NAT_NEEDED */ | ||
119 | |||
120 | #if defined(CONFIG_IP_NF_CONNTRACK_MARK) | ||
121 | u_int32_t mark; | ||
122 | #endif | ||
123 | |||
124 | #ifdef CONFIG_IP_NF_CONNTRACK_SECMARK | ||
125 | u_int32_t secmark; | ||
126 | #endif | ||
127 | |||
128 | /* Traversed often, so hopefully in different cacheline to top */ | ||
129 | /* These are my tuples; original and reply */ | ||
130 | struct ip_conntrack_tuple_hash tuplehash[IP_CT_DIR_MAX]; | ||
131 | }; | ||
132 | |||
133 | struct ip_conntrack_expect | ||
134 | { | ||
135 | /* Internal linked list (global expectation list) */ | ||
136 | struct list_head list; | ||
137 | |||
138 | /* We expect this tuple, with the following mask */ | ||
139 | struct ip_conntrack_tuple tuple, mask; | ||
140 | |||
141 | /* Function to call after setup and insertion */ | ||
142 | void (*expectfn)(struct ip_conntrack *new, | ||
143 | struct ip_conntrack_expect *this); | ||
144 | |||
145 | /* The conntrack of the master connection */ | ||
146 | struct ip_conntrack *master; | ||
147 | |||
148 | /* Timer function; deletes the expectation. */ | ||
149 | struct timer_list timeout; | ||
150 | |||
151 | /* Usage count. */ | ||
152 | atomic_t use; | ||
153 | |||
154 | /* Unique ID */ | ||
155 | unsigned int id; | ||
156 | |||
157 | /* Flags */ | ||
158 | unsigned int flags; | ||
159 | |||
160 | #ifdef CONFIG_IP_NF_NAT_NEEDED | ||
161 | __be32 saved_ip; | ||
162 | /* This is the original per-proto part, used to map the | ||
163 | * expected connection the way the recipient expects. */ | ||
164 | union ip_conntrack_manip_proto saved_proto; | ||
165 | /* Direction relative to the master connection. */ | ||
166 | enum ip_conntrack_dir dir; | ||
167 | #endif | ||
168 | }; | ||
169 | |||
170 | #define IP_CT_EXPECT_PERMANENT 0x1 | ||
171 | |||
172 | static inline struct ip_conntrack * | ||
173 | tuplehash_to_ctrack(const struct ip_conntrack_tuple_hash *hash) | ||
174 | { | ||
175 | return container_of(hash, struct ip_conntrack, | ||
176 | tuplehash[hash->tuple.dst.dir]); | ||
177 | } | ||
178 | |||
179 | /* get master conntrack via master expectation */ | ||
180 | #define master_ct(conntr) (conntr->master) | ||
181 | |||
182 | /* Alter reply tuple (maybe alter helper). */ | ||
183 | extern void | ||
184 | ip_conntrack_alter_reply(struct ip_conntrack *conntrack, | ||
185 | const struct ip_conntrack_tuple *newreply); | ||
186 | |||
187 | /* Is this tuple taken? (ignoring any belonging to the given | ||
188 | conntrack). */ | ||
189 | extern int | ||
190 | ip_conntrack_tuple_taken(const struct ip_conntrack_tuple *tuple, | ||
191 | const struct ip_conntrack *ignored_conntrack); | ||
192 | |||
193 | /* Return conntrack_info and tuple hash for given skb. */ | ||
194 | static inline struct ip_conntrack * | ||
195 | ip_conntrack_get(const struct sk_buff *skb, enum ip_conntrack_info *ctinfo) | ||
196 | { | ||
197 | *ctinfo = skb->nfctinfo; | ||
198 | return (struct ip_conntrack *)skb->nfct; | ||
199 | } | ||
200 | |||
201 | /* decrement reference count on a conntrack */ | ||
202 | static inline void | ||
203 | ip_conntrack_put(struct ip_conntrack *ct) | ||
204 | { | ||
205 | IP_NF_ASSERT(ct); | ||
206 | nf_conntrack_put(&ct->ct_general); | ||
207 | } | ||
208 | |||
209 | extern int invert_tuplepr(struct ip_conntrack_tuple *inverse, | ||
210 | const struct ip_conntrack_tuple *orig); | ||
211 | |||
212 | extern void __ip_ct_refresh_acct(struct ip_conntrack *ct, | ||
213 | enum ip_conntrack_info ctinfo, | ||
214 | const struct sk_buff *skb, | ||
215 | unsigned long extra_jiffies, | ||
216 | int do_acct); | ||
217 | |||
218 | /* Refresh conntrack for this many jiffies and do accounting */ | ||
219 | static inline void ip_ct_refresh_acct(struct ip_conntrack *ct, | ||
220 | enum ip_conntrack_info ctinfo, | ||
221 | const struct sk_buff *skb, | ||
222 | unsigned long extra_jiffies) | ||
223 | { | ||
224 | __ip_ct_refresh_acct(ct, ctinfo, skb, extra_jiffies, 1); | ||
225 | } | ||
226 | |||
227 | /* Refresh conntrack for this many jiffies */ | ||
228 | static inline void ip_ct_refresh(struct ip_conntrack *ct, | ||
229 | const struct sk_buff *skb, | ||
230 | unsigned long extra_jiffies) | ||
231 | { | ||
232 | __ip_ct_refresh_acct(ct, 0, skb, extra_jiffies, 0); | ||
233 | } | ||
234 | |||
235 | /* These are for NAT. Icky. */ | ||
236 | /* Update TCP window tracking data when NAT mangles the packet */ | ||
237 | extern void ip_conntrack_tcp_update(struct sk_buff *skb, | ||
238 | struct ip_conntrack *conntrack, | ||
239 | enum ip_conntrack_dir dir); | ||
240 | |||
241 | /* Call me when a conntrack is destroyed. */ | ||
242 | extern void (*ip_conntrack_destroyed)(struct ip_conntrack *conntrack); | ||
243 | |||
244 | /* Fake conntrack entry for untracked connections */ | ||
245 | extern struct ip_conntrack ip_conntrack_untracked; | ||
246 | |||
247 | /* Returns new sk_buff, or NULL */ | ||
248 | struct sk_buff * | ||
249 | ip_ct_gather_frags(struct sk_buff *skb, u_int32_t user); | ||
250 | |||
251 | /* Iterate over all conntracks: if iter returns true, it's deleted. */ | ||
252 | extern void | ||
253 | ip_ct_iterate_cleanup(int (*iter)(struct ip_conntrack *i, void *data), | ||
254 | void *data); | ||
255 | |||
256 | extern struct ip_conntrack_helper * | ||
257 | __ip_conntrack_helper_find_byname(const char *); | ||
258 | extern struct ip_conntrack_helper * | ||
259 | ip_conntrack_helper_find_get(const struct ip_conntrack_tuple *tuple); | ||
260 | extern void ip_conntrack_helper_put(struct ip_conntrack_helper *helper); | ||
261 | |||
262 | extern struct ip_conntrack_protocol * | ||
263 | __ip_conntrack_proto_find(u_int8_t protocol); | ||
264 | extern struct ip_conntrack_protocol * | ||
265 | ip_conntrack_proto_find_get(u_int8_t protocol); | ||
266 | extern void ip_conntrack_proto_put(struct ip_conntrack_protocol *proto); | ||
267 | |||
268 | extern void ip_ct_remove_expectations(struct ip_conntrack *ct); | ||
269 | |||
270 | extern struct ip_conntrack *ip_conntrack_alloc(struct ip_conntrack_tuple *, | ||
271 | struct ip_conntrack_tuple *); | ||
272 | |||
273 | extern void ip_conntrack_free(struct ip_conntrack *ct); | ||
274 | |||
275 | extern void ip_conntrack_hash_insert(struct ip_conntrack *ct); | ||
276 | |||
277 | extern struct ip_conntrack_expect * | ||
278 | __ip_conntrack_expect_find(const struct ip_conntrack_tuple *tuple); | ||
279 | |||
280 | extern struct ip_conntrack_expect * | ||
281 | ip_conntrack_expect_find_get(const struct ip_conntrack_tuple *tuple); | ||
282 | |||
283 | extern struct ip_conntrack_tuple_hash * | ||
284 | __ip_conntrack_find(const struct ip_conntrack_tuple *tuple, | ||
285 | const struct ip_conntrack *ignored_conntrack); | ||
286 | |||
287 | extern void ip_conntrack_flush(void); | ||
288 | |||
289 | /* It's confirmed if it is, or has been in the hash table. */ | ||
290 | static inline int is_confirmed(struct ip_conntrack *ct) | ||
291 | { | ||
292 | return test_bit(IPS_CONFIRMED_BIT, &ct->status); | ||
293 | } | ||
294 | |||
295 | static inline int is_dying(struct ip_conntrack *ct) | ||
296 | { | ||
297 | return test_bit(IPS_DYING_BIT, &ct->status); | ||
298 | } | ||
299 | |||
300 | extern unsigned int ip_conntrack_htable_size; | ||
301 | extern int ip_conntrack_checksum; | ||
302 | |||
303 | #define CONNTRACK_STAT_INC(count) (__get_cpu_var(ip_conntrack_stat).count++) | ||
304 | #define CONNTRACK_STAT_INC_ATOMIC(count) \ | ||
305 | do { \ | ||
306 | local_bh_disable(); \ | ||
307 | __get_cpu_var(ip_conntrack_stat).count++; \ | ||
308 | local_bh_enable(); \ | ||
309 | } while (0) | ||
310 | |||
311 | #ifdef CONFIG_IP_NF_CONNTRACK_EVENTS | ||
312 | #include <linux/notifier.h> | ||
313 | #include <linux/interrupt.h> | ||
314 | |||
315 | struct ip_conntrack_ecache { | ||
316 | struct ip_conntrack *ct; | ||
317 | unsigned int events; | ||
318 | }; | ||
319 | DECLARE_PER_CPU(struct ip_conntrack_ecache, ip_conntrack_ecache); | ||
320 | |||
321 | #define CONNTRACK_ECACHE(x) (__get_cpu_var(ip_conntrack_ecache).x) | ||
322 | |||
323 | extern struct atomic_notifier_head ip_conntrack_chain; | ||
324 | extern struct atomic_notifier_head ip_conntrack_expect_chain; | ||
325 | |||
326 | static inline int ip_conntrack_register_notifier(struct notifier_block *nb) | ||
327 | { | ||
328 | return atomic_notifier_chain_register(&ip_conntrack_chain, nb); | ||
329 | } | ||
330 | |||
331 | static inline int ip_conntrack_unregister_notifier(struct notifier_block *nb) | ||
332 | { | ||
333 | return atomic_notifier_chain_unregister(&ip_conntrack_chain, nb); | ||
334 | } | ||
335 | |||
336 | static inline int | ||
337 | ip_conntrack_expect_register_notifier(struct notifier_block *nb) | ||
338 | { | ||
339 | return atomic_notifier_chain_register(&ip_conntrack_expect_chain, nb); | ||
340 | } | ||
341 | |||
342 | static inline int | ||
343 | ip_conntrack_expect_unregister_notifier(struct notifier_block *nb) | ||
344 | { | ||
345 | return atomic_notifier_chain_unregister(&ip_conntrack_expect_chain, | ||
346 | nb); | ||
347 | } | ||
348 | |||
349 | extern void ip_ct_deliver_cached_events(const struct ip_conntrack *ct); | ||
350 | extern void __ip_ct_event_cache_init(struct ip_conntrack *ct); | ||
351 | |||
352 | static inline void | ||
353 | ip_conntrack_event_cache(enum ip_conntrack_events event, | ||
354 | const struct sk_buff *skb) | ||
355 | { | ||
356 | struct ip_conntrack *ct = (struct ip_conntrack *)skb->nfct; | ||
357 | struct ip_conntrack_ecache *ecache; | ||
358 | |||
359 | local_bh_disable(); | ||
360 | ecache = &__get_cpu_var(ip_conntrack_ecache); | ||
361 | if (ct != ecache->ct) | ||
362 | __ip_ct_event_cache_init(ct); | ||
363 | ecache->events |= event; | ||
364 | local_bh_enable(); | ||
365 | } | ||
366 | |||
367 | static inline void ip_conntrack_event(enum ip_conntrack_events event, | ||
368 | struct ip_conntrack *ct) | ||
369 | { | ||
370 | if (is_confirmed(ct) && !is_dying(ct)) | ||
371 | atomic_notifier_call_chain(&ip_conntrack_chain, event, ct); | ||
372 | } | ||
373 | |||
374 | static inline void | ||
375 | ip_conntrack_expect_event(enum ip_conntrack_expect_events event, | ||
376 | struct ip_conntrack_expect *exp) | ||
377 | { | ||
378 | atomic_notifier_call_chain(&ip_conntrack_expect_chain, event, exp); | ||
379 | } | ||
380 | #else /* CONFIG_IP_NF_CONNTRACK_EVENTS */ | ||
381 | static inline void ip_conntrack_event_cache(enum ip_conntrack_events event, | ||
382 | const struct sk_buff *skb) {} | ||
383 | static inline void ip_conntrack_event(enum ip_conntrack_events event, | ||
384 | struct ip_conntrack *ct) {} | ||
385 | static inline void ip_ct_deliver_cached_events(const struct ip_conntrack *ct) {} | ||
386 | static inline void | ||
387 | ip_conntrack_expect_event(enum ip_conntrack_expect_events event, | ||
388 | struct ip_conntrack_expect *exp) {} | ||
389 | #endif /* CONFIG_IP_NF_CONNTRACK_EVENTS */ | ||
390 | |||
391 | #ifdef CONFIG_IP_NF_NAT_NEEDED | ||
392 | static inline int ip_nat_initialized(struct ip_conntrack *conntrack, | ||
393 | enum ip_nat_manip_type manip) | ||
394 | { | ||
395 | if (manip == IP_NAT_MANIP_SRC) | ||
396 | return test_bit(IPS_SRC_NAT_DONE_BIT, &conntrack->status); | ||
397 | return test_bit(IPS_DST_NAT_DONE_BIT, &conntrack->status); | ||
398 | } | ||
399 | #endif /* CONFIG_IP_NF_NAT_NEEDED */ | ||
400 | |||
401 | #endif /* __KERNEL__ */ | ||
402 | #endif /* _IP_CONNTRACK_H */ | ||
diff --git a/include/linux/netfilter_ipv4/ip_conntrack_amanda.h b/include/linux/netfilter_ipv4/ip_conntrack_amanda.h deleted file mode 100644 index de3e41f51aec..000000000000 --- a/include/linux/netfilter_ipv4/ip_conntrack_amanda.h +++ /dev/null | |||
@@ -1,11 +0,0 @@ | |||
1 | #ifndef _IP_CONNTRACK_AMANDA_H | ||
2 | #define _IP_CONNTRACK_AMANDA_H | ||
3 | /* AMANDA tracking. */ | ||
4 | |||
5 | struct ip_conntrack_expect; | ||
6 | extern unsigned int (*ip_nat_amanda_hook)(struct sk_buff **pskb, | ||
7 | enum ip_conntrack_info ctinfo, | ||
8 | unsigned int matchoff, | ||
9 | unsigned int matchlen, | ||
10 | struct ip_conntrack_expect *exp); | ||
11 | #endif /* _IP_CONNTRACK_AMANDA_H */ | ||
diff --git a/include/linux/netfilter_ipv4/ip_conntrack_core.h b/include/linux/netfilter_ipv4/ip_conntrack_core.h deleted file mode 100644 index e3a6df07aa4b..000000000000 --- a/include/linux/netfilter_ipv4/ip_conntrack_core.h +++ /dev/null | |||
@@ -1,61 +0,0 @@ | |||
1 | #ifndef _IP_CONNTRACK_CORE_H | ||
2 | #define _IP_CONNTRACK_CORE_H | ||
3 | #include <linux/netfilter.h> | ||
4 | |||
5 | #define MAX_IP_CT_PROTO 256 | ||
6 | extern struct ip_conntrack_protocol *ip_ct_protos[MAX_IP_CT_PROTO]; | ||
7 | |||
8 | /* This header is used to share core functionality between the | ||
9 | standalone connection tracking module, and the compatibility layer's use | ||
10 | of connection tracking. */ | ||
11 | extern unsigned int ip_conntrack_in(unsigned int hooknum, | ||
12 | struct sk_buff **pskb, | ||
13 | const struct net_device *in, | ||
14 | const struct net_device *out, | ||
15 | int (*okfn)(struct sk_buff *)); | ||
16 | |||
17 | extern int ip_conntrack_init(void); | ||
18 | extern void ip_conntrack_cleanup(void); | ||
19 | |||
20 | struct ip_conntrack_protocol; | ||
21 | |||
22 | extern int | ||
23 | ip_ct_get_tuple(const struct iphdr *iph, | ||
24 | const struct sk_buff *skb, | ||
25 | unsigned int dataoff, | ||
26 | struct ip_conntrack_tuple *tuple, | ||
27 | const struct ip_conntrack_protocol *protocol); | ||
28 | |||
29 | extern int | ||
30 | ip_ct_invert_tuple(struct ip_conntrack_tuple *inverse, | ||
31 | const struct ip_conntrack_tuple *orig, | ||
32 | const struct ip_conntrack_protocol *protocol); | ||
33 | |||
34 | /* Find a connection corresponding to a tuple. */ | ||
35 | struct ip_conntrack_tuple_hash * | ||
36 | ip_conntrack_find_get(const struct ip_conntrack_tuple *tuple, | ||
37 | const struct ip_conntrack *ignored_conntrack); | ||
38 | |||
39 | extern int __ip_conntrack_confirm(struct sk_buff **pskb); | ||
40 | |||
41 | /* Confirm a connection: returns NF_DROP if packet must be dropped. */ | ||
42 | static inline int ip_conntrack_confirm(struct sk_buff **pskb) | ||
43 | { | ||
44 | struct ip_conntrack *ct = (struct ip_conntrack *)(*pskb)->nfct; | ||
45 | int ret = NF_ACCEPT; | ||
46 | |||
47 | if (ct) { | ||
48 | if (!is_confirmed(ct) && !is_dying(ct)) | ||
49 | ret = __ip_conntrack_confirm(pskb); | ||
50 | ip_ct_deliver_cached_events(ct); | ||
51 | } | ||
52 | return ret; | ||
53 | } | ||
54 | |||
55 | extern void ip_ct_unlink_expect(struct ip_conntrack_expect *exp); | ||
56 | |||
57 | extern struct list_head *ip_conntrack_hash; | ||
58 | extern struct list_head ip_conntrack_expect_list; | ||
59 | extern rwlock_t ip_conntrack_lock; | ||
60 | #endif /* _IP_CONNTRACK_CORE_H */ | ||
61 | |||
diff --git a/include/linux/netfilter_ipv4/ip_conntrack_ftp.h b/include/linux/netfilter_ipv4/ip_conntrack_ftp.h deleted file mode 100644 index 2129fc3972ac..000000000000 --- a/include/linux/netfilter_ipv4/ip_conntrack_ftp.h +++ /dev/null | |||
@@ -1,44 +0,0 @@ | |||
1 | #ifndef _IP_CONNTRACK_FTP_H | ||
2 | #define _IP_CONNTRACK_FTP_H | ||
3 | /* FTP tracking. */ | ||
4 | |||
5 | /* This enum is exposed to userspace */ | ||
6 | enum ip_ct_ftp_type | ||
7 | { | ||
8 | /* PORT command from client */ | ||
9 | IP_CT_FTP_PORT, | ||
10 | /* PASV response from server */ | ||
11 | IP_CT_FTP_PASV, | ||
12 | /* EPRT command from client */ | ||
13 | IP_CT_FTP_EPRT, | ||
14 | /* EPSV response from server */ | ||
15 | IP_CT_FTP_EPSV, | ||
16 | }; | ||
17 | |||
18 | #ifdef __KERNEL__ | ||
19 | |||
20 | #define FTP_PORT 21 | ||
21 | |||
22 | #define NUM_SEQ_TO_REMEMBER 2 | ||
23 | /* This structure exists only once per master */ | ||
24 | struct ip_ct_ftp_master { | ||
25 | /* Valid seq positions for cmd matching after newline */ | ||
26 | u_int32_t seq_aft_nl[IP_CT_DIR_MAX][NUM_SEQ_TO_REMEMBER]; | ||
27 | /* 0 means seq_match_aft_nl not set */ | ||
28 | int seq_aft_nl_num[IP_CT_DIR_MAX]; | ||
29 | }; | ||
30 | |||
31 | struct ip_conntrack_expect; | ||
32 | |||
33 | /* For NAT to hook in when we find a packet which describes what other | ||
34 | * connection we should expect. */ | ||
35 | extern unsigned int (*ip_nat_ftp_hook)(struct sk_buff **pskb, | ||
36 | enum ip_conntrack_info ctinfo, | ||
37 | enum ip_ct_ftp_type type, | ||
38 | unsigned int matchoff, | ||
39 | unsigned int matchlen, | ||
40 | struct ip_conntrack_expect *exp, | ||
41 | u32 *seq); | ||
42 | #endif /* __KERNEL__ */ | ||
43 | |||
44 | #endif /* _IP_CONNTRACK_FTP_H */ | ||
diff --git a/include/linux/netfilter_ipv4/ip_conntrack_h323.h b/include/linux/netfilter_ipv4/ip_conntrack_h323.h deleted file mode 100644 index 18f769818f4e..000000000000 --- a/include/linux/netfilter_ipv4/ip_conntrack_h323.h +++ /dev/null | |||
@@ -1,89 +0,0 @@ | |||
1 | #ifndef _IP_CONNTRACK_H323_H | ||
2 | #define _IP_CONNTRACK_H323_H | ||
3 | |||
4 | #ifdef __KERNEL__ | ||
5 | |||
6 | #include <linux/netfilter/nf_conntrack_h323_asn1.h> | ||
7 | |||
8 | #define RAS_PORT 1719 | ||
9 | #define Q931_PORT 1720 | ||
10 | #define H323_RTP_CHANNEL_MAX 4 /* Audio, video, FAX and other */ | ||
11 | |||
12 | /* This structure exists only once per master */ | ||
13 | struct ip_ct_h323_master { | ||
14 | |||
15 | /* Original and NATed Q.931 or H.245 signal ports */ | ||
16 | u_int16_t sig_port[IP_CT_DIR_MAX]; | ||
17 | |||
18 | /* Original and NATed RTP ports */ | ||
19 | u_int16_t rtp_port[H323_RTP_CHANNEL_MAX][IP_CT_DIR_MAX]; | ||
20 | |||
21 | union { | ||
22 | /* RAS connection timeout */ | ||
23 | u_int32_t timeout; | ||
24 | |||
25 | /* Next TPKT length (for separate TPKT header and data) */ | ||
26 | u_int16_t tpkt_len[IP_CT_DIR_MAX]; | ||
27 | }; | ||
28 | }; | ||
29 | |||
30 | struct ip_conntrack_expect; | ||
31 | |||
32 | extern int get_h225_addr(unsigned char *data, TransportAddress * addr, | ||
33 | __be32 * ip, u_int16_t * port); | ||
34 | extern void ip_conntrack_h245_expect(struct ip_conntrack *new, | ||
35 | struct ip_conntrack_expect *this); | ||
36 | extern void ip_conntrack_q931_expect(struct ip_conntrack *new, | ||
37 | struct ip_conntrack_expect *this); | ||
38 | extern int (*set_h245_addr_hook) (struct sk_buff ** pskb, | ||
39 | unsigned char **data, int dataoff, | ||
40 | H245_TransportAddress * addr, | ||
41 | __be32 ip, u_int16_t port); | ||
42 | extern int (*set_h225_addr_hook) (struct sk_buff ** pskb, | ||
43 | unsigned char **data, int dataoff, | ||
44 | TransportAddress * addr, | ||
45 | __be32 ip, u_int16_t port); | ||
46 | extern int (*set_sig_addr_hook) (struct sk_buff ** pskb, | ||
47 | struct ip_conntrack * ct, | ||
48 | enum ip_conntrack_info ctinfo, | ||
49 | unsigned char **data, | ||
50 | TransportAddress * addr, int count); | ||
51 | extern int (*set_ras_addr_hook) (struct sk_buff ** pskb, | ||
52 | struct ip_conntrack * ct, | ||
53 | enum ip_conntrack_info ctinfo, | ||
54 | unsigned char **data, | ||
55 | TransportAddress * addr, int count); | ||
56 | extern int (*nat_rtp_rtcp_hook) (struct sk_buff ** pskb, | ||
57 | struct ip_conntrack * ct, | ||
58 | enum ip_conntrack_info ctinfo, | ||
59 | unsigned char **data, int dataoff, | ||
60 | H245_TransportAddress * addr, | ||
61 | u_int16_t port, u_int16_t rtp_port, | ||
62 | struct ip_conntrack_expect * rtp_exp, | ||
63 | struct ip_conntrack_expect * rtcp_exp); | ||
64 | extern int (*nat_t120_hook) (struct sk_buff ** pskb, struct ip_conntrack * ct, | ||
65 | enum ip_conntrack_info ctinfo, | ||
66 | unsigned char **data, int dataoff, | ||
67 | H245_TransportAddress * addr, u_int16_t port, | ||
68 | struct ip_conntrack_expect * exp); | ||
69 | extern int (*nat_h245_hook) (struct sk_buff ** pskb, struct ip_conntrack * ct, | ||
70 | enum ip_conntrack_info ctinfo, | ||
71 | unsigned char **data, int dataoff, | ||
72 | TransportAddress * addr, u_int16_t port, | ||
73 | struct ip_conntrack_expect * exp); | ||
74 | extern int (*nat_callforwarding_hook) (struct sk_buff ** pskb, | ||
75 | struct ip_conntrack * ct, | ||
76 | enum ip_conntrack_info ctinfo, | ||
77 | unsigned char **data, int dataoff, | ||
78 | TransportAddress * addr, | ||
79 | u_int16_t port, | ||
80 | struct ip_conntrack_expect * exp); | ||
81 | extern int (*nat_q931_hook) (struct sk_buff ** pskb, struct ip_conntrack * ct, | ||
82 | enum ip_conntrack_info ctinfo, | ||
83 | unsigned char **data, TransportAddress * addr, | ||
84 | int idx, u_int16_t port, | ||
85 | struct ip_conntrack_expect * exp); | ||
86 | |||
87 | #endif | ||
88 | |||
89 | #endif | ||
diff --git a/include/linux/netfilter_ipv4/ip_conntrack_helper.h b/include/linux/netfilter_ipv4/ip_conntrack_helper.h deleted file mode 100644 index 77fe868d36ff..000000000000 --- a/include/linux/netfilter_ipv4/ip_conntrack_helper.h +++ /dev/null | |||
@@ -1,46 +0,0 @@ | |||
1 | /* IP connection tracking helpers. */ | ||
2 | #ifndef _IP_CONNTRACK_HELPER_H | ||
3 | #define _IP_CONNTRACK_HELPER_H | ||
4 | #include <linux/netfilter_ipv4/ip_conntrack.h> | ||
5 | |||
6 | struct module; | ||
7 | |||
8 | struct ip_conntrack_helper | ||
9 | { | ||
10 | struct list_head list; /* Internal use. */ | ||
11 | |||
12 | const char *name; /* name of the module */ | ||
13 | struct module *me; /* pointer to self */ | ||
14 | unsigned int max_expected; /* Maximum number of concurrent | ||
15 | * expected connections */ | ||
16 | unsigned int timeout; /* timeout for expecteds */ | ||
17 | |||
18 | /* Mask of things we will help (compared against server response) */ | ||
19 | struct ip_conntrack_tuple tuple; | ||
20 | struct ip_conntrack_tuple mask; | ||
21 | |||
22 | /* Function to call when data passes; return verdict, or -1 to | ||
23 | invalidate. */ | ||
24 | int (*help)(struct sk_buff **pskb, | ||
25 | struct ip_conntrack *ct, | ||
26 | enum ip_conntrack_info conntrackinfo); | ||
27 | |||
28 | void (*destroy)(struct ip_conntrack *ct); | ||
29 | |||
30 | int (*to_nfattr)(struct sk_buff *skb, const struct ip_conntrack *ct); | ||
31 | }; | ||
32 | |||
33 | extern int ip_conntrack_helper_register(struct ip_conntrack_helper *); | ||
34 | extern void ip_conntrack_helper_unregister(struct ip_conntrack_helper *); | ||
35 | |||
36 | /* Allocate space for an expectation: this is mandatory before calling | ||
37 | ip_conntrack_expect_related. You will have to call put afterwards. */ | ||
38 | extern struct ip_conntrack_expect * | ||
39 | ip_conntrack_expect_alloc(struct ip_conntrack *master); | ||
40 | extern void ip_conntrack_expect_put(struct ip_conntrack_expect *exp); | ||
41 | |||
42 | /* Add an expected connection: can have more than one per connection */ | ||
43 | extern int ip_conntrack_expect_related(struct ip_conntrack_expect *exp); | ||
44 | extern void ip_conntrack_unexpect_related(struct ip_conntrack_expect *exp); | ||
45 | |||
46 | #endif /*_IP_CONNTRACK_HELPER_H*/ | ||
diff --git a/include/linux/netfilter_ipv4/ip_conntrack_icmp.h b/include/linux/netfilter_ipv4/ip_conntrack_icmp.h deleted file mode 100644 index eed5ee3e4744..000000000000 --- a/include/linux/netfilter_ipv4/ip_conntrack_icmp.h +++ /dev/null | |||
@@ -1,6 +0,0 @@ | |||
1 | #ifndef _IP_CONNTRACK_ICMP_H | ||
2 | #define _IP_CONNTRACK_ICMP_H | ||
3 | |||
4 | #include <net/netfilter/ipv4/nf_conntrack_icmp.h> | ||
5 | |||
6 | #endif /* _IP_CONNTRACK_ICMP_H */ | ||
diff --git a/include/linux/netfilter_ipv4/ip_conntrack_irc.h b/include/linux/netfilter_ipv4/ip_conntrack_irc.h deleted file mode 100644 index 16601e0d5626..000000000000 --- a/include/linux/netfilter_ipv4/ip_conntrack_irc.h +++ /dev/null | |||
@@ -1,32 +0,0 @@ | |||
1 | /* IRC extension for IP connection tracking. | ||
2 | * (C) 2000 by Harald Welte <laforge@gnumonks.org> | ||
3 | * based on RR's ip_conntrack_ftp.h | ||
4 | * | ||
5 | * ip_conntrack_irc.h,v 1.6 2000/11/07 18:26:42 laforge Exp | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License | ||
9 | * as published by the Free Software Foundation; either version | ||
10 | * 2 of the License, or (at your option) any later version. | ||
11 | * | ||
12 | * | ||
13 | */ | ||
14 | #ifndef _IP_CONNTRACK_IRC_H | ||
15 | #define _IP_CONNTRACK_IRC_H | ||
16 | |||
17 | /* This structure exists only once per master */ | ||
18 | struct ip_ct_irc_master { | ||
19 | }; | ||
20 | |||
21 | #ifdef __KERNEL__ | ||
22 | extern unsigned int (*ip_nat_irc_hook)(struct sk_buff **pskb, | ||
23 | enum ip_conntrack_info ctinfo, | ||
24 | unsigned int matchoff, | ||
25 | unsigned int matchlen, | ||
26 | struct ip_conntrack_expect *exp); | ||
27 | |||
28 | #define IRC_PORT 6667 | ||
29 | |||
30 | #endif /* __KERNEL__ */ | ||
31 | |||
32 | #endif /* _IP_CONNTRACK_IRC_H */ | ||
diff --git a/include/linux/netfilter_ipv4/ip_conntrack_pptp.h b/include/linux/netfilter_ipv4/ip_conntrack_pptp.h deleted file mode 100644 index 2644b1faddd6..000000000000 --- a/include/linux/netfilter_ipv4/ip_conntrack_pptp.h +++ /dev/null | |||
@@ -1,326 +0,0 @@ | |||
1 | /* PPTP constants and structs */ | ||
2 | #ifndef _CONNTRACK_PPTP_H | ||
3 | #define _CONNTRACK_PPTP_H | ||
4 | |||
5 | /* state of the control session */ | ||
6 | enum pptp_ctrlsess_state { | ||
7 | PPTP_SESSION_NONE, /* no session present */ | ||
8 | PPTP_SESSION_ERROR, /* some session error */ | ||
9 | PPTP_SESSION_STOPREQ, /* stop_sess request seen */ | ||
10 | PPTP_SESSION_REQUESTED, /* start_sess request seen */ | ||
11 | PPTP_SESSION_CONFIRMED, /* session established */ | ||
12 | }; | ||
13 | |||
14 | /* state of the call inside the control session */ | ||
15 | enum pptp_ctrlcall_state { | ||
16 | PPTP_CALL_NONE, | ||
17 | PPTP_CALL_ERROR, | ||
18 | PPTP_CALL_OUT_REQ, | ||
19 | PPTP_CALL_OUT_CONF, | ||
20 | PPTP_CALL_IN_REQ, | ||
21 | PPTP_CALL_IN_REP, | ||
22 | PPTP_CALL_IN_CONF, | ||
23 | PPTP_CALL_CLEAR_REQ, | ||
24 | }; | ||
25 | |||
26 | |||
27 | /* conntrack private data */ | ||
28 | struct ip_ct_pptp_master { | ||
29 | enum pptp_ctrlsess_state sstate; /* session state */ | ||
30 | |||
31 | /* everything below is going to be per-expectation in newnat, | ||
32 | * since there could be more than one call within one session */ | ||
33 | enum pptp_ctrlcall_state cstate; /* call state */ | ||
34 | __be16 pac_call_id; /* call id of PAC, host byte order */ | ||
35 | __be16 pns_call_id; /* call id of PNS, host byte order */ | ||
36 | |||
37 | /* in pre-2.6.11 this used to be per-expect. Now it is per-conntrack | ||
38 | * and therefore imposes a fixed limit on the number of maps */ | ||
39 | struct ip_ct_gre_keymap *keymap_orig, *keymap_reply; | ||
40 | }; | ||
41 | |||
42 | /* conntrack_expect private member */ | ||
43 | struct ip_ct_pptp_expect { | ||
44 | enum pptp_ctrlcall_state cstate; /* call state */ | ||
45 | __be16 pac_call_id; /* call id of PAC */ | ||
46 | __be16 pns_call_id; /* call id of PNS */ | ||
47 | }; | ||
48 | |||
49 | |||
50 | #ifdef __KERNEL__ | ||
51 | |||
52 | #define IP_CONNTR_PPTP PPTP_CONTROL_PORT | ||
53 | |||
54 | #define PPTP_CONTROL_PORT 1723 | ||
55 | |||
56 | #define PPTP_PACKET_CONTROL 1 | ||
57 | #define PPTP_PACKET_MGMT 2 | ||
58 | |||
59 | #define PPTP_MAGIC_COOKIE 0x1a2b3c4d | ||
60 | |||
61 | struct pptp_pkt_hdr { | ||
62 | __u16 packetLength; | ||
63 | __be16 packetType; | ||
64 | __be32 magicCookie; | ||
65 | }; | ||
66 | |||
67 | /* PptpControlMessageType values */ | ||
68 | #define PPTP_START_SESSION_REQUEST 1 | ||
69 | #define PPTP_START_SESSION_REPLY 2 | ||
70 | #define PPTP_STOP_SESSION_REQUEST 3 | ||
71 | #define PPTP_STOP_SESSION_REPLY 4 | ||
72 | #define PPTP_ECHO_REQUEST 5 | ||
73 | #define PPTP_ECHO_REPLY 6 | ||
74 | #define PPTP_OUT_CALL_REQUEST 7 | ||
75 | #define PPTP_OUT_CALL_REPLY 8 | ||
76 | #define PPTP_IN_CALL_REQUEST 9 | ||
77 | #define PPTP_IN_CALL_REPLY 10 | ||
78 | #define PPTP_IN_CALL_CONNECT 11 | ||
79 | #define PPTP_CALL_CLEAR_REQUEST 12 | ||
80 | #define PPTP_CALL_DISCONNECT_NOTIFY 13 | ||
81 | #define PPTP_WAN_ERROR_NOTIFY 14 | ||
82 | #define PPTP_SET_LINK_INFO 15 | ||
83 | |||
84 | #define PPTP_MSG_MAX 15 | ||
85 | |||
86 | /* PptpGeneralError values */ | ||
87 | #define PPTP_ERROR_CODE_NONE 0 | ||
88 | #define PPTP_NOT_CONNECTED 1 | ||
89 | #define PPTP_BAD_FORMAT 2 | ||
90 | #define PPTP_BAD_VALUE 3 | ||
91 | #define PPTP_NO_RESOURCE 4 | ||
92 | #define PPTP_BAD_CALLID 5 | ||
93 | #define PPTP_REMOVE_DEVICE_ERROR 6 | ||
94 | |||
95 | struct PptpControlHeader { | ||
96 | __be16 messageType; | ||
97 | __u16 reserved; | ||
98 | }; | ||
99 | |||
100 | /* FramingCapability Bitmap Values */ | ||
101 | #define PPTP_FRAME_CAP_ASYNC 0x1 | ||
102 | #define PPTP_FRAME_CAP_SYNC 0x2 | ||
103 | |||
104 | /* BearerCapability Bitmap Values */ | ||
105 | #define PPTP_BEARER_CAP_ANALOG 0x1 | ||
106 | #define PPTP_BEARER_CAP_DIGITAL 0x2 | ||
107 | |||
108 | struct PptpStartSessionRequest { | ||
109 | __be16 protocolVersion; | ||
110 | __u16 reserved1; | ||
111 | __be32 framingCapability; | ||
112 | __be32 bearerCapability; | ||
113 | __be16 maxChannels; | ||
114 | __be16 firmwareRevision; | ||
115 | __u8 hostName[64]; | ||
116 | __u8 vendorString[64]; | ||
117 | }; | ||
118 | |||
119 | /* PptpStartSessionResultCode Values */ | ||
120 | #define PPTP_START_OK 1 | ||
121 | #define PPTP_START_GENERAL_ERROR 2 | ||
122 | #define PPTP_START_ALREADY_CONNECTED 3 | ||
123 | #define PPTP_START_NOT_AUTHORIZED 4 | ||
124 | #define PPTP_START_UNKNOWN_PROTOCOL 5 | ||
125 | |||
126 | struct PptpStartSessionReply { | ||
127 | __be16 protocolVersion; | ||
128 | __u8 resultCode; | ||
129 | __u8 generalErrorCode; | ||
130 | __be32 framingCapability; | ||
131 | __be32 bearerCapability; | ||
132 | __be16 maxChannels; | ||
133 | __be16 firmwareRevision; | ||
134 | __u8 hostName[64]; | ||
135 | __u8 vendorString[64]; | ||
136 | }; | ||
137 | |||
138 | /* PptpStopReasons */ | ||
139 | #define PPTP_STOP_NONE 1 | ||
140 | #define PPTP_STOP_PROTOCOL 2 | ||
141 | #define PPTP_STOP_LOCAL_SHUTDOWN 3 | ||
142 | |||
143 | struct PptpStopSessionRequest { | ||
144 | __u8 reason; | ||
145 | __u8 reserved1; | ||
146 | __u16 reserved2; | ||
147 | }; | ||
148 | |||
149 | /* PptpStopSessionResultCode */ | ||
150 | #define PPTP_STOP_OK 1 | ||
151 | #define PPTP_STOP_GENERAL_ERROR 2 | ||
152 | |||
153 | struct PptpStopSessionReply { | ||
154 | __u8 resultCode; | ||
155 | __u8 generalErrorCode; | ||
156 | __u16 reserved1; | ||
157 | }; | ||
158 | |||
159 | struct PptpEchoRequest { | ||
160 | __be32 identNumber; | ||
161 | }; | ||
162 | |||
163 | /* PptpEchoReplyResultCode */ | ||
164 | #define PPTP_ECHO_OK 1 | ||
165 | #define PPTP_ECHO_GENERAL_ERROR 2 | ||
166 | |||
167 | struct PptpEchoReply { | ||
168 | __be32 identNumber; | ||
169 | __u8 resultCode; | ||
170 | __u8 generalErrorCode; | ||
171 | __u16 reserved; | ||
172 | }; | ||
173 | |||
174 | /* PptpFramingType */ | ||
175 | #define PPTP_ASYNC_FRAMING 1 | ||
176 | #define PPTP_SYNC_FRAMING 2 | ||
177 | #define PPTP_DONT_CARE_FRAMING 3 | ||
178 | |||
179 | /* PptpCallBearerType */ | ||
180 | #define PPTP_ANALOG_TYPE 1 | ||
181 | #define PPTP_DIGITAL_TYPE 2 | ||
182 | #define PPTP_DONT_CARE_BEARER_TYPE 3 | ||
183 | |||
184 | struct PptpOutCallRequest { | ||
185 | __be16 callID; | ||
186 | __be16 callSerialNumber; | ||
187 | __be32 minBPS; | ||
188 | __be32 maxBPS; | ||
189 | __be32 bearerType; | ||
190 | __be32 framingType; | ||
191 | __be16 packetWindow; | ||
192 | __be16 packetProcDelay; | ||
193 | __be16 phoneNumberLength; | ||
194 | __u16 reserved1; | ||
195 | __u8 phoneNumber[64]; | ||
196 | __u8 subAddress[64]; | ||
197 | }; | ||
198 | |||
199 | /* PptpCallResultCode */ | ||
200 | #define PPTP_OUTCALL_CONNECT 1 | ||
201 | #define PPTP_OUTCALL_GENERAL_ERROR 2 | ||
202 | #define PPTP_OUTCALL_NO_CARRIER 3 | ||
203 | #define PPTP_OUTCALL_BUSY 4 | ||
204 | #define PPTP_OUTCALL_NO_DIAL_TONE 5 | ||
205 | #define PPTP_OUTCALL_TIMEOUT 6 | ||
206 | #define PPTP_OUTCALL_DONT_ACCEPT 7 | ||
207 | |||
208 | struct PptpOutCallReply { | ||
209 | __be16 callID; | ||
210 | __be16 peersCallID; | ||
211 | __u8 resultCode; | ||
212 | __u8 generalErrorCode; | ||
213 | __be16 causeCode; | ||
214 | __be32 connectSpeed; | ||
215 | __be16 packetWindow; | ||
216 | __be16 packetProcDelay; | ||
217 | __be32 physChannelID; | ||
218 | }; | ||
219 | |||
220 | struct PptpInCallRequest { | ||
221 | __be16 callID; | ||
222 | __be16 callSerialNumber; | ||
223 | __be32 callBearerType; | ||
224 | __be32 physChannelID; | ||
225 | __be16 dialedNumberLength; | ||
226 | __be16 dialingNumberLength; | ||
227 | __u8 dialedNumber[64]; | ||
228 | __u8 dialingNumber[64]; | ||
229 | __u8 subAddress[64]; | ||
230 | }; | ||
231 | |||
232 | /* PptpInCallResultCode */ | ||
233 | #define PPTP_INCALL_ACCEPT 1 | ||
234 | #define PPTP_INCALL_GENERAL_ERROR 2 | ||
235 | #define PPTP_INCALL_DONT_ACCEPT 3 | ||
236 | |||
237 | struct PptpInCallReply { | ||
238 | __be16 callID; | ||
239 | __be16 peersCallID; | ||
240 | __u8 resultCode; | ||
241 | __u8 generalErrorCode; | ||
242 | __be16 packetWindow; | ||
243 | __be16 packetProcDelay; | ||
244 | __u16 reserved; | ||
245 | }; | ||
246 | |||
247 | struct PptpInCallConnected { | ||
248 | __be16 peersCallID; | ||
249 | __u16 reserved; | ||
250 | __be32 connectSpeed; | ||
251 | __be16 packetWindow; | ||
252 | __be16 packetProcDelay; | ||
253 | __be32 callFramingType; | ||
254 | }; | ||
255 | |||
256 | struct PptpClearCallRequest { | ||
257 | __be16 callID; | ||
258 | __u16 reserved; | ||
259 | }; | ||
260 | |||
261 | struct PptpCallDisconnectNotify { | ||
262 | __be16 callID; | ||
263 | __u8 resultCode; | ||
264 | __u8 generalErrorCode; | ||
265 | __be16 causeCode; | ||
266 | __u16 reserved; | ||
267 | __u8 callStatistics[128]; | ||
268 | }; | ||
269 | |||
270 | struct PptpWanErrorNotify { | ||
271 | __be16 peersCallID; | ||
272 | __u16 reserved; | ||
273 | __be32 crcErrors; | ||
274 | __be32 framingErrors; | ||
275 | __be32 hardwareOverRuns; | ||
276 | __be32 bufferOverRuns; | ||
277 | __be32 timeoutErrors; | ||
278 | __be32 alignmentErrors; | ||
279 | }; | ||
280 | |||
281 | struct PptpSetLinkInfo { | ||
282 | __be16 peersCallID; | ||
283 | __u16 reserved; | ||
284 | __be32 sendAccm; | ||
285 | __be32 recvAccm; | ||
286 | }; | ||
287 | |||
288 | union pptp_ctrl_union { | ||
289 | struct PptpStartSessionRequest sreq; | ||
290 | struct PptpStartSessionReply srep; | ||
291 | struct PptpStopSessionRequest streq; | ||
292 | struct PptpStopSessionReply strep; | ||
293 | struct PptpOutCallRequest ocreq; | ||
294 | struct PptpOutCallReply ocack; | ||
295 | struct PptpInCallRequest icreq; | ||
296 | struct PptpInCallReply icack; | ||
297 | struct PptpInCallConnected iccon; | ||
298 | struct PptpClearCallRequest clrreq; | ||
299 | struct PptpCallDisconnectNotify disc; | ||
300 | struct PptpWanErrorNotify wanerr; | ||
301 | struct PptpSetLinkInfo setlink; | ||
302 | }; | ||
303 | |||
304 | extern int | ||
305 | (*ip_nat_pptp_hook_outbound)(struct sk_buff **pskb, | ||
306 | struct ip_conntrack *ct, | ||
307 | enum ip_conntrack_info ctinfo, | ||
308 | struct PptpControlHeader *ctlh, | ||
309 | union pptp_ctrl_union *pptpReq); | ||
310 | |||
311 | extern int | ||
312 | (*ip_nat_pptp_hook_inbound)(struct sk_buff **pskb, | ||
313 | struct ip_conntrack *ct, | ||
314 | enum ip_conntrack_info ctinfo, | ||
315 | struct PptpControlHeader *ctlh, | ||
316 | union pptp_ctrl_union *pptpReq); | ||
317 | |||
318 | extern void | ||
319 | (*ip_nat_pptp_hook_exp_gre)(struct ip_conntrack_expect *exp_orig, | ||
320 | struct ip_conntrack_expect *exp_reply); | ||
321 | |||
322 | extern void | ||
323 | (*ip_nat_pptp_hook_expectfn)(struct ip_conntrack *ct, | ||
324 | struct ip_conntrack_expect *exp); | ||
325 | #endif /* __KERNEL__ */ | ||
326 | #endif /* _CONNTRACK_PPTP_H */ | ||
diff --git a/include/linux/netfilter_ipv4/ip_conntrack_proto_gre.h b/include/linux/netfilter_ipv4/ip_conntrack_proto_gre.h deleted file mode 100644 index e371e0fc1672..000000000000 --- a/include/linux/netfilter_ipv4/ip_conntrack_proto_gre.h +++ /dev/null | |||
@@ -1,114 +0,0 @@ | |||
1 | #ifndef _CONNTRACK_PROTO_GRE_H | ||
2 | #define _CONNTRACK_PROTO_GRE_H | ||
3 | #include <asm/byteorder.h> | ||
4 | |||
5 | /* GRE PROTOCOL HEADER */ | ||
6 | |||
7 | /* GRE Version field */ | ||
8 | #define GRE_VERSION_1701 0x0 | ||
9 | #define GRE_VERSION_PPTP 0x1 | ||
10 | |||
11 | /* GRE Protocol field */ | ||
12 | #define GRE_PROTOCOL_PPTP 0x880B | ||
13 | |||
14 | /* GRE Flags */ | ||
15 | #define GRE_FLAG_C 0x80 | ||
16 | #define GRE_FLAG_R 0x40 | ||
17 | #define GRE_FLAG_K 0x20 | ||
18 | #define GRE_FLAG_S 0x10 | ||
19 | #define GRE_FLAG_A 0x80 | ||
20 | |||
21 | #define GRE_IS_C(f) ((f)&GRE_FLAG_C) | ||
22 | #define GRE_IS_R(f) ((f)&GRE_FLAG_R) | ||
23 | #define GRE_IS_K(f) ((f)&GRE_FLAG_K) | ||
24 | #define GRE_IS_S(f) ((f)&GRE_FLAG_S) | ||
25 | #define GRE_IS_A(f) ((f)&GRE_FLAG_A) | ||
26 | |||
27 | /* GRE is a mess: Four different standards */ | ||
28 | struct gre_hdr { | ||
29 | #if defined(__LITTLE_ENDIAN_BITFIELD) | ||
30 | __u16 rec:3, | ||
31 | srr:1, | ||
32 | seq:1, | ||
33 | key:1, | ||
34 | routing:1, | ||
35 | csum:1, | ||
36 | version:3, | ||
37 | reserved:4, | ||
38 | ack:1; | ||
39 | #elif defined(__BIG_ENDIAN_BITFIELD) | ||
40 | __u16 csum:1, | ||
41 | routing:1, | ||
42 | key:1, | ||
43 | seq:1, | ||
44 | srr:1, | ||
45 | rec:3, | ||
46 | ack:1, | ||
47 | reserved:4, | ||
48 | version:3; | ||
49 | #else | ||
50 | #error "Adjust your <asm/byteorder.h> defines" | ||
51 | #endif | ||
52 | __be16 protocol; | ||
53 | }; | ||
54 | |||
55 | /* modified GRE header for PPTP */ | ||
56 | struct gre_hdr_pptp { | ||
57 | __u8 flags; /* bitfield */ | ||
58 | __u8 version; /* should be GRE_VERSION_PPTP */ | ||
59 | __be16 protocol; /* should be GRE_PROTOCOL_PPTP */ | ||
60 | __be16 payload_len; /* size of ppp payload, not inc. gre header */ | ||
61 | __be16 call_id; /* peer's call_id for this session */ | ||
62 | __be32 seq; /* sequence number. Present if S==1 */ | ||
63 | __be32 ack; /* seq number of highest packet recieved by */ | ||
64 | /* sender in this session */ | ||
65 | }; | ||
66 | |||
67 | |||
68 | /* this is part of ip_conntrack */ | ||
69 | struct ip_ct_gre { | ||
70 | unsigned int stream_timeout; | ||
71 | unsigned int timeout; | ||
72 | }; | ||
73 | |||
74 | #ifdef __KERNEL__ | ||
75 | struct ip_conntrack_expect; | ||
76 | struct ip_conntrack; | ||
77 | |||
78 | /* structure for original <-> reply keymap */ | ||
79 | struct ip_ct_gre_keymap { | ||
80 | struct list_head list; | ||
81 | |||
82 | struct ip_conntrack_tuple tuple; | ||
83 | }; | ||
84 | |||
85 | /* add new tuple->key_reply pair to keymap */ | ||
86 | int ip_ct_gre_keymap_add(struct ip_conntrack *ct, | ||
87 | struct ip_conntrack_tuple *t, | ||
88 | int reply); | ||
89 | |||
90 | /* delete keymap entries */ | ||
91 | void ip_ct_gre_keymap_destroy(struct ip_conntrack *ct); | ||
92 | |||
93 | |||
94 | /* get pointer to gre key, if present */ | ||
95 | static inline __be32 *gre_key(struct gre_hdr *greh) | ||
96 | { | ||
97 | if (!greh->key) | ||
98 | return NULL; | ||
99 | if (greh->csum || greh->routing) | ||
100 | return (__be32 *) (greh+sizeof(*greh)+4); | ||
101 | return (__be32 *) (greh+sizeof(*greh)); | ||
102 | } | ||
103 | |||
104 | /* get pointer ot gre csum, if present */ | ||
105 | static inline __sum16 *gre_csum(struct gre_hdr *greh) | ||
106 | { | ||
107 | if (!greh->csum) | ||
108 | return NULL; | ||
109 | return (__sum16 *) (greh+sizeof(*greh)); | ||
110 | } | ||
111 | |||
112 | #endif /* __KERNEL__ */ | ||
113 | |||
114 | #endif /* _CONNTRACK_PROTO_GRE_H */ | ||
diff --git a/include/linux/netfilter_ipv4/ip_conntrack_protocol.h b/include/linux/netfilter_ipv4/ip_conntrack_protocol.h deleted file mode 100644 index 2c76b879e3dc..000000000000 --- a/include/linux/netfilter_ipv4/ip_conntrack_protocol.h +++ /dev/null | |||
@@ -1,98 +0,0 @@ | |||
1 | /* Header for use in defining a given protocol for connection tracking. */ | ||
2 | #ifndef _IP_CONNTRACK_PROTOCOL_H | ||
3 | #define _IP_CONNTRACK_PROTOCOL_H | ||
4 | #include <linux/netfilter_ipv4/ip_conntrack.h> | ||
5 | #include <linux/netfilter/nfnetlink_conntrack.h> | ||
6 | |||
7 | struct seq_file; | ||
8 | |||
9 | struct ip_conntrack_protocol | ||
10 | { | ||
11 | /* Protocol number. */ | ||
12 | u_int8_t proto; | ||
13 | |||
14 | /* Protocol name */ | ||
15 | const char *name; | ||
16 | |||
17 | /* Try to fill in the third arg: dataoff is offset past IP | ||
18 | hdr. Return true if possible. */ | ||
19 | int (*pkt_to_tuple)(const struct sk_buff *skb, | ||
20 | unsigned int dataoff, | ||
21 | struct ip_conntrack_tuple *tuple); | ||
22 | |||
23 | /* Invert the per-proto part of the tuple: ie. turn xmit into reply. | ||
24 | * Some packets can't be inverted: return 0 in that case. | ||
25 | */ | ||
26 | int (*invert_tuple)(struct ip_conntrack_tuple *inverse, | ||
27 | const struct ip_conntrack_tuple *orig); | ||
28 | |||
29 | /* Print out the per-protocol part of the tuple. Return like seq_* */ | ||
30 | int (*print_tuple)(struct seq_file *, | ||
31 | const struct ip_conntrack_tuple *); | ||
32 | |||
33 | /* Print out the private part of the conntrack. */ | ||
34 | int (*print_conntrack)(struct seq_file *, const struct ip_conntrack *); | ||
35 | |||
36 | /* Returns verdict for packet, or -1 for invalid. */ | ||
37 | int (*packet)(struct ip_conntrack *conntrack, | ||
38 | const struct sk_buff *skb, | ||
39 | enum ip_conntrack_info ctinfo); | ||
40 | |||
41 | /* Called when a new connection for this protocol found; | ||
42 | * returns TRUE if it's OK. If so, packet() called next. */ | ||
43 | int (*new)(struct ip_conntrack *conntrack, const struct sk_buff *skb); | ||
44 | |||
45 | /* Called when a conntrack entry is destroyed */ | ||
46 | void (*destroy)(struct ip_conntrack *conntrack); | ||
47 | |||
48 | int (*error)(struct sk_buff *skb, enum ip_conntrack_info *ctinfo, | ||
49 | unsigned int hooknum); | ||
50 | |||
51 | /* convert protoinfo to nfnetink attributes */ | ||
52 | int (*to_nfattr)(struct sk_buff *skb, struct nfattr *nfa, | ||
53 | const struct ip_conntrack *ct); | ||
54 | |||
55 | /* convert nfnetlink attributes to protoinfo */ | ||
56 | int (*from_nfattr)(struct nfattr *tb[], struct ip_conntrack *ct); | ||
57 | |||
58 | int (*tuple_to_nfattr)(struct sk_buff *skb, | ||
59 | const struct ip_conntrack_tuple *t); | ||
60 | int (*nfattr_to_tuple)(struct nfattr *tb[], | ||
61 | struct ip_conntrack_tuple *t); | ||
62 | |||
63 | /* Module (if any) which this is connected to. */ | ||
64 | struct module *me; | ||
65 | }; | ||
66 | |||
67 | /* Protocol registration. */ | ||
68 | extern int ip_conntrack_protocol_register(struct ip_conntrack_protocol *proto); | ||
69 | extern void ip_conntrack_protocol_unregister(struct ip_conntrack_protocol *proto); | ||
70 | /* Existing built-in protocols */ | ||
71 | extern struct ip_conntrack_protocol ip_conntrack_protocol_tcp; | ||
72 | extern struct ip_conntrack_protocol ip_conntrack_protocol_udp; | ||
73 | extern struct ip_conntrack_protocol ip_conntrack_protocol_icmp; | ||
74 | extern struct ip_conntrack_protocol ip_conntrack_generic_protocol; | ||
75 | extern int ip_conntrack_protocol_tcp_init(void); | ||
76 | |||
77 | /* Log invalid packets */ | ||
78 | extern unsigned int ip_ct_log_invalid; | ||
79 | |||
80 | extern int ip_ct_port_tuple_to_nfattr(struct sk_buff *, | ||
81 | const struct ip_conntrack_tuple *); | ||
82 | extern int ip_ct_port_nfattr_to_tuple(struct nfattr *tb[], | ||
83 | struct ip_conntrack_tuple *); | ||
84 | |||
85 | #ifdef CONFIG_SYSCTL | ||
86 | #ifdef DEBUG_INVALID_PACKETS | ||
87 | #define LOG_INVALID(proto) \ | ||
88 | (ip_ct_log_invalid == (proto) || ip_ct_log_invalid == IPPROTO_RAW) | ||
89 | #else | ||
90 | #define LOG_INVALID(proto) \ | ||
91 | ((ip_ct_log_invalid == (proto) || ip_ct_log_invalid == IPPROTO_RAW) \ | ||
92 | && net_ratelimit()) | ||
93 | #endif | ||
94 | #else | ||
95 | #define LOG_INVALID(proto) 0 | ||
96 | #endif /* CONFIG_SYSCTL */ | ||
97 | |||
98 | #endif /*_IP_CONNTRACK_PROTOCOL_H*/ | ||
diff --git a/include/linux/netfilter_ipv4/ip_conntrack_sctp.h b/include/linux/netfilter_ipv4/ip_conntrack_sctp.h deleted file mode 100644 index 4099a041a32a..000000000000 --- a/include/linux/netfilter_ipv4/ip_conntrack_sctp.h +++ /dev/null | |||
@@ -1,6 +0,0 @@ | |||
1 | #ifndef _IP_CONNTRACK_SCTP_H | ||
2 | #define _IP_CONNTRACK_SCTP_H | ||
3 | |||
4 | #include <linux/netfilter/nf_conntrack_sctp.h> | ||
5 | |||
6 | #endif /* _IP_CONNTRACK_SCTP_H */ | ||
diff --git a/include/linux/netfilter_ipv4/ip_conntrack_sip.h b/include/linux/netfilter_ipv4/ip_conntrack_sip.h deleted file mode 100644 index bef6c646defa..000000000000 --- a/include/linux/netfilter_ipv4/ip_conntrack_sip.h +++ /dev/null | |||
@@ -1,40 +0,0 @@ | |||
1 | #ifndef __IP_CONNTRACK_SIP_H__ | ||
2 | #define __IP_CONNTRACK_SIP_H__ | ||
3 | #ifdef __KERNEL__ | ||
4 | |||
5 | #define SIP_PORT 5060 | ||
6 | #define SIP_TIMEOUT 3600 | ||
7 | |||
8 | enum sip_header_pos { | ||
9 | POS_REG_REQ_URI, | ||
10 | POS_REQ_URI, | ||
11 | POS_FROM, | ||
12 | POS_TO, | ||
13 | POS_VIA, | ||
14 | POS_CONTACT, | ||
15 | POS_CONTENT, | ||
16 | POS_MEDIA, | ||
17 | POS_OWNER, | ||
18 | POS_CONNECTION, | ||
19 | POS_SDP_HEADER, | ||
20 | }; | ||
21 | |||
22 | extern unsigned int (*ip_nat_sip_hook)(struct sk_buff **pskb, | ||
23 | enum ip_conntrack_info ctinfo, | ||
24 | struct ip_conntrack *ct, | ||
25 | const char **dptr); | ||
26 | extern unsigned int (*ip_nat_sdp_hook)(struct sk_buff **pskb, | ||
27 | enum ip_conntrack_info ctinfo, | ||
28 | struct ip_conntrack_expect *exp, | ||
29 | const char *dptr); | ||
30 | |||
31 | extern int ct_sip_get_info(const char *dptr, size_t dlen, | ||
32 | unsigned int *matchoff, | ||
33 | unsigned int *matchlen, | ||
34 | enum sip_header_pos pos); | ||
35 | extern int ct_sip_lnlen(const char *line, const char *limit); | ||
36 | extern const char *ct_sip_search(const char *needle, const char *haystack, | ||
37 | size_t needle_len, size_t haystack_len, | ||
38 | int case_sensitive); | ||
39 | #endif /* __KERNEL__ */ | ||
40 | #endif /* __IP_CONNTRACK_SIP_H__ */ | ||
diff --git a/include/linux/netfilter_ipv4/ip_conntrack_tcp.h b/include/linux/netfilter_ipv4/ip_conntrack_tcp.h deleted file mode 100644 index 876b8fb17e68..000000000000 --- a/include/linux/netfilter_ipv4/ip_conntrack_tcp.h +++ /dev/null | |||
@@ -1,6 +0,0 @@ | |||
1 | #ifndef _IP_CONNTRACK_TCP_H | ||
2 | #define _IP_CONNTRACK_TCP_H | ||
3 | |||
4 | #include <linux/netfilter/nf_conntrack_tcp.h> | ||
5 | |||
6 | #endif /* _IP_CONNTRACK_TCP_H */ | ||
diff --git a/include/linux/netfilter_ipv4/ip_conntrack_tftp.h b/include/linux/netfilter_ipv4/ip_conntrack_tftp.h deleted file mode 100644 index a404fc0abf0e..000000000000 --- a/include/linux/netfilter_ipv4/ip_conntrack_tftp.h +++ /dev/null | |||
@@ -1,20 +0,0 @@ | |||
1 | #ifndef _IP_CT_TFTP | ||
2 | #define _IP_CT_TFTP | ||
3 | |||
4 | #define TFTP_PORT 69 | ||
5 | |||
6 | struct tftphdr { | ||
7 | __be16 opcode; | ||
8 | }; | ||
9 | |||
10 | #define TFTP_OPCODE_READ 1 | ||
11 | #define TFTP_OPCODE_WRITE 2 | ||
12 | #define TFTP_OPCODE_DATA 3 | ||
13 | #define TFTP_OPCODE_ACK 4 | ||
14 | #define TFTP_OPCODE_ERROR 5 | ||
15 | |||
16 | extern unsigned int (*ip_nat_tftp_hook)(struct sk_buff **pskb, | ||
17 | enum ip_conntrack_info ctinfo, | ||
18 | struct ip_conntrack_expect *exp); | ||
19 | |||
20 | #endif /* _IP_CT_TFTP */ | ||
diff --git a/include/linux/netfilter_ipv4/ip_conntrack_tuple.h b/include/linux/netfilter_ipv4/ip_conntrack_tuple.h deleted file mode 100644 index c228bde74c33..000000000000 --- a/include/linux/netfilter_ipv4/ip_conntrack_tuple.h +++ /dev/null | |||
@@ -1,146 +0,0 @@ | |||
1 | #ifndef _IP_CONNTRACK_TUPLE_H | ||
2 | #define _IP_CONNTRACK_TUPLE_H | ||
3 | |||
4 | #include <linux/types.h> | ||
5 | #include <linux/netfilter/nf_conntrack_tuple_common.h> | ||
6 | |||
7 | /* A `tuple' is a structure containing the information to uniquely | ||
8 | identify a connection. ie. if two packets have the same tuple, they | ||
9 | are in the same connection; if not, they are not. | ||
10 | |||
11 | We divide the structure along "manipulatable" and | ||
12 | "non-manipulatable" lines, for the benefit of the NAT code. | ||
13 | */ | ||
14 | |||
15 | /* The protocol-specific manipulable parts of the tuple: always in | ||
16 | network order! */ | ||
17 | union ip_conntrack_manip_proto | ||
18 | { | ||
19 | /* Add other protocols here. */ | ||
20 | u_int16_t all; | ||
21 | |||
22 | struct { | ||
23 | __be16 port; | ||
24 | } tcp; | ||
25 | struct { | ||
26 | __be16 port; | ||
27 | } udp; | ||
28 | struct { | ||
29 | __be16 id; | ||
30 | } icmp; | ||
31 | struct { | ||
32 | __be16 port; | ||
33 | } sctp; | ||
34 | struct { | ||
35 | __be16 key; /* key is 32bit, pptp only uses 16 */ | ||
36 | } gre; | ||
37 | }; | ||
38 | |||
39 | /* The manipulable part of the tuple. */ | ||
40 | struct ip_conntrack_manip | ||
41 | { | ||
42 | __be32 ip; | ||
43 | union ip_conntrack_manip_proto u; | ||
44 | }; | ||
45 | |||
46 | /* This contains the information to distinguish a connection. */ | ||
47 | struct ip_conntrack_tuple | ||
48 | { | ||
49 | struct ip_conntrack_manip src; | ||
50 | |||
51 | /* These are the parts of the tuple which are fixed. */ | ||
52 | struct { | ||
53 | __be32 ip; | ||
54 | union { | ||
55 | /* Add other protocols here. */ | ||
56 | u_int16_t all; | ||
57 | |||
58 | struct { | ||
59 | __be16 port; | ||
60 | } tcp; | ||
61 | struct { | ||
62 | __be16 port; | ||
63 | } udp; | ||
64 | struct { | ||
65 | u_int8_t type, code; | ||
66 | } icmp; | ||
67 | struct { | ||
68 | __be16 port; | ||
69 | } sctp; | ||
70 | struct { | ||
71 | __be16 key; /* key is 32bit, | ||
72 | * pptp only uses 16 */ | ||
73 | } gre; | ||
74 | } u; | ||
75 | |||
76 | /* The protocol. */ | ||
77 | u_int8_t protonum; | ||
78 | |||
79 | /* The direction (for tuplehash) */ | ||
80 | u_int8_t dir; | ||
81 | } dst; | ||
82 | }; | ||
83 | |||
84 | /* This is optimized opposed to a memset of the whole structure. Everything we | ||
85 | * really care about is the source/destination unions */ | ||
86 | #define IP_CT_TUPLE_U_BLANK(tuple) \ | ||
87 | do { \ | ||
88 | (tuple)->src.u.all = 0; \ | ||
89 | (tuple)->dst.u.all = 0; \ | ||
90 | } while (0) | ||
91 | |||
92 | #ifdef __KERNEL__ | ||
93 | |||
94 | #define DUMP_TUPLE(tp) \ | ||
95 | DEBUGP("tuple %p: %u %u.%u.%u.%u:%hu -> %u.%u.%u.%u:%hu\n", \ | ||
96 | (tp), (tp)->dst.protonum, \ | ||
97 | NIPQUAD((tp)->src.ip), ntohs((tp)->src.u.all), \ | ||
98 | NIPQUAD((tp)->dst.ip), ntohs((tp)->dst.u.all)) | ||
99 | |||
100 | /* If we're the first tuple, it's the original dir. */ | ||
101 | #define DIRECTION(h) ((enum ip_conntrack_dir)(h)->tuple.dst.dir) | ||
102 | |||
103 | /* Connections have two entries in the hash table: one for each way */ | ||
104 | struct ip_conntrack_tuple_hash | ||
105 | { | ||
106 | struct list_head list; | ||
107 | |||
108 | struct ip_conntrack_tuple tuple; | ||
109 | }; | ||
110 | |||
111 | #endif /* __KERNEL__ */ | ||
112 | |||
113 | static inline int ip_ct_tuple_src_equal(const struct ip_conntrack_tuple *t1, | ||
114 | const struct ip_conntrack_tuple *t2) | ||
115 | { | ||
116 | return t1->src.ip == t2->src.ip | ||
117 | && t1->src.u.all == t2->src.u.all; | ||
118 | } | ||
119 | |||
120 | static inline int ip_ct_tuple_dst_equal(const struct ip_conntrack_tuple *t1, | ||
121 | const struct ip_conntrack_tuple *t2) | ||
122 | { | ||
123 | return t1->dst.ip == t2->dst.ip | ||
124 | && t1->dst.u.all == t2->dst.u.all | ||
125 | && t1->dst.protonum == t2->dst.protonum; | ||
126 | } | ||
127 | |||
128 | static inline int ip_ct_tuple_equal(const struct ip_conntrack_tuple *t1, | ||
129 | const struct ip_conntrack_tuple *t2) | ||
130 | { | ||
131 | return ip_ct_tuple_src_equal(t1, t2) && ip_ct_tuple_dst_equal(t1, t2); | ||
132 | } | ||
133 | |||
134 | static inline int ip_ct_tuple_mask_cmp(const struct ip_conntrack_tuple *t, | ||
135 | const struct ip_conntrack_tuple *tuple, | ||
136 | const struct ip_conntrack_tuple *mask) | ||
137 | { | ||
138 | return !(((t->src.ip ^ tuple->src.ip) & mask->src.ip) | ||
139 | || ((t->dst.ip ^ tuple->dst.ip) & mask->dst.ip) | ||
140 | || ((t->src.u.all ^ tuple->src.u.all) & mask->src.u.all) | ||
141 | || ((t->dst.u.all ^ tuple->dst.u.all) & mask->dst.u.all) | ||
142 | || ((t->dst.protonum ^ tuple->dst.protonum) | ||
143 | & mask->dst.protonum)); | ||
144 | } | ||
145 | |||
146 | #endif /* _IP_CONNTRACK_TUPLE_H */ | ||
diff --git a/include/linux/netfilter_ipv4/ip_nat.h b/include/linux/netfilter_ipv4/ip_nat.h deleted file mode 100644 index bbca89aab813..000000000000 --- a/include/linux/netfilter_ipv4/ip_nat.h +++ /dev/null | |||
@@ -1,79 +0,0 @@ | |||
1 | #ifndef _IP_NAT_H | ||
2 | #define _IP_NAT_H | ||
3 | #include <linux/netfilter_ipv4.h> | ||
4 | #include <linux/netfilter_ipv4/ip_conntrack_tuple.h> | ||
5 | |||
6 | #define IP_NAT_MAPPING_TYPE_MAX_NAMELEN 16 | ||
7 | |||
8 | enum ip_nat_manip_type | ||
9 | { | ||
10 | IP_NAT_MANIP_SRC, | ||
11 | IP_NAT_MANIP_DST | ||
12 | }; | ||
13 | |||
14 | /* SRC manip occurs POST_ROUTING or LOCAL_IN */ | ||
15 | #define HOOK2MANIP(hooknum) ((hooknum) != NF_IP_POST_ROUTING && (hooknum) != NF_IP_LOCAL_IN) | ||
16 | |||
17 | #define IP_NAT_RANGE_MAP_IPS 1 | ||
18 | #define IP_NAT_RANGE_PROTO_SPECIFIED 2 | ||
19 | #define IP_NAT_RANGE_PROTO_RANDOM 4 /* add randomness to "port" selection */ | ||
20 | |||
21 | /* NAT sequence number modifications */ | ||
22 | struct ip_nat_seq { | ||
23 | /* position of the last TCP sequence number | ||
24 | * modification (if any) */ | ||
25 | u_int32_t correction_pos; | ||
26 | /* sequence number offset before and after last modification */ | ||
27 | int16_t offset_before, offset_after; | ||
28 | }; | ||
29 | |||
30 | /* Single range specification. */ | ||
31 | struct ip_nat_range | ||
32 | { | ||
33 | /* Set to OR of flags above. */ | ||
34 | unsigned int flags; | ||
35 | |||
36 | /* Inclusive: network order. */ | ||
37 | __be32 min_ip, max_ip; | ||
38 | |||
39 | /* Inclusive: network order */ | ||
40 | union ip_conntrack_manip_proto min, max; | ||
41 | }; | ||
42 | |||
43 | /* For backwards compat: don't use in modern code. */ | ||
44 | struct ip_nat_multi_range_compat | ||
45 | { | ||
46 | unsigned int rangesize; /* Must be 1. */ | ||
47 | |||
48 | /* hangs off end. */ | ||
49 | struct ip_nat_range range[1]; | ||
50 | }; | ||
51 | |||
52 | #ifdef __KERNEL__ | ||
53 | #include <linux/list.h> | ||
54 | |||
55 | /* Protects NAT hash tables, and NAT-private part of conntracks. */ | ||
56 | extern rwlock_t ip_nat_lock; | ||
57 | |||
58 | /* The structure embedded in the conntrack structure. */ | ||
59 | struct ip_nat_info | ||
60 | { | ||
61 | struct list_head bysource; | ||
62 | struct ip_nat_seq seq[IP_CT_DIR_MAX]; | ||
63 | }; | ||
64 | |||
65 | struct ip_conntrack; | ||
66 | |||
67 | /* Set up the info structure to map into this range. */ | ||
68 | extern unsigned int ip_nat_setup_info(struct ip_conntrack *conntrack, | ||
69 | const struct ip_nat_range *range, | ||
70 | unsigned int hooknum); | ||
71 | |||
72 | /* Is this tuple already taken? (not by us)*/ | ||
73 | extern int ip_nat_used_tuple(const struct ip_conntrack_tuple *tuple, | ||
74 | const struct ip_conntrack *ignored_conntrack); | ||
75 | |||
76 | #else /* !__KERNEL__: iptables wants this to compile. */ | ||
77 | #define ip_nat_multi_range ip_nat_multi_range_compat | ||
78 | #endif /*__KERNEL__*/ | ||
79 | #endif | ||
diff --git a/include/linux/netfilter_ipv4/ip_nat_core.h b/include/linux/netfilter_ipv4/ip_nat_core.h deleted file mode 100644 index 60566f9fd7b3..000000000000 --- a/include/linux/netfilter_ipv4/ip_nat_core.h +++ /dev/null | |||
@@ -1,18 +0,0 @@ | |||
1 | #ifndef _IP_NAT_CORE_H | ||
2 | #define _IP_NAT_CORE_H | ||
3 | #include <linux/list.h> | ||
4 | #include <linux/netfilter_ipv4/ip_conntrack.h> | ||
5 | |||
6 | /* This header used to share core functionality between the standalone | ||
7 | NAT module, and the compatibility layer's use of NAT for masquerading. */ | ||
8 | |||
9 | extern unsigned int ip_nat_packet(struct ip_conntrack *ct, | ||
10 | enum ip_conntrack_info conntrackinfo, | ||
11 | unsigned int hooknum, | ||
12 | struct sk_buff **pskb); | ||
13 | |||
14 | extern int ip_nat_icmp_reply_translation(struct ip_conntrack *ct, | ||
15 | enum ip_conntrack_info ctinfo, | ||
16 | unsigned int hooknum, | ||
17 | struct sk_buff **pskb); | ||
18 | #endif /* _IP_NAT_CORE_H */ | ||
diff --git a/include/linux/netfilter_ipv4/ip_nat_helper.h b/include/linux/netfilter_ipv4/ip_nat_helper.h deleted file mode 100644 index bf9cb105c885..000000000000 --- a/include/linux/netfilter_ipv4/ip_nat_helper.h +++ /dev/null | |||
@@ -1,33 +0,0 @@ | |||
1 | #ifndef _IP_NAT_HELPER_H | ||
2 | #define _IP_NAT_HELPER_H | ||
3 | /* NAT protocol helper routines. */ | ||
4 | |||
5 | #include <linux/netfilter_ipv4/ip_conntrack.h> | ||
6 | #include <linux/module.h> | ||
7 | |||
8 | struct sk_buff; | ||
9 | |||
10 | /* These return true or false. */ | ||
11 | extern int ip_nat_mangle_tcp_packet(struct sk_buff **skb, | ||
12 | struct ip_conntrack *ct, | ||
13 | enum ip_conntrack_info ctinfo, | ||
14 | unsigned int match_offset, | ||
15 | unsigned int match_len, | ||
16 | const char *rep_buffer, | ||
17 | unsigned int rep_len); | ||
18 | extern int ip_nat_mangle_udp_packet(struct sk_buff **skb, | ||
19 | struct ip_conntrack *ct, | ||
20 | enum ip_conntrack_info ctinfo, | ||
21 | unsigned int match_offset, | ||
22 | unsigned int match_len, | ||
23 | const char *rep_buffer, | ||
24 | unsigned int rep_len); | ||
25 | extern int ip_nat_seq_adjust(struct sk_buff **pskb, | ||
26 | struct ip_conntrack *ct, | ||
27 | enum ip_conntrack_info ctinfo); | ||
28 | |||
29 | /* Setup NAT on this expected conntrack so it follows master, but goes | ||
30 | * to port ct->master->saved_proto. */ | ||
31 | extern void ip_nat_follow_master(struct ip_conntrack *ct, | ||
32 | struct ip_conntrack_expect *this); | ||
33 | #endif | ||
diff --git a/include/linux/netfilter_ipv4/ip_nat_pptp.h b/include/linux/netfilter_ipv4/ip_nat_pptp.h deleted file mode 100644 index 36668bf0f373..000000000000 --- a/include/linux/netfilter_ipv4/ip_nat_pptp.h +++ /dev/null | |||
@@ -1,11 +0,0 @@ | |||
1 | /* PPTP constants and structs */ | ||
2 | #ifndef _NAT_PPTP_H | ||
3 | #define _NAT_PPTP_H | ||
4 | |||
5 | /* conntrack private data */ | ||
6 | struct ip_nat_pptp { | ||
7 | __be16 pns_call_id; /* NAT'ed PNS call id */ | ||
8 | __be16 pac_call_id; /* NAT'ed PAC call id */ | ||
9 | }; | ||
10 | |||
11 | #endif /* _NAT_PPTP_H */ | ||
diff --git a/include/linux/netfilter_ipv4/ip_nat_protocol.h b/include/linux/netfilter_ipv4/ip_nat_protocol.h deleted file mode 100644 index 612a43614e7b..000000000000 --- a/include/linux/netfilter_ipv4/ip_nat_protocol.h +++ /dev/null | |||
@@ -1,74 +0,0 @@ | |||
1 | /* Header for use in defining a given protocol. */ | ||
2 | #ifndef _IP_NAT_PROTOCOL_H | ||
3 | #define _IP_NAT_PROTOCOL_H | ||
4 | #include <linux/init.h> | ||
5 | #include <linux/list.h> | ||
6 | |||
7 | #include <linux/netfilter_ipv4/ip_nat.h> | ||
8 | #include <linux/netfilter/nfnetlink_conntrack.h> | ||
9 | |||
10 | struct iphdr; | ||
11 | struct ip_nat_range; | ||
12 | |||
13 | struct ip_nat_protocol | ||
14 | { | ||
15 | /* Protocol name */ | ||
16 | const char *name; | ||
17 | |||
18 | /* Protocol number. */ | ||
19 | unsigned int protonum; | ||
20 | |||
21 | struct module *me; | ||
22 | |||
23 | /* Translate a packet to the target according to manip type. | ||
24 | Return true if succeeded. */ | ||
25 | int (*manip_pkt)(struct sk_buff **pskb, | ||
26 | unsigned int iphdroff, | ||
27 | const struct ip_conntrack_tuple *tuple, | ||
28 | enum ip_nat_manip_type maniptype); | ||
29 | |||
30 | /* Is the manipable part of the tuple between min and max incl? */ | ||
31 | int (*in_range)(const struct ip_conntrack_tuple *tuple, | ||
32 | enum ip_nat_manip_type maniptype, | ||
33 | const union ip_conntrack_manip_proto *min, | ||
34 | const union ip_conntrack_manip_proto *max); | ||
35 | |||
36 | /* Alter the per-proto part of the tuple (depending on | ||
37 | maniptype), to give a unique tuple in the given range if | ||
38 | possible; return false if not. Per-protocol part of tuple | ||
39 | is initialized to the incoming packet. */ | ||
40 | int (*unique_tuple)(struct ip_conntrack_tuple *tuple, | ||
41 | const struct ip_nat_range *range, | ||
42 | enum ip_nat_manip_type maniptype, | ||
43 | const struct ip_conntrack *conntrack); | ||
44 | |||
45 | int (*range_to_nfattr)(struct sk_buff *skb, | ||
46 | const struct ip_nat_range *range); | ||
47 | |||
48 | int (*nfattr_to_range)(struct nfattr *tb[], | ||
49 | struct ip_nat_range *range); | ||
50 | }; | ||
51 | |||
52 | /* Protocol registration. */ | ||
53 | extern int ip_nat_protocol_register(struct ip_nat_protocol *proto); | ||
54 | extern void ip_nat_protocol_unregister(struct ip_nat_protocol *proto); | ||
55 | |||
56 | extern struct ip_nat_protocol *ip_nat_proto_find_get(u_int8_t protocol); | ||
57 | extern void ip_nat_proto_put(struct ip_nat_protocol *proto); | ||
58 | |||
59 | /* Built-in protocols. */ | ||
60 | extern struct ip_nat_protocol ip_nat_protocol_tcp; | ||
61 | extern struct ip_nat_protocol ip_nat_protocol_udp; | ||
62 | extern struct ip_nat_protocol ip_nat_protocol_icmp; | ||
63 | extern struct ip_nat_protocol ip_nat_unknown_protocol; | ||
64 | |||
65 | extern int init_protocols(void) __init; | ||
66 | extern void cleanup_protocols(void); | ||
67 | extern struct ip_nat_protocol *find_nat_proto(u_int16_t protonum); | ||
68 | |||
69 | extern int ip_nat_port_range_to_nfattr(struct sk_buff *skb, | ||
70 | const struct ip_nat_range *range); | ||
71 | extern int ip_nat_port_nfattr_to_range(struct nfattr *tb[], | ||
72 | struct ip_nat_range *range); | ||
73 | |||
74 | #endif /*_IP_NAT_PROTO_H*/ | ||
diff --git a/include/linux/netfilter_ipv4/ip_nat_rule.h b/include/linux/netfilter_ipv4/ip_nat_rule.h deleted file mode 100644 index 73b9552e6a89..000000000000 --- a/include/linux/netfilter_ipv4/ip_nat_rule.h +++ /dev/null | |||
@@ -1,28 +0,0 @@ | |||
1 | #ifndef _IP_NAT_RULE_H | ||
2 | #define _IP_NAT_RULE_H | ||
3 | #include <linux/netfilter_ipv4/ip_conntrack.h> | ||
4 | #include <linux/netfilter_ipv4/ip_tables.h> | ||
5 | #include <linux/netfilter_ipv4/ip_nat.h> | ||
6 | |||
7 | #ifdef __KERNEL__ | ||
8 | |||
9 | extern int ip_nat_rule_init(void) __init; | ||
10 | extern void ip_nat_rule_cleanup(void); | ||
11 | extern int ip_nat_rule_find(struct sk_buff **pskb, | ||
12 | unsigned int hooknum, | ||
13 | const struct net_device *in, | ||
14 | const struct net_device *out, | ||
15 | struct ip_conntrack *ct, | ||
16 | struct ip_nat_info *info); | ||
17 | |||
18 | extern unsigned int | ||
19 | alloc_null_binding(struct ip_conntrack *conntrack, | ||
20 | struct ip_nat_info *info, | ||
21 | unsigned int hooknum); | ||
22 | |||
23 | extern unsigned int | ||
24 | alloc_null_binding_confirmed(struct ip_conntrack *conntrack, | ||
25 | struct ip_nat_info *info, | ||
26 | unsigned int hooknum); | ||
27 | #endif | ||
28 | #endif /* _IP_NAT_RULE_H */ | ||
diff --git a/include/linux/netfilter_ipv4/ipt_SAME.h b/include/linux/netfilter_ipv4/ipt_SAME.h index cc4c0b2269af..be6e682a85ec 100644 --- a/include/linux/netfilter_ipv4/ipt_SAME.h +++ b/include/linux/netfilter_ipv4/ipt_SAME.h | |||
@@ -13,7 +13,7 @@ struct ipt_same_info | |||
13 | u_int32_t *iparray; | 13 | u_int32_t *iparray; |
14 | 14 | ||
15 | /* hangs off end. */ | 15 | /* hangs off end. */ |
16 | struct ip_nat_range range[IPT_SAME_MAX_RANGE]; | 16 | struct nf_nat_range range[IPT_SAME_MAX_RANGE]; |
17 | }; | 17 | }; |
18 | 18 | ||
19 | #endif /*_IPT_SAME_H*/ | 19 | #endif /*_IPT_SAME_H*/ |
diff --git a/include/net/netfilter/nf_conntrack.h b/include/net/netfilter/nf_conntrack.h index 0e690e34c00b..1c6b8bd09b9a 100644 --- a/include/net/netfilter/nf_conntrack.h +++ b/include/net/netfilter/nf_conntrack.h | |||
@@ -250,6 +250,11 @@ static inline int nf_ct_is_dying(struct nf_conn *ct) | |||
250 | return test_bit(IPS_DYING_BIT, &ct->status); | 250 | return test_bit(IPS_DYING_BIT, &ct->status); |
251 | } | 251 | } |
252 | 252 | ||
253 | static inline int nf_ct_is_untracked(const struct sk_buff *skb) | ||
254 | { | ||
255 | return (skb->nfct == &nf_conntrack_untracked.ct_general); | ||
256 | } | ||
257 | |||
253 | extern unsigned int nf_conntrack_htable_size; | 258 | extern unsigned int nf_conntrack_htable_size; |
254 | extern int nf_conntrack_checksum; | 259 | extern int nf_conntrack_checksum; |
255 | extern atomic_t nf_conntrack_count; | 260 | extern atomic_t nf_conntrack_count; |
diff --git a/include/net/netfilter/nf_conntrack_compat.h b/include/net/netfilter/nf_conntrack_compat.h deleted file mode 100644 index 6f84c1f7fcd4..000000000000 --- a/include/net/netfilter/nf_conntrack_compat.h +++ /dev/null | |||
@@ -1,145 +0,0 @@ | |||
1 | #ifndef _NF_CONNTRACK_COMPAT_H | ||
2 | #define _NF_CONNTRACK_COMPAT_H | ||
3 | |||
4 | #ifdef __KERNEL__ | ||
5 | |||
6 | #if defined(CONFIG_IP_NF_CONNTRACK) || defined(CONFIG_IP_NF_CONNTRACK_MODULE) | ||
7 | |||
8 | #include <linux/netfilter_ipv4/ip_conntrack.h> | ||
9 | #include <linux/socket.h> | ||
10 | |||
11 | #ifdef CONFIG_IP_NF_CONNTRACK_MARK | ||
12 | static inline u_int32_t *nf_ct_get_mark(const struct sk_buff *skb, | ||
13 | u_int32_t *ctinfo) | ||
14 | { | ||
15 | struct ip_conntrack *ct = ip_conntrack_get(skb, ctinfo); | ||
16 | |||
17 | if (ct) | ||
18 | return &ct->mark; | ||
19 | else | ||
20 | return NULL; | ||
21 | } | ||
22 | #endif /* CONFIG_IP_NF_CONNTRACK_MARK */ | ||
23 | |||
24 | #ifdef CONFIG_IP_NF_CONNTRACK_SECMARK | ||
25 | static inline u_int32_t *nf_ct_get_secmark(const struct sk_buff *skb, | ||
26 | u_int32_t *ctinfo) | ||
27 | { | ||
28 | struct ip_conntrack *ct = ip_conntrack_get(skb, ctinfo); | ||
29 | |||
30 | if (ct) | ||
31 | return &ct->secmark; | ||
32 | else | ||
33 | return NULL; | ||
34 | } | ||
35 | #endif /* CONFIG_IP_NF_CONNTRACK_SECMARK */ | ||
36 | |||
37 | #ifdef CONFIG_IP_NF_CT_ACCT | ||
38 | static inline struct ip_conntrack_counter * | ||
39 | nf_ct_get_counters(const struct sk_buff *skb) | ||
40 | { | ||
41 | enum ip_conntrack_info ctinfo; | ||
42 | struct ip_conntrack *ct = ip_conntrack_get(skb, &ctinfo); | ||
43 | |||
44 | if (ct) | ||
45 | return ct->counters; | ||
46 | else | ||
47 | return NULL; | ||
48 | } | ||
49 | #endif /* CONFIG_IP_NF_CT_ACCT */ | ||
50 | |||
51 | static inline int nf_ct_is_untracked(const struct sk_buff *skb) | ||
52 | { | ||
53 | return (skb->nfct == &ip_conntrack_untracked.ct_general); | ||
54 | } | ||
55 | |||
56 | static inline void nf_ct_untrack(struct sk_buff *skb) | ||
57 | { | ||
58 | skb->nfct = &ip_conntrack_untracked.ct_general; | ||
59 | } | ||
60 | |||
61 | static inline int nf_ct_get_ctinfo(const struct sk_buff *skb, | ||
62 | enum ip_conntrack_info *ctinfo) | ||
63 | { | ||
64 | struct ip_conntrack *ct = ip_conntrack_get(skb, ctinfo); | ||
65 | return (ct != NULL); | ||
66 | } | ||
67 | |||
68 | static inline int nf_ct_l3proto_try_module_get(unsigned short l3proto) | ||
69 | { | ||
70 | need_conntrack(); | ||
71 | return l3proto == PF_INET ? 0 : -1; | ||
72 | } | ||
73 | |||
74 | static inline void nf_ct_l3proto_module_put(unsigned short l3proto) | ||
75 | { | ||
76 | } | ||
77 | |||
78 | #else /* CONFIG_IP_NF_CONNTRACK */ | ||
79 | |||
80 | #include <net/netfilter/ipv4/nf_conntrack_ipv4.h> | ||
81 | #include <net/netfilter/nf_conntrack.h> | ||
82 | |||
83 | #ifdef CONFIG_NF_CONNTRACK_MARK | ||
84 | |||
85 | static inline u_int32_t *nf_ct_get_mark(const struct sk_buff *skb, | ||
86 | u_int32_t *ctinfo) | ||
87 | { | ||
88 | struct nf_conn *ct = nf_ct_get(skb, ctinfo); | ||
89 | |||
90 | if (ct) | ||
91 | return &ct->mark; | ||
92 | else | ||
93 | return NULL; | ||
94 | } | ||
95 | #endif /* CONFIG_NF_CONNTRACK_MARK */ | ||
96 | |||
97 | #ifdef CONFIG_NF_CONNTRACK_SECMARK | ||
98 | static inline u_int32_t *nf_ct_get_secmark(const struct sk_buff *skb, | ||
99 | u_int32_t *ctinfo) | ||
100 | { | ||
101 | struct nf_conn *ct = nf_ct_get(skb, ctinfo); | ||
102 | |||
103 | if (ct) | ||
104 | return &ct->secmark; | ||
105 | else | ||
106 | return NULL; | ||
107 | } | ||
108 | #endif /* CONFIG_NF_CONNTRACK_MARK */ | ||
109 | |||
110 | #ifdef CONFIG_NF_CT_ACCT | ||
111 | static inline struct ip_conntrack_counter * | ||
112 | nf_ct_get_counters(const struct sk_buff *skb) | ||
113 | { | ||
114 | enum ip_conntrack_info ctinfo; | ||
115 | struct nf_conn *ct = nf_ct_get(skb, &ctinfo); | ||
116 | |||
117 | if (ct) | ||
118 | return ct->counters; | ||
119 | else | ||
120 | return NULL; | ||
121 | } | ||
122 | #endif /* CONFIG_NF_CT_ACCT */ | ||
123 | |||
124 | static inline int nf_ct_is_untracked(const struct sk_buff *skb) | ||
125 | { | ||
126 | return (skb->nfct == &nf_conntrack_untracked.ct_general); | ||
127 | } | ||
128 | |||
129 | static inline void nf_ct_untrack(struct sk_buff *skb) | ||
130 | { | ||
131 | skb->nfct = &nf_conntrack_untracked.ct_general; | ||
132 | } | ||
133 | |||
134 | static inline int nf_ct_get_ctinfo(const struct sk_buff *skb, | ||
135 | enum ip_conntrack_info *ctinfo) | ||
136 | { | ||
137 | struct nf_conn *ct = nf_ct_get(skb, ctinfo); | ||
138 | return (ct != NULL); | ||
139 | } | ||
140 | |||
141 | #endif /* CONFIG_IP_NF_CONNTRACK */ | ||
142 | |||
143 | #endif /* __KERNEL__ */ | ||
144 | |||
145 | #endif /* _NF_CONNTRACK_COMPAT_H */ | ||
diff --git a/include/net/netfilter/nf_nat_rule.h b/include/net/netfilter/nf_nat_rule.h index f191c672bcc6..e76565459ad9 100644 --- a/include/net/netfilter/nf_nat_rule.h +++ b/include/net/netfilter/nf_nat_rule.h | |||
@@ -4,16 +4,6 @@ | |||
4 | #include <net/netfilter/nf_nat.h> | 4 | #include <net/netfilter/nf_nat.h> |
5 | #include <linux/netfilter_ipv4/ip_tables.h> | 5 | #include <linux/netfilter_ipv4/ip_tables.h> |
6 | 6 | ||
7 | /* Compatibility definitions for ipt_FOO modules */ | ||
8 | #define ip_nat_range nf_nat_range | ||
9 | #define ip_conntrack_tuple nf_conntrack_tuple | ||
10 | #define ip_conntrack_get nf_ct_get | ||
11 | #define ip_conntrack nf_conn | ||
12 | #define ip_nat_setup_info nf_nat_setup_info | ||
13 | #define ip_nat_multi_range_compat nf_nat_multi_range_compat | ||
14 | #define ip_ct_iterate_cleanup nf_ct_iterate_cleanup | ||
15 | #define IP_NF_ASSERT NF_CT_ASSERT | ||
16 | |||
17 | extern int nf_nat_rule_init(void) __init; | 7 | extern int nf_nat_rule_init(void) __init; |
18 | extern void nf_nat_rule_cleanup(void); | 8 | extern void nf_nat_rule_cleanup(void); |
19 | extern int nf_nat_rule_find(struct sk_buff **pskb, | 9 | extern int nf_nat_rule_find(struct sk_buff **pskb, |
diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig index 601808c796ec..46509fae9fd8 100644 --- a/net/ipv4/netfilter/Kconfig +++ b/net/ipv4/netfilter/Kconfig | |||
@@ -30,188 +30,6 @@ config NF_CONNTRACK_PROC_COMPAT | |||
30 | 30 | ||
31 | If unsure, say Y. | 31 | If unsure, say Y. |
32 | 32 | ||
33 | # connection tracking, helpers and protocols | ||
34 | config IP_NF_CT_ACCT | ||
35 | bool "Connection tracking flow accounting" | ||
36 | depends on IP_NF_CONNTRACK | ||
37 | help | ||
38 | If this option is enabled, the connection tracking code will | ||
39 | keep per-flow packet and byte counters. | ||
40 | |||
41 | Those counters can be used for flow-based accounting or the | ||
42 | `connbytes' match. | ||
43 | |||
44 | If unsure, say `N'. | ||
45 | |||
46 | config IP_NF_CONNTRACK_MARK | ||
47 | bool 'Connection mark tracking support' | ||
48 | depends on IP_NF_CONNTRACK | ||
49 | help | ||
50 | This option enables support for connection marks, used by the | ||
51 | `CONNMARK' target and `connmark' match. Similar to the mark value | ||
52 | of packets, but this mark value is kept in the conntrack session | ||
53 | instead of the individual packets. | ||
54 | |||
55 | config IP_NF_CONNTRACK_SECMARK | ||
56 | bool 'Connection tracking security mark support' | ||
57 | depends on IP_NF_CONNTRACK && NETWORK_SECMARK | ||
58 | help | ||
59 | This option enables security markings to be applied to | ||
60 | connections. Typically they are copied to connections from | ||
61 | packets using the CONNSECMARK target and copied back from | ||
62 | connections to packets with the same target, with the packets | ||
63 | being originally labeled via SECMARK. | ||
64 | |||
65 | If unsure, say 'N'. | ||
66 | |||
67 | config IP_NF_CONNTRACK_EVENTS | ||
68 | bool "Connection tracking events (EXPERIMENTAL)" | ||
69 | depends on EXPERIMENTAL && IP_NF_CONNTRACK | ||
70 | help | ||
71 | If this option is enabled, the connection tracking code will | ||
72 | provide a notifier chain that can be used by other kernel code | ||
73 | to get notified about changes in the connection tracking state. | ||
74 | |||
75 | IF unsure, say `N'. | ||
76 | |||
77 | config IP_NF_CONNTRACK_NETLINK | ||
78 | tristate 'Connection tracking netlink interface (EXPERIMENTAL)' | ||
79 | depends on EXPERIMENTAL && IP_NF_CONNTRACK && NETFILTER_NETLINK | ||
80 | depends on IP_NF_CONNTRACK!=y || NETFILTER_NETLINK!=m | ||
81 | depends on IP_NF_NAT=n || IP_NF_NAT | ||
82 | help | ||
83 | This option enables support for a netlink-based userspace interface | ||
84 | |||
85 | |||
86 | config IP_NF_CT_PROTO_SCTP | ||
87 | tristate 'SCTP protocol connection tracking support (EXPERIMENTAL)' | ||
88 | depends on IP_NF_CONNTRACK && EXPERIMENTAL | ||
89 | help | ||
90 | With this option enabled, the connection tracking code will | ||
91 | be able to do state tracking on SCTP connections. | ||
92 | |||
93 | If you want to compile it as a module, say M here and read | ||
94 | <file:Documentation/modules.txt>. If unsure, say `N'. | ||
95 | |||
96 | config IP_NF_FTP | ||
97 | tristate "FTP protocol support" | ||
98 | depends on IP_NF_CONNTRACK | ||
99 | help | ||
100 | Tracking FTP connections is problematic: special helpers are | ||
101 | required for tracking them, and doing masquerading and other forms | ||
102 | of Network Address Translation on them. | ||
103 | |||
104 | To compile it as a module, choose M here. If unsure, say Y. | ||
105 | |||
106 | config IP_NF_IRC | ||
107 | tristate "IRC protocol support" | ||
108 | depends on IP_NF_CONNTRACK | ||
109 | ---help--- | ||
110 | There is a commonly-used extension to IRC called | ||
111 | Direct Client-to-Client Protocol (DCC). This enables users to send | ||
112 | files to each other, and also chat to each other without the need | ||
113 | of a server. DCC Sending is used anywhere you send files over IRC, | ||
114 | and DCC Chat is most commonly used by Eggdrop bots. If you are | ||
115 | using NAT, this extension will enable you to send files and initiate | ||
116 | chats. Note that you do NOT need this extension to get files or | ||
117 | have others initiate chats, or everything else in IRC. | ||
118 | |||
119 | To compile it as a module, choose M here. If unsure, say Y. | ||
120 | |||
121 | config IP_NF_NETBIOS_NS | ||
122 | tristate "NetBIOS name service protocol support (EXPERIMENTAL)" | ||
123 | depends on IP_NF_CONNTRACK && EXPERIMENTAL | ||
124 | help | ||
125 | NetBIOS name service requests are sent as broadcast messages from an | ||
126 | unprivileged port and responded to with unicast messages to the | ||
127 | same port. This make them hard to firewall properly because connection | ||
128 | tracking doesn't deal with broadcasts. This helper tracks locally | ||
129 | originating NetBIOS name service requests and the corresponding | ||
130 | responses. It relies on correct IP address configuration, specifically | ||
131 | netmask and broadcast address. When properly configured, the output | ||
132 | of "ip address show" should look similar to this: | ||
133 | |||
134 | $ ip -4 address show eth0 | ||
135 | 4: eth0: <BROADCAST,MULTICAST,UP> mtu 1500 qdisc pfifo_fast qlen 1000 | ||
136 | inet 172.16.2.252/24 brd 172.16.2.255 scope global eth0 | ||
137 | |||
138 | To compile it as a module, choose M here. If unsure, say N. | ||
139 | |||
140 | config IP_NF_TFTP | ||
141 | tristate "TFTP protocol support" | ||
142 | depends on IP_NF_CONNTRACK | ||
143 | help | ||
144 | TFTP connection tracking helper, this is required depending | ||
145 | on how restrictive your ruleset is. | ||
146 | If you are using a tftp client behind -j SNAT or -j MASQUERADING | ||
147 | you will need this. | ||
148 | |||
149 | To compile it as a module, choose M here. If unsure, say Y. | ||
150 | |||
151 | config IP_NF_AMANDA | ||
152 | tristate "Amanda backup protocol support" | ||
153 | depends on IP_NF_CONNTRACK | ||
154 | select TEXTSEARCH | ||
155 | select TEXTSEARCH_KMP | ||
156 | help | ||
157 | If you are running the Amanda backup package <http://www.amanda.org/> | ||
158 | on this machine or machines that will be MASQUERADED through this | ||
159 | machine, then you may want to enable this feature. This allows the | ||
160 | connection tracking and natting code to allow the sub-channels that | ||
161 | Amanda requires for communication of the backup data, messages and | ||
162 | index. | ||
163 | |||
164 | To compile it as a module, choose M here. If unsure, say Y. | ||
165 | |||
166 | config IP_NF_PPTP | ||
167 | tristate 'PPTP protocol support' | ||
168 | depends on IP_NF_CONNTRACK | ||
169 | help | ||
170 | This module adds support for PPTP (Point to Point Tunnelling | ||
171 | Protocol, RFC2637) connection tracking and NAT. | ||
172 | |||
173 | If you are running PPTP sessions over a stateful firewall or NAT | ||
174 | box, you may want to enable this feature. | ||
175 | |||
176 | Please note that not all PPTP modes of operation are supported yet. | ||
177 | For more info, read top of the file | ||
178 | net/ipv4/netfilter/ip_conntrack_pptp.c | ||
179 | |||
180 | If you want to compile it as a module, say M here and read | ||
181 | Documentation/modules.txt. If unsure, say `N'. | ||
182 | |||
183 | config IP_NF_H323 | ||
184 | tristate 'H.323 protocol support (EXPERIMENTAL)' | ||
185 | depends on IP_NF_CONNTRACK && EXPERIMENTAL | ||
186 | help | ||
187 | H.323 is a VoIP signalling protocol from ITU-T. As one of the most | ||
188 | important VoIP protocols, it is widely used by voice hardware and | ||
189 | software including voice gateways, IP phones, Netmeeting, OpenPhone, | ||
190 | Gnomemeeting, etc. | ||
191 | |||
192 | With this module you can support H.323 on a connection tracking/NAT | ||
193 | firewall. | ||
194 | |||
195 | This module supports RAS, Fast Start, H.245 Tunnelling, Call | ||
196 | Forwarding, RTP/RTCP and T.120 based audio, video, fax, chat, | ||
197 | whiteboard, file transfer, etc. For more information, please | ||
198 | visit http://nath323.sourceforge.net/. | ||
199 | |||
200 | If you want to compile it as a module, say 'M' here and read | ||
201 | Documentation/modules.txt. If unsure, say 'N'. | ||
202 | |||
203 | config IP_NF_SIP | ||
204 | tristate "SIP protocol support (EXPERIMENTAL)" | ||
205 | depends on IP_NF_CONNTRACK && EXPERIMENTAL | ||
206 | help | ||
207 | SIP is an application-layer control protocol that can establish, | ||
208 | modify, and terminate multimedia sessions (conferences) such as | ||
209 | Internet telephony calls. With the ip_conntrack_sip and | ||
210 | the ip_nat_sip modules you can support the protocol on a connection | ||
211 | tracking/NATing firewall. | ||
212 | |||
213 | To compile it as a module, choose M here. If unsure, say Y. | ||
214 | |||
215 | config IP_NF_QUEUE | 33 | config IP_NF_QUEUE |
216 | tristate "IP Userspace queueing via NETLINK (OBSOLETE)" | 34 | tristate "IP Userspace queueing via NETLINK (OBSOLETE)" |
217 | help | 35 | help |
@@ -361,17 +179,6 @@ config IP_NF_TARGET_ULOG | |||
361 | 179 | ||
362 | To compile it as a module, choose M here. If unsure, say N. | 180 | To compile it as a module, choose M here. If unsure, say N. |
363 | 181 | ||
364 | # NAT + specific targets: ip_conntrack | ||
365 | config IP_NF_NAT | ||
366 | tristate "Full NAT" | ||
367 | depends on IP_NF_IPTABLES && IP_NF_CONNTRACK | ||
368 | help | ||
369 | The Full NAT option allows masquerading, port forwarding and other | ||
370 | forms of full Network Address Port Translation. It is controlled by | ||
371 | the `nat' table in iptables: see the man page for iptables(8). | ||
372 | |||
373 | To compile it as a module, choose M here. If unsure, say N. | ||
374 | |||
375 | # NAT + specific targets: nf_conntrack | 182 | # NAT + specific targets: nf_conntrack |
376 | config NF_NAT | 183 | config NF_NAT |
377 | tristate "Full NAT" | 184 | tristate "Full NAT" |
@@ -383,11 +190,6 @@ config NF_NAT | |||
383 | 190 | ||
384 | To compile it as a module, choose M here. If unsure, say N. | 191 | To compile it as a module, choose M here. If unsure, say N. |
385 | 192 | ||
386 | config IP_NF_NAT_NEEDED | ||
387 | bool | ||
388 | depends on IP_NF_NAT | ||
389 | default y | ||
390 | |||
391 | config NF_NAT_NEEDED | 193 | config NF_NAT_NEEDED |
392 | bool | 194 | bool |
393 | depends on NF_NAT | 195 | depends on NF_NAT |
@@ -395,7 +197,7 @@ config NF_NAT_NEEDED | |||
395 | 197 | ||
396 | config IP_NF_TARGET_MASQUERADE | 198 | config IP_NF_TARGET_MASQUERADE |
397 | tristate "MASQUERADE target support" | 199 | tristate "MASQUERADE target support" |
398 | depends on (NF_NAT || IP_NF_NAT) | 200 | depends on NF_NAT |
399 | help | 201 | help |
400 | Masquerading is a special case of NAT: all outgoing connections are | 202 | Masquerading is a special case of NAT: all outgoing connections are |
401 | changed to seem to come from a particular interface's address, and | 203 | changed to seem to come from a particular interface's address, and |
@@ -407,7 +209,7 @@ config IP_NF_TARGET_MASQUERADE | |||
407 | 209 | ||
408 | config IP_NF_TARGET_REDIRECT | 210 | config IP_NF_TARGET_REDIRECT |
409 | tristate "REDIRECT target support" | 211 | tristate "REDIRECT target support" |
410 | depends on (NF_NAT || IP_NF_NAT) | 212 | depends on NF_NAT |
411 | help | 213 | help |
412 | REDIRECT is a special case of NAT: all incoming connections are | 214 | REDIRECT is a special case of NAT: all incoming connections are |
413 | mapped onto the incoming interface's address, causing the packets to | 215 | mapped onto the incoming interface's address, causing the packets to |
@@ -418,7 +220,7 @@ config IP_NF_TARGET_REDIRECT | |||
418 | 220 | ||
419 | config IP_NF_TARGET_NETMAP | 221 | config IP_NF_TARGET_NETMAP |
420 | tristate "NETMAP target support" | 222 | tristate "NETMAP target support" |
421 | depends on (NF_NAT || IP_NF_NAT) | 223 | depends on NF_NAT |
422 | help | 224 | help |
423 | NETMAP is an implementation of static 1:1 NAT mapping of network | 225 | NETMAP is an implementation of static 1:1 NAT mapping of network |
424 | addresses. It maps the network address part, while keeping the host | 226 | addresses. It maps the network address part, while keeping the host |
@@ -429,28 +231,13 @@ config IP_NF_TARGET_NETMAP | |||
429 | 231 | ||
430 | config IP_NF_TARGET_SAME | 232 | config IP_NF_TARGET_SAME |
431 | tristate "SAME target support" | 233 | tristate "SAME target support" |
432 | depends on (NF_NAT || IP_NF_NAT) | 234 | depends on NF_NAT |
433 | help | 235 | help |
434 | This option adds a `SAME' target, which works like the standard SNAT | 236 | This option adds a `SAME' target, which works like the standard SNAT |
435 | target, but attempts to give clients the same IP for all connections. | 237 | target, but attempts to give clients the same IP for all connections. |
436 | 238 | ||
437 | To compile it as a module, choose M here. If unsure, say N. | 239 | To compile it as a module, choose M here. If unsure, say N. |
438 | 240 | ||
439 | config IP_NF_NAT_SNMP_BASIC | ||
440 | tristate "Basic SNMP-ALG support (EXPERIMENTAL)" | ||
441 | depends on EXPERIMENTAL && IP_NF_NAT | ||
442 | ---help--- | ||
443 | |||
444 | This module implements an Application Layer Gateway (ALG) for | ||
445 | SNMP payloads. In conjunction with NAT, it allows a network | ||
446 | management system to access multiple private networks with | ||
447 | conflicting addresses. It works by modifying IP addresses | ||
448 | inside SNMP payloads to match IP-layer NAT mapping. | ||
449 | |||
450 | This is the "basic" form of SNMP-ALG, as described in RFC 2962 | ||
451 | |||
452 | To compile it as a module, choose M here. If unsure, say N. | ||
453 | |||
454 | config NF_NAT_SNMP_BASIC | 241 | config NF_NAT_SNMP_BASIC |
455 | tristate "Basic SNMP-ALG support (EXPERIMENTAL)" | 242 | tristate "Basic SNMP-ALG support (EXPERIMENTAL)" |
456 | depends on EXPERIMENTAL && NF_NAT | 243 | depends on EXPERIMENTAL && NF_NAT |
@@ -477,78 +264,37 @@ config NF_NAT_PROTO_GRE | |||
477 | tristate | 264 | tristate |
478 | depends on NF_NAT && NF_CT_PROTO_GRE | 265 | depends on NF_NAT && NF_CT_PROTO_GRE |
479 | 266 | ||
480 | config IP_NF_NAT_FTP | ||
481 | tristate | ||
482 | depends on IP_NF_IPTABLES && IP_NF_CONNTRACK && IP_NF_NAT | ||
483 | default IP_NF_NAT && IP_NF_FTP | ||
484 | |||
485 | config NF_NAT_FTP | 267 | config NF_NAT_FTP |
486 | tristate | 268 | tristate |
487 | depends on IP_NF_IPTABLES && NF_CONNTRACK && NF_NAT | 269 | depends on IP_NF_IPTABLES && NF_CONNTRACK && NF_NAT |
488 | default NF_NAT && NF_CONNTRACK_FTP | 270 | default NF_NAT && NF_CONNTRACK_FTP |
489 | 271 | ||
490 | config IP_NF_NAT_IRC | ||
491 | tristate | ||
492 | depends on IP_NF_IPTABLES!=n && IP_NF_CONNTRACK!=n && IP_NF_NAT!=n | ||
493 | default IP_NF_NAT if IP_NF_IRC=y | ||
494 | default m if IP_NF_IRC=m | ||
495 | |||
496 | config NF_NAT_IRC | 272 | config NF_NAT_IRC |
497 | tristate | 273 | tristate |
498 | depends on IP_NF_IPTABLES && NF_CONNTRACK && NF_NAT | 274 | depends on IP_NF_IPTABLES && NF_CONNTRACK && NF_NAT |
499 | default NF_NAT && NF_CONNTRACK_IRC | 275 | default NF_NAT && NF_CONNTRACK_IRC |
500 | 276 | ||
501 | config IP_NF_NAT_TFTP | ||
502 | tristate | ||
503 | depends on IP_NF_IPTABLES!=n && IP_NF_CONNTRACK!=n && IP_NF_NAT!=n | ||
504 | default IP_NF_NAT if IP_NF_TFTP=y | ||
505 | default m if IP_NF_TFTP=m | ||
506 | |||
507 | config NF_NAT_TFTP | 277 | config NF_NAT_TFTP |
508 | tristate | 278 | tristate |
509 | depends on IP_NF_IPTABLES && NF_CONNTRACK && NF_NAT | 279 | depends on IP_NF_IPTABLES && NF_CONNTRACK && NF_NAT |
510 | default NF_NAT && NF_CONNTRACK_TFTP | 280 | default NF_NAT && NF_CONNTRACK_TFTP |
511 | 281 | ||
512 | config IP_NF_NAT_AMANDA | ||
513 | tristate | ||
514 | depends on IP_NF_IPTABLES!=n && IP_NF_CONNTRACK!=n && IP_NF_NAT!=n | ||
515 | default IP_NF_NAT if IP_NF_AMANDA=y | ||
516 | default m if IP_NF_AMANDA=m | ||
517 | |||
518 | config NF_NAT_AMANDA | 282 | config NF_NAT_AMANDA |
519 | tristate | 283 | tristate |
520 | depends on IP_NF_IPTABLES && NF_CONNTRACK && NF_NAT | 284 | depends on IP_NF_IPTABLES && NF_CONNTRACK && NF_NAT |
521 | default NF_NAT && NF_CONNTRACK_AMANDA | 285 | default NF_NAT && NF_CONNTRACK_AMANDA |
522 | 286 | ||
523 | config IP_NF_NAT_PPTP | ||
524 | tristate | ||
525 | depends on IP_NF_NAT!=n && IP_NF_PPTP!=n | ||
526 | default IP_NF_NAT if IP_NF_PPTP=y | ||
527 | default m if IP_NF_PPTP=m | ||
528 | |||
529 | config NF_NAT_PPTP | 287 | config NF_NAT_PPTP |
530 | tristate | 288 | tristate |
531 | depends on IP_NF_IPTABLES && NF_CONNTRACK && NF_NAT | 289 | depends on IP_NF_IPTABLES && NF_CONNTRACK && NF_NAT |
532 | default NF_NAT && NF_CONNTRACK_PPTP | 290 | default NF_NAT && NF_CONNTRACK_PPTP |
533 | select NF_NAT_PROTO_GRE | 291 | select NF_NAT_PROTO_GRE |
534 | 292 | ||
535 | config IP_NF_NAT_H323 | ||
536 | tristate | ||
537 | depends on IP_NF_IPTABLES!=n && IP_NF_CONNTRACK!=n && IP_NF_NAT!=n | ||
538 | default IP_NF_NAT if IP_NF_H323=y | ||
539 | default m if IP_NF_H323=m | ||
540 | |||
541 | config NF_NAT_H323 | 293 | config NF_NAT_H323 |
542 | tristate | 294 | tristate |
543 | depends on IP_NF_IPTABLES && NF_CONNTRACK && NF_NAT | 295 | depends on IP_NF_IPTABLES && NF_CONNTRACK && NF_NAT |
544 | default NF_NAT && NF_CONNTRACK_H323 | 296 | default NF_NAT && NF_CONNTRACK_H323 |
545 | 297 | ||
546 | config IP_NF_NAT_SIP | ||
547 | tristate | ||
548 | depends on IP_NF_IPTABLES!=n && IP_NF_CONNTRACK!=n && IP_NF_NAT!=n | ||
549 | default IP_NF_NAT if IP_NF_SIP=y | ||
550 | default m if IP_NF_SIP=m | ||
551 | |||
552 | config NF_NAT_SIP | 298 | config NF_NAT_SIP |
553 | tristate | 299 | tristate |
554 | depends on IP_NF_IPTABLES && NF_CONNTRACK && NF_NAT | 300 | depends on IP_NF_IPTABLES && NF_CONNTRACK && NF_NAT |
@@ -606,9 +352,8 @@ config IP_NF_TARGET_TTL | |||
606 | config IP_NF_TARGET_CLUSTERIP | 352 | config IP_NF_TARGET_CLUSTERIP |
607 | tristate "CLUSTERIP target support (EXPERIMENTAL)" | 353 | tristate "CLUSTERIP target support (EXPERIMENTAL)" |
608 | depends on IP_NF_MANGLE && EXPERIMENTAL | 354 | depends on IP_NF_MANGLE && EXPERIMENTAL |
609 | depends on IP_NF_CONNTRACK || NF_CONNTRACK_IPV4 | 355 | depends on NF_CONNTRACK_IPV4 |
610 | select IP_NF_CONNTRACK_MARK if IP_NF_CONNTRACK | 356 | select NF_CONNTRACK_MARK |
611 | select NF_CONNTRACK_MARK if NF_CONNTRACK_IPV4 | ||
612 | help | 357 | help |
613 | The CLUSTERIP target allows you to build load-balancing clusters of | 358 | The CLUSTERIP target allows you to build load-balancing clusters of |
614 | network servers without having a dedicated load-balancing | 359 | network servers without having a dedicated load-balancing |
diff --git a/net/ipv4/netfilter/Makefile b/net/ipv4/netfilter/Makefile index 6625ec68180c..409d273f6f82 100644 --- a/net/ipv4/netfilter/Makefile +++ b/net/ipv4/netfilter/Makefile | |||
@@ -2,8 +2,6 @@ | |||
2 | # Makefile for the netfilter modules on top of IPv4. | 2 | # Makefile for the netfilter modules on top of IPv4. |
3 | # | 3 | # |
4 | 4 | ||
5 | # objects for the standalone - connection tracking / NAT | ||
6 | ip_conntrack-objs := ip_conntrack_standalone.o ip_conntrack_core.o ip_conntrack_proto_generic.o ip_conntrack_proto_tcp.o ip_conntrack_proto_udp.o ip_conntrack_proto_icmp.o | ||
7 | # objects for l3 independent conntrack | 5 | # objects for l3 independent conntrack |
8 | nf_conntrack_ipv4-objs := nf_conntrack_l3proto_ipv4.o nf_conntrack_proto_icmp.o | 6 | nf_conntrack_ipv4-objs := nf_conntrack_l3proto_ipv4.o nf_conntrack_proto_icmp.o |
9 | ifeq ($(CONFIG_NF_CONNTRACK_PROC_COMPAT),y) | 7 | ifeq ($(CONFIG_NF_CONNTRACK_PROC_COMPAT),y) |
@@ -12,53 +10,14 @@ nf_conntrack_ipv4-objs += nf_conntrack_l3proto_ipv4_compat.o | |||
12 | endif | 10 | endif |
13 | endif | 11 | endif |
14 | 12 | ||
15 | ip_nat-objs := ip_nat_core.o ip_nat_helper.o ip_nat_proto_unknown.o ip_nat_proto_tcp.o ip_nat_proto_udp.o ip_nat_proto_icmp.o | 13 | nf_nat-objs := nf_nat_core.o nf_nat_helper.o nf_nat_proto_unknown.o nf_nat_proto_tcp.o nf_nat_proto_udp.o nf_nat_proto_icmp.o |
16 | nf_nat-objs := nf_nat_core.o nf_nat_helper.o nf_nat_proto_unknown.o nf_nat_proto_tcp.o nf_nat_proto_udp.o nf_nat_proto_icmp.o | ||
17 | ifneq ($(CONFIG_NF_NAT),) | ||
18 | iptable_nat-objs := nf_nat_rule.o nf_nat_standalone.o | 14 | iptable_nat-objs := nf_nat_rule.o nf_nat_standalone.o |
19 | else | ||
20 | iptable_nat-objs := ip_nat_rule.o ip_nat_standalone.o | ||
21 | endif | ||
22 | |||
23 | ip_conntrack_pptp-objs := ip_conntrack_helper_pptp.o ip_conntrack_proto_gre.o | ||
24 | ip_nat_pptp-objs := ip_nat_helper_pptp.o ip_nat_proto_gre.o | ||
25 | |||
26 | ip_conntrack_h323-objs := ip_conntrack_helper_h323.o ../../netfilter/nf_conntrack_h323_asn1.o | ||
27 | ip_nat_h323-objs := ip_nat_helper_h323.o | ||
28 | 15 | ||
29 | # connection tracking | 16 | # connection tracking |
30 | obj-$(CONFIG_IP_NF_CONNTRACK) += ip_conntrack.o | ||
31 | obj-$(CONFIG_NF_CONNTRACK_IPV4) += nf_conntrack_ipv4.o | 17 | obj-$(CONFIG_NF_CONNTRACK_IPV4) += nf_conntrack_ipv4.o |
32 | 18 | ||
33 | obj-$(CONFIG_IP_NF_NAT) += ip_nat.o | ||
34 | obj-$(CONFIG_NF_NAT) += nf_nat.o | 19 | obj-$(CONFIG_NF_NAT) += nf_nat.o |
35 | 20 | ||
36 | # conntrack netlink interface | ||
37 | obj-$(CONFIG_IP_NF_CONNTRACK_NETLINK) += ip_conntrack_netlink.o | ||
38 | |||
39 | |||
40 | # SCTP protocol connection tracking | ||
41 | obj-$(CONFIG_IP_NF_CT_PROTO_SCTP) += ip_conntrack_proto_sctp.o | ||
42 | |||
43 | # connection tracking helpers | ||
44 | obj-$(CONFIG_IP_NF_H323) += ip_conntrack_h323.o | ||
45 | obj-$(CONFIG_IP_NF_PPTP) += ip_conntrack_pptp.o | ||
46 | obj-$(CONFIG_IP_NF_AMANDA) += ip_conntrack_amanda.o | ||
47 | obj-$(CONFIG_IP_NF_TFTP) += ip_conntrack_tftp.o | ||
48 | obj-$(CONFIG_IP_NF_FTP) += ip_conntrack_ftp.o | ||
49 | obj-$(CONFIG_IP_NF_IRC) += ip_conntrack_irc.o | ||
50 | obj-$(CONFIG_IP_NF_SIP) += ip_conntrack_sip.o | ||
51 | obj-$(CONFIG_IP_NF_NETBIOS_NS) += ip_conntrack_netbios_ns.o | ||
52 | |||
53 | # NAT helpers (ip_conntrack) | ||
54 | obj-$(CONFIG_IP_NF_NAT_H323) += ip_nat_h323.o | ||
55 | obj-$(CONFIG_IP_NF_NAT_PPTP) += ip_nat_pptp.o | ||
56 | obj-$(CONFIG_IP_NF_NAT_AMANDA) += ip_nat_amanda.o | ||
57 | obj-$(CONFIG_IP_NF_NAT_TFTP) += ip_nat_tftp.o | ||
58 | obj-$(CONFIG_IP_NF_NAT_FTP) += ip_nat_ftp.o | ||
59 | obj-$(CONFIG_IP_NF_NAT_IRC) += ip_nat_irc.o | ||
60 | obj-$(CONFIG_IP_NF_NAT_SIP) += ip_nat_sip.o | ||
61 | |||
62 | # NAT helpers (nf_conntrack) | 21 | # NAT helpers (nf_conntrack) |
63 | obj-$(CONFIG_NF_NAT_AMANDA) += nf_nat_amanda.o | 22 | obj-$(CONFIG_NF_NAT_AMANDA) += nf_nat_amanda.o |
64 | obj-$(CONFIG_NF_NAT_FTP) += nf_nat_ftp.o | 23 | obj-$(CONFIG_NF_NAT_FTP) += nf_nat_ftp.o |
@@ -78,7 +37,6 @@ obj-$(CONFIG_IP_NF_IPTABLES) += ip_tables.o | |||
78 | # the three instances of ip_tables | 37 | # the three instances of ip_tables |
79 | obj-$(CONFIG_IP_NF_FILTER) += iptable_filter.o | 38 | obj-$(CONFIG_IP_NF_FILTER) += iptable_filter.o |
80 | obj-$(CONFIG_IP_NF_MANGLE) += iptable_mangle.o | 39 | obj-$(CONFIG_IP_NF_MANGLE) += iptable_mangle.o |
81 | obj-$(CONFIG_IP_NF_NAT) += iptable_nat.o | ||
82 | obj-$(CONFIG_NF_NAT) += iptable_nat.o | 40 | obj-$(CONFIG_NF_NAT) += iptable_nat.o |
83 | obj-$(CONFIG_IP_NF_RAW) += iptable_raw.o | 41 | obj-$(CONFIG_IP_NF_RAW) += iptable_raw.o |
84 | 42 | ||
@@ -100,7 +58,6 @@ obj-$(CONFIG_IP_NF_TARGET_MASQUERADE) += ipt_MASQUERADE.o | |||
100 | obj-$(CONFIG_IP_NF_TARGET_REDIRECT) += ipt_REDIRECT.o | 58 | obj-$(CONFIG_IP_NF_TARGET_REDIRECT) += ipt_REDIRECT.o |
101 | obj-$(CONFIG_IP_NF_TARGET_NETMAP) += ipt_NETMAP.o | 59 | obj-$(CONFIG_IP_NF_TARGET_NETMAP) += ipt_NETMAP.o |
102 | obj-$(CONFIG_IP_NF_TARGET_SAME) += ipt_SAME.o | 60 | obj-$(CONFIG_IP_NF_TARGET_SAME) += ipt_SAME.o |
103 | obj-$(CONFIG_IP_NF_NAT_SNMP_BASIC) += ip_nat_snmp_basic.o | ||
104 | obj-$(CONFIG_IP_NF_TARGET_LOG) += ipt_LOG.o | 61 | obj-$(CONFIG_IP_NF_TARGET_LOG) += ipt_LOG.o |
105 | obj-$(CONFIG_IP_NF_TARGET_ULOG) += ipt_ULOG.o | 62 | obj-$(CONFIG_IP_NF_TARGET_ULOG) += ipt_ULOG.o |
106 | obj-$(CONFIG_IP_NF_TARGET_CLUSTERIP) += ipt_CLUSTERIP.o | 63 | obj-$(CONFIG_IP_NF_TARGET_CLUSTERIP) += ipt_CLUSTERIP.o |
diff --git a/net/ipv4/netfilter/ip_conntrack_amanda.c b/net/ipv4/netfilter/ip_conntrack_amanda.c deleted file mode 100644 index c40762c67d0e..000000000000 --- a/net/ipv4/netfilter/ip_conntrack_amanda.c +++ /dev/null | |||
@@ -1,229 +0,0 @@ | |||
1 | /* Amanda extension for IP connection tracking, Version 0.2 | ||
2 | * (C) 2002 by Brian J. Murrell <netfilter@interlinx.bc.ca> | ||
3 | * based on HW's ip_conntrack_irc.c as well as other modules | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or | ||
6 | * modify it under the terms of the GNU General Public License | ||
7 | * as published by the Free Software Foundation; either version | ||
8 | * 2 of the License, or (at your option) any later version. | ||
9 | * | ||
10 | * Module load syntax: | ||
11 | * insmod ip_conntrack_amanda.o [master_timeout=n] | ||
12 | * | ||
13 | * Where master_timeout is the timeout (in seconds) of the master | ||
14 | * connection (port 10080). This defaults to 5 minutes but if | ||
15 | * your clients take longer than 5 minutes to do their work | ||
16 | * before getting back to the Amanda server, you can increase | ||
17 | * this value. | ||
18 | * | ||
19 | */ | ||
20 | #include <linux/kernel.h> | ||
21 | #include <linux/module.h> | ||
22 | #include <linux/moduleparam.h> | ||
23 | #include <linux/textsearch.h> | ||
24 | #include <linux/skbuff.h> | ||
25 | #include <linux/in.h> | ||
26 | #include <linux/ip.h> | ||
27 | #include <linux/udp.h> | ||
28 | |||
29 | #include <linux/netfilter.h> | ||
30 | #include <linux/netfilter_ipv4/ip_conntrack_helper.h> | ||
31 | #include <linux/netfilter_ipv4/ip_conntrack_amanda.h> | ||
32 | |||
33 | static unsigned int master_timeout = 300; | ||
34 | static char *ts_algo = "kmp"; | ||
35 | |||
36 | MODULE_AUTHOR("Brian J. Murrell <netfilter@interlinx.bc.ca>"); | ||
37 | MODULE_DESCRIPTION("Amanda connection tracking module"); | ||
38 | MODULE_LICENSE("GPL"); | ||
39 | module_param(master_timeout, uint, 0600); | ||
40 | MODULE_PARM_DESC(master_timeout, "timeout for the master connection"); | ||
41 | module_param(ts_algo, charp, 0400); | ||
42 | MODULE_PARM_DESC(ts_algo, "textsearch algorithm to use (default kmp)"); | ||
43 | |||
44 | unsigned int (*ip_nat_amanda_hook)(struct sk_buff **pskb, | ||
45 | enum ip_conntrack_info ctinfo, | ||
46 | unsigned int matchoff, | ||
47 | unsigned int matchlen, | ||
48 | struct ip_conntrack_expect *exp); | ||
49 | EXPORT_SYMBOL_GPL(ip_nat_amanda_hook); | ||
50 | |||
51 | enum amanda_strings { | ||
52 | SEARCH_CONNECT, | ||
53 | SEARCH_NEWLINE, | ||
54 | SEARCH_DATA, | ||
55 | SEARCH_MESG, | ||
56 | SEARCH_INDEX, | ||
57 | }; | ||
58 | |||
59 | static struct { | ||
60 | char *string; | ||
61 | size_t len; | ||
62 | struct ts_config *ts; | ||
63 | } search[] = { | ||
64 | [SEARCH_CONNECT] = { | ||
65 | .string = "CONNECT ", | ||
66 | .len = 8, | ||
67 | }, | ||
68 | [SEARCH_NEWLINE] = { | ||
69 | .string = "\n", | ||
70 | .len = 1, | ||
71 | }, | ||
72 | [SEARCH_DATA] = { | ||
73 | .string = "DATA ", | ||
74 | .len = 5, | ||
75 | }, | ||
76 | [SEARCH_MESG] = { | ||
77 | .string = "MESG ", | ||
78 | .len = 5, | ||
79 | }, | ||
80 | [SEARCH_INDEX] = { | ||
81 | .string = "INDEX ", | ||
82 | .len = 6, | ||
83 | }, | ||
84 | }; | ||
85 | |||
86 | static int help(struct sk_buff **pskb, | ||
87 | struct ip_conntrack *ct, enum ip_conntrack_info ctinfo) | ||
88 | { | ||
89 | struct ts_state ts; | ||
90 | struct ip_conntrack_expect *exp; | ||
91 | unsigned int dataoff, start, stop, off, i; | ||
92 | char pbuf[sizeof("65535")], *tmp; | ||
93 | u_int16_t port, len; | ||
94 | int ret = NF_ACCEPT; | ||
95 | typeof(ip_nat_amanda_hook) ip_nat_amanda; | ||
96 | |||
97 | /* Only look at packets from the Amanda server */ | ||
98 | if (CTINFO2DIR(ctinfo) == IP_CT_DIR_ORIGINAL) | ||
99 | return NF_ACCEPT; | ||
100 | |||
101 | /* increase the UDP timeout of the master connection as replies from | ||
102 | * Amanda clients to the server can be quite delayed */ | ||
103 | ip_ct_refresh(ct, *pskb, master_timeout * HZ); | ||
104 | |||
105 | /* No data? */ | ||
106 | dataoff = ip_hdrlen(*pskb) + sizeof(struct udphdr); | ||
107 | if (dataoff >= (*pskb)->len) { | ||
108 | if (net_ratelimit()) | ||
109 | printk("amanda_help: skblen = %u\n", (*pskb)->len); | ||
110 | return NF_ACCEPT; | ||
111 | } | ||
112 | |||
113 | memset(&ts, 0, sizeof(ts)); | ||
114 | start = skb_find_text(*pskb, dataoff, (*pskb)->len, | ||
115 | search[SEARCH_CONNECT].ts, &ts); | ||
116 | if (start == UINT_MAX) | ||
117 | goto out; | ||
118 | start += dataoff + search[SEARCH_CONNECT].len; | ||
119 | |||
120 | memset(&ts, 0, sizeof(ts)); | ||
121 | stop = skb_find_text(*pskb, start, (*pskb)->len, | ||
122 | search[SEARCH_NEWLINE].ts, &ts); | ||
123 | if (stop == UINT_MAX) | ||
124 | goto out; | ||
125 | stop += start; | ||
126 | |||
127 | for (i = SEARCH_DATA; i <= SEARCH_INDEX; i++) { | ||
128 | memset(&ts, 0, sizeof(ts)); | ||
129 | off = skb_find_text(*pskb, start, stop, search[i].ts, &ts); | ||
130 | if (off == UINT_MAX) | ||
131 | continue; | ||
132 | off += start + search[i].len; | ||
133 | |||
134 | len = min_t(unsigned int, sizeof(pbuf) - 1, stop - off); | ||
135 | if (skb_copy_bits(*pskb, off, pbuf, len)) | ||
136 | break; | ||
137 | pbuf[len] = '\0'; | ||
138 | |||
139 | port = simple_strtoul(pbuf, &tmp, 10); | ||
140 | len = tmp - pbuf; | ||
141 | if (port == 0 || len > 5) | ||
142 | break; | ||
143 | |||
144 | exp = ip_conntrack_expect_alloc(ct); | ||
145 | if (exp == NULL) { | ||
146 | ret = NF_DROP; | ||
147 | goto out; | ||
148 | } | ||
149 | |||
150 | exp->expectfn = NULL; | ||
151 | exp->flags = 0; | ||
152 | |||
153 | exp->tuple.src.ip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip; | ||
154 | exp->tuple.src.u.tcp.port = 0; | ||
155 | exp->tuple.dst.ip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip; | ||
156 | exp->tuple.dst.protonum = IPPROTO_TCP; | ||
157 | exp->tuple.dst.u.tcp.port = htons(port); | ||
158 | |||
159 | exp->mask.src.ip = htonl(0xFFFFFFFF); | ||
160 | exp->mask.src.u.tcp.port = 0; | ||
161 | exp->mask.dst.ip = htonl(0xFFFFFFFF); | ||
162 | exp->mask.dst.protonum = 0xFF; | ||
163 | exp->mask.dst.u.tcp.port = htons(0xFFFF); | ||
164 | |||
165 | /* RCU read locked by nf_hook_slow */ | ||
166 | ip_nat_amanda = rcu_dereference(ip_nat_amanda_hook); | ||
167 | if (ip_nat_amanda) | ||
168 | ret = ip_nat_amanda(pskb, ctinfo, off - dataoff, | ||
169 | len, exp); | ||
170 | else if (ip_conntrack_expect_related(exp) != 0) | ||
171 | ret = NF_DROP; | ||
172 | ip_conntrack_expect_put(exp); | ||
173 | } | ||
174 | |||
175 | out: | ||
176 | return ret; | ||
177 | } | ||
178 | |||
179 | static struct ip_conntrack_helper amanda_helper = { | ||
180 | .max_expected = 3, | ||
181 | .timeout = 180, | ||
182 | .me = THIS_MODULE, | ||
183 | .help = help, | ||
184 | .name = "amanda", | ||
185 | |||
186 | .tuple = { .src = { .u = { .udp = {.port = __constant_htons(10080) } } }, | ||
187 | .dst = { .protonum = IPPROTO_UDP }, | ||
188 | }, | ||
189 | .mask = { .src = { .u = { 0xFFFF } }, | ||
190 | .dst = { .protonum = 0xFF }, | ||
191 | }, | ||
192 | }; | ||
193 | |||
194 | static void __exit ip_conntrack_amanda_fini(void) | ||
195 | { | ||
196 | int i; | ||
197 | |||
198 | ip_conntrack_helper_unregister(&amanda_helper); | ||
199 | for (i = 0; i < ARRAY_SIZE(search); i++) | ||
200 | textsearch_destroy(search[i].ts); | ||
201 | } | ||
202 | |||
203 | static int __init ip_conntrack_amanda_init(void) | ||
204 | { | ||
205 | int ret, i; | ||
206 | |||
207 | ret = -ENOMEM; | ||
208 | for (i = 0; i < ARRAY_SIZE(search); i++) { | ||
209 | search[i].ts = textsearch_prepare(ts_algo, search[i].string, | ||
210 | search[i].len, | ||
211 | GFP_KERNEL, TS_AUTOLOAD); | ||
212 | if (search[i].ts == NULL) | ||
213 | goto err; | ||
214 | } | ||
215 | ret = ip_conntrack_helper_register(&amanda_helper); | ||
216 | if (ret < 0) | ||
217 | goto err; | ||
218 | return 0; | ||
219 | |||
220 | err: | ||
221 | for (; i >= 0; i--) { | ||
222 | if (search[i].ts) | ||
223 | textsearch_destroy(search[i].ts); | ||
224 | } | ||
225 | return ret; | ||
226 | } | ||
227 | |||
228 | module_init(ip_conntrack_amanda_init); | ||
229 | module_exit(ip_conntrack_amanda_fini); | ||
diff --git a/net/ipv4/netfilter/ip_conntrack_core.c b/net/ipv4/netfilter/ip_conntrack_core.c deleted file mode 100644 index 986c0c81294f..000000000000 --- a/net/ipv4/netfilter/ip_conntrack_core.c +++ /dev/null | |||
@@ -1,1549 +0,0 @@ | |||
1 | /* Connection state tracking for netfilter. This is separated from, | ||
2 | but required by, the NAT layer; it can also be used by an iptables | ||
3 | extension. */ | ||
4 | |||
5 | /* (C) 1999-2001 Paul `Rusty' Russell | ||
6 | * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | * | ||
12 | * 23 Apr 2001: Harald Welte <laforge@gnumonks.org> | ||
13 | * - new API and handling of conntrack/nat helpers | ||
14 | * - now capable of multiple expectations for one master | ||
15 | * 16 Jul 2002: Harald Welte <laforge@gnumonks.org> | ||
16 | * - add usage/reference counts to ip_conntrack_expect | ||
17 | * - export ip_conntrack[_expect]_{find_get,put} functions | ||
18 | * */ | ||
19 | |||
20 | #include <linux/types.h> | ||
21 | #include <linux/icmp.h> | ||
22 | #include <linux/ip.h> | ||
23 | #include <linux/netfilter.h> | ||
24 | #include <linux/netfilter_ipv4.h> | ||
25 | #include <linux/module.h> | ||
26 | #include <linux/skbuff.h> | ||
27 | #include <linux/proc_fs.h> | ||
28 | #include <linux/vmalloc.h> | ||
29 | #include <net/checksum.h> | ||
30 | #include <net/ip.h> | ||
31 | #include <linux/stddef.h> | ||
32 | #include <linux/sysctl.h> | ||
33 | #include <linux/slab.h> | ||
34 | #include <linux/random.h> | ||
35 | #include <linux/jhash.h> | ||
36 | #include <linux/err.h> | ||
37 | #include <linux/percpu.h> | ||
38 | #include <linux/moduleparam.h> | ||
39 | #include <linux/notifier.h> | ||
40 | |||
41 | /* ip_conntrack_lock protects the main hash table, protocol/helper/expected | ||
42 | registrations, conntrack timers*/ | ||
43 | #include <linux/netfilter_ipv4/ip_conntrack.h> | ||
44 | #include <linux/netfilter_ipv4/ip_conntrack_protocol.h> | ||
45 | #include <linux/netfilter_ipv4/ip_conntrack_helper.h> | ||
46 | #include <linux/netfilter_ipv4/ip_conntrack_core.h> | ||
47 | |||
48 | #define IP_CONNTRACK_VERSION "2.4" | ||
49 | |||
50 | #if 0 | ||
51 | #define DEBUGP printk | ||
52 | #else | ||
53 | #define DEBUGP(format, args...) | ||
54 | #endif | ||
55 | |||
56 | DEFINE_RWLOCK(ip_conntrack_lock); | ||
57 | |||
58 | /* ip_conntrack_standalone needs this */ | ||
59 | atomic_t ip_conntrack_count = ATOMIC_INIT(0); | ||
60 | |||
61 | void (*ip_conntrack_destroyed)(struct ip_conntrack *conntrack) = NULL; | ||
62 | LIST_HEAD(ip_conntrack_expect_list); | ||
63 | struct ip_conntrack_protocol *ip_ct_protos[MAX_IP_CT_PROTO] __read_mostly; | ||
64 | static LIST_HEAD(helpers); | ||
65 | unsigned int ip_conntrack_htable_size __read_mostly = 0; | ||
66 | int ip_conntrack_max __read_mostly; | ||
67 | struct list_head *ip_conntrack_hash __read_mostly; | ||
68 | static struct kmem_cache *ip_conntrack_cachep __read_mostly; | ||
69 | static struct kmem_cache *ip_conntrack_expect_cachep __read_mostly; | ||
70 | struct ip_conntrack ip_conntrack_untracked; | ||
71 | unsigned int ip_ct_log_invalid __read_mostly; | ||
72 | static LIST_HEAD(unconfirmed); | ||
73 | static int ip_conntrack_vmalloc __read_mostly; | ||
74 | |||
75 | static unsigned int ip_conntrack_next_id; | ||
76 | static unsigned int ip_conntrack_expect_next_id; | ||
77 | #ifdef CONFIG_IP_NF_CONNTRACK_EVENTS | ||
78 | ATOMIC_NOTIFIER_HEAD(ip_conntrack_chain); | ||
79 | ATOMIC_NOTIFIER_HEAD(ip_conntrack_expect_chain); | ||
80 | |||
81 | DEFINE_PER_CPU(struct ip_conntrack_ecache, ip_conntrack_ecache); | ||
82 | |||
83 | /* deliver cached events and clear cache entry - must be called with locally | ||
84 | * disabled softirqs */ | ||
85 | static inline void | ||
86 | __ip_ct_deliver_cached_events(struct ip_conntrack_ecache *ecache) | ||
87 | { | ||
88 | DEBUGP("ecache: delivering events for %p\n", ecache->ct); | ||
89 | if (is_confirmed(ecache->ct) && !is_dying(ecache->ct) && ecache->events) | ||
90 | atomic_notifier_call_chain(&ip_conntrack_chain, ecache->events, | ||
91 | ecache->ct); | ||
92 | ecache->events = 0; | ||
93 | ip_conntrack_put(ecache->ct); | ||
94 | ecache->ct = NULL; | ||
95 | } | ||
96 | |||
97 | /* Deliver all cached events for a particular conntrack. This is called | ||
98 | * by code prior to async packet handling or freeing the skb */ | ||
99 | void ip_ct_deliver_cached_events(const struct ip_conntrack *ct) | ||
100 | { | ||
101 | struct ip_conntrack_ecache *ecache; | ||
102 | |||
103 | local_bh_disable(); | ||
104 | ecache = &__get_cpu_var(ip_conntrack_ecache); | ||
105 | if (ecache->ct == ct) | ||
106 | __ip_ct_deliver_cached_events(ecache); | ||
107 | local_bh_enable(); | ||
108 | } | ||
109 | |||
110 | void __ip_ct_event_cache_init(struct ip_conntrack *ct) | ||
111 | { | ||
112 | struct ip_conntrack_ecache *ecache; | ||
113 | |||
114 | /* take care of delivering potentially old events */ | ||
115 | ecache = &__get_cpu_var(ip_conntrack_ecache); | ||
116 | BUG_ON(ecache->ct == ct); | ||
117 | if (ecache->ct) | ||
118 | __ip_ct_deliver_cached_events(ecache); | ||
119 | /* initialize for this conntrack/packet */ | ||
120 | ecache->ct = ct; | ||
121 | nf_conntrack_get(&ct->ct_general); | ||
122 | } | ||
123 | |||
124 | /* flush the event cache - touches other CPU's data and must not be called while | ||
125 | * packets are still passing through the code */ | ||
126 | static void ip_ct_event_cache_flush(void) | ||
127 | { | ||
128 | struct ip_conntrack_ecache *ecache; | ||
129 | int cpu; | ||
130 | |||
131 | for_each_possible_cpu(cpu) { | ||
132 | ecache = &per_cpu(ip_conntrack_ecache, cpu); | ||
133 | if (ecache->ct) | ||
134 | ip_conntrack_put(ecache->ct); | ||
135 | } | ||
136 | } | ||
137 | #else | ||
138 | static inline void ip_ct_event_cache_flush(void) {} | ||
139 | #endif /* CONFIG_IP_NF_CONNTRACK_EVENTS */ | ||
140 | |||
141 | DEFINE_PER_CPU(struct ip_conntrack_stat, ip_conntrack_stat); | ||
142 | |||
143 | static int ip_conntrack_hash_rnd_initted; | ||
144 | static unsigned int ip_conntrack_hash_rnd; | ||
145 | |||
146 | static u_int32_t __hash_conntrack(const struct ip_conntrack_tuple *tuple, | ||
147 | unsigned int size, unsigned int rnd) | ||
148 | { | ||
149 | return (jhash_3words((__force u32)tuple->src.ip, | ||
150 | ((__force u32)tuple->dst.ip ^ tuple->dst.protonum), | ||
151 | (tuple->src.u.all | (tuple->dst.u.all << 16)), | ||
152 | rnd) % size); | ||
153 | } | ||
154 | |||
155 | static u_int32_t | ||
156 | hash_conntrack(const struct ip_conntrack_tuple *tuple) | ||
157 | { | ||
158 | return __hash_conntrack(tuple, ip_conntrack_htable_size, | ||
159 | ip_conntrack_hash_rnd); | ||
160 | } | ||
161 | |||
162 | int | ||
163 | ip_ct_get_tuple(const struct iphdr *iph, | ||
164 | const struct sk_buff *skb, | ||
165 | unsigned int dataoff, | ||
166 | struct ip_conntrack_tuple *tuple, | ||
167 | const struct ip_conntrack_protocol *protocol) | ||
168 | { | ||
169 | /* Never happen */ | ||
170 | if (iph->frag_off & htons(IP_OFFSET)) { | ||
171 | printk("ip_conntrack_core: Frag of proto %u.\n", | ||
172 | iph->protocol); | ||
173 | return 0; | ||
174 | } | ||
175 | |||
176 | tuple->src.ip = iph->saddr; | ||
177 | tuple->dst.ip = iph->daddr; | ||
178 | tuple->dst.protonum = iph->protocol; | ||
179 | tuple->dst.dir = IP_CT_DIR_ORIGINAL; | ||
180 | |||
181 | return protocol->pkt_to_tuple(skb, dataoff, tuple); | ||
182 | } | ||
183 | |||
184 | int | ||
185 | ip_ct_invert_tuple(struct ip_conntrack_tuple *inverse, | ||
186 | const struct ip_conntrack_tuple *orig, | ||
187 | const struct ip_conntrack_protocol *protocol) | ||
188 | { | ||
189 | inverse->src.ip = orig->dst.ip; | ||
190 | inverse->dst.ip = orig->src.ip; | ||
191 | inverse->dst.protonum = orig->dst.protonum; | ||
192 | inverse->dst.dir = !orig->dst.dir; | ||
193 | |||
194 | return protocol->invert_tuple(inverse, orig); | ||
195 | } | ||
196 | |||
197 | |||
198 | /* ip_conntrack_expect helper functions */ | ||
199 | void ip_ct_unlink_expect(struct ip_conntrack_expect *exp) | ||
200 | { | ||
201 | IP_NF_ASSERT(!timer_pending(&exp->timeout)); | ||
202 | list_del(&exp->list); | ||
203 | CONNTRACK_STAT_INC(expect_delete); | ||
204 | exp->master->expecting--; | ||
205 | ip_conntrack_expect_put(exp); | ||
206 | } | ||
207 | |||
208 | static void expectation_timed_out(unsigned long ul_expect) | ||
209 | { | ||
210 | struct ip_conntrack_expect *exp = (void *)ul_expect; | ||
211 | |||
212 | write_lock_bh(&ip_conntrack_lock); | ||
213 | ip_ct_unlink_expect(exp); | ||
214 | write_unlock_bh(&ip_conntrack_lock); | ||
215 | ip_conntrack_expect_put(exp); | ||
216 | } | ||
217 | |||
218 | struct ip_conntrack_expect * | ||
219 | __ip_conntrack_expect_find(const struct ip_conntrack_tuple *tuple) | ||
220 | { | ||
221 | struct ip_conntrack_expect *i; | ||
222 | |||
223 | list_for_each_entry(i, &ip_conntrack_expect_list, list) { | ||
224 | if (ip_ct_tuple_mask_cmp(tuple, &i->tuple, &i->mask)) | ||
225 | return i; | ||
226 | } | ||
227 | return NULL; | ||
228 | } | ||
229 | |||
230 | /* Just find a expectation corresponding to a tuple. */ | ||
231 | struct ip_conntrack_expect * | ||
232 | ip_conntrack_expect_find_get(const struct ip_conntrack_tuple *tuple) | ||
233 | { | ||
234 | struct ip_conntrack_expect *i; | ||
235 | |||
236 | read_lock_bh(&ip_conntrack_lock); | ||
237 | i = __ip_conntrack_expect_find(tuple); | ||
238 | if (i) | ||
239 | atomic_inc(&i->use); | ||
240 | read_unlock_bh(&ip_conntrack_lock); | ||
241 | |||
242 | return i; | ||
243 | } | ||
244 | |||
245 | /* If an expectation for this connection is found, it gets delete from | ||
246 | * global list then returned. */ | ||
247 | static struct ip_conntrack_expect * | ||
248 | find_expectation(const struct ip_conntrack_tuple *tuple) | ||
249 | { | ||
250 | struct ip_conntrack_expect *i; | ||
251 | |||
252 | list_for_each_entry(i, &ip_conntrack_expect_list, list) { | ||
253 | /* If master is not in hash table yet (ie. packet hasn't left | ||
254 | this machine yet), how can other end know about expected? | ||
255 | Hence these are not the droids you are looking for (if | ||
256 | master ct never got confirmed, we'd hold a reference to it | ||
257 | and weird things would happen to future packets). */ | ||
258 | if (ip_ct_tuple_mask_cmp(tuple, &i->tuple, &i->mask) | ||
259 | && is_confirmed(i->master)) { | ||
260 | if (i->flags & IP_CT_EXPECT_PERMANENT) { | ||
261 | atomic_inc(&i->use); | ||
262 | return i; | ||
263 | } else if (del_timer(&i->timeout)) { | ||
264 | ip_ct_unlink_expect(i); | ||
265 | return i; | ||
266 | } | ||
267 | } | ||
268 | } | ||
269 | return NULL; | ||
270 | } | ||
271 | |||
272 | /* delete all expectations for this conntrack */ | ||
273 | void ip_ct_remove_expectations(struct ip_conntrack *ct) | ||
274 | { | ||
275 | struct ip_conntrack_expect *i, *tmp; | ||
276 | |||
277 | /* Optimization: most connection never expect any others. */ | ||
278 | if (ct->expecting == 0) | ||
279 | return; | ||
280 | |||
281 | list_for_each_entry_safe(i, tmp, &ip_conntrack_expect_list, list) { | ||
282 | if (i->master == ct && del_timer(&i->timeout)) { | ||
283 | ip_ct_unlink_expect(i); | ||
284 | ip_conntrack_expect_put(i); | ||
285 | } | ||
286 | } | ||
287 | } | ||
288 | |||
289 | static void | ||
290 | clean_from_lists(struct ip_conntrack *ct) | ||
291 | { | ||
292 | DEBUGP("clean_from_lists(%p)\n", ct); | ||
293 | list_del(&ct->tuplehash[IP_CT_DIR_ORIGINAL].list); | ||
294 | list_del(&ct->tuplehash[IP_CT_DIR_REPLY].list); | ||
295 | |||
296 | /* Destroy all pending expectations */ | ||
297 | ip_ct_remove_expectations(ct); | ||
298 | } | ||
299 | |||
300 | static void | ||
301 | destroy_conntrack(struct nf_conntrack *nfct) | ||
302 | { | ||
303 | struct ip_conntrack *ct = (struct ip_conntrack *)nfct; | ||
304 | struct ip_conntrack_protocol *proto; | ||
305 | struct ip_conntrack_helper *helper; | ||
306 | typeof(ip_conntrack_destroyed) destroyed; | ||
307 | |||
308 | DEBUGP("destroy_conntrack(%p)\n", ct); | ||
309 | IP_NF_ASSERT(atomic_read(&nfct->use) == 0); | ||
310 | IP_NF_ASSERT(!timer_pending(&ct->timeout)); | ||
311 | |||
312 | ip_conntrack_event(IPCT_DESTROY, ct); | ||
313 | set_bit(IPS_DYING_BIT, &ct->status); | ||
314 | |||
315 | helper = ct->helper; | ||
316 | if (helper && helper->destroy) | ||
317 | helper->destroy(ct); | ||
318 | |||
319 | /* To make sure we don't get any weird locking issues here: | ||
320 | * destroy_conntrack() MUST NOT be called with a write lock | ||
321 | * to ip_conntrack_lock!!! -HW */ | ||
322 | rcu_read_lock(); | ||
323 | proto = __ip_conntrack_proto_find(ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.protonum); | ||
324 | if (proto && proto->destroy) | ||
325 | proto->destroy(ct); | ||
326 | |||
327 | destroyed = rcu_dereference(ip_conntrack_destroyed); | ||
328 | if (destroyed) | ||
329 | destroyed(ct); | ||
330 | |||
331 | rcu_read_unlock(); | ||
332 | |||
333 | write_lock_bh(&ip_conntrack_lock); | ||
334 | /* Expectations will have been removed in clean_from_lists, | ||
335 | * except TFTP can create an expectation on the first packet, | ||
336 | * before connection is in the list, so we need to clean here, | ||
337 | * too. */ | ||
338 | ip_ct_remove_expectations(ct); | ||
339 | |||
340 | /* We overload first tuple to link into unconfirmed list. */ | ||
341 | if (!is_confirmed(ct)) { | ||
342 | BUG_ON(list_empty(&ct->tuplehash[IP_CT_DIR_ORIGINAL].list)); | ||
343 | list_del(&ct->tuplehash[IP_CT_DIR_ORIGINAL].list); | ||
344 | } | ||
345 | |||
346 | CONNTRACK_STAT_INC(delete); | ||
347 | write_unlock_bh(&ip_conntrack_lock); | ||
348 | |||
349 | if (ct->master) | ||
350 | ip_conntrack_put(ct->master); | ||
351 | |||
352 | DEBUGP("destroy_conntrack: returning ct=%p to slab\n", ct); | ||
353 | ip_conntrack_free(ct); | ||
354 | } | ||
355 | |||
356 | static void death_by_timeout(unsigned long ul_conntrack) | ||
357 | { | ||
358 | struct ip_conntrack *ct = (void *)ul_conntrack; | ||
359 | |||
360 | write_lock_bh(&ip_conntrack_lock); | ||
361 | /* Inside lock so preempt is disabled on module removal path. | ||
362 | * Otherwise we can get spurious warnings. */ | ||
363 | CONNTRACK_STAT_INC(delete_list); | ||
364 | clean_from_lists(ct); | ||
365 | write_unlock_bh(&ip_conntrack_lock); | ||
366 | ip_conntrack_put(ct); | ||
367 | } | ||
368 | |||
369 | struct ip_conntrack_tuple_hash * | ||
370 | __ip_conntrack_find(const struct ip_conntrack_tuple *tuple, | ||
371 | const struct ip_conntrack *ignored_conntrack) | ||
372 | { | ||
373 | struct ip_conntrack_tuple_hash *h; | ||
374 | unsigned int hash = hash_conntrack(tuple); | ||
375 | |||
376 | list_for_each_entry(h, &ip_conntrack_hash[hash], list) { | ||
377 | if (tuplehash_to_ctrack(h) != ignored_conntrack && | ||
378 | ip_ct_tuple_equal(tuple, &h->tuple)) { | ||
379 | CONNTRACK_STAT_INC(found); | ||
380 | return h; | ||
381 | } | ||
382 | CONNTRACK_STAT_INC(searched); | ||
383 | } | ||
384 | |||
385 | return NULL; | ||
386 | } | ||
387 | |||
388 | /* Find a connection corresponding to a tuple. */ | ||
389 | struct ip_conntrack_tuple_hash * | ||
390 | ip_conntrack_find_get(const struct ip_conntrack_tuple *tuple, | ||
391 | const struct ip_conntrack *ignored_conntrack) | ||
392 | { | ||
393 | struct ip_conntrack_tuple_hash *h; | ||
394 | |||
395 | read_lock_bh(&ip_conntrack_lock); | ||
396 | h = __ip_conntrack_find(tuple, ignored_conntrack); | ||
397 | if (h) | ||
398 | atomic_inc(&tuplehash_to_ctrack(h)->ct_general.use); | ||
399 | read_unlock_bh(&ip_conntrack_lock); | ||
400 | |||
401 | return h; | ||
402 | } | ||
403 | |||
404 | static void __ip_conntrack_hash_insert(struct ip_conntrack *ct, | ||
405 | unsigned int hash, | ||
406 | unsigned int repl_hash) | ||
407 | { | ||
408 | ct->id = ++ip_conntrack_next_id; | ||
409 | list_add(&ct->tuplehash[IP_CT_DIR_ORIGINAL].list, | ||
410 | &ip_conntrack_hash[hash]); | ||
411 | list_add(&ct->tuplehash[IP_CT_DIR_REPLY].list, | ||
412 | &ip_conntrack_hash[repl_hash]); | ||
413 | } | ||
414 | |||
415 | void ip_conntrack_hash_insert(struct ip_conntrack *ct) | ||
416 | { | ||
417 | unsigned int hash, repl_hash; | ||
418 | |||
419 | hash = hash_conntrack(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); | ||
420 | repl_hash = hash_conntrack(&ct->tuplehash[IP_CT_DIR_REPLY].tuple); | ||
421 | |||
422 | write_lock_bh(&ip_conntrack_lock); | ||
423 | __ip_conntrack_hash_insert(ct, hash, repl_hash); | ||
424 | write_unlock_bh(&ip_conntrack_lock); | ||
425 | } | ||
426 | |||
427 | /* Confirm a connection given skb; places it in hash table */ | ||
428 | int | ||
429 | __ip_conntrack_confirm(struct sk_buff **pskb) | ||
430 | { | ||
431 | unsigned int hash, repl_hash; | ||
432 | struct ip_conntrack_tuple_hash *h; | ||
433 | struct ip_conntrack *ct; | ||
434 | enum ip_conntrack_info ctinfo; | ||
435 | |||
436 | ct = ip_conntrack_get(*pskb, &ctinfo); | ||
437 | |||
438 | /* ipt_REJECT uses ip_conntrack_attach to attach related | ||
439 | ICMP/TCP RST packets in other direction. Actual packet | ||
440 | which created connection will be IP_CT_NEW or for an | ||
441 | expected connection, IP_CT_RELATED. */ | ||
442 | if (CTINFO2DIR(ctinfo) != IP_CT_DIR_ORIGINAL) | ||
443 | return NF_ACCEPT; | ||
444 | |||
445 | hash = hash_conntrack(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); | ||
446 | repl_hash = hash_conntrack(&ct->tuplehash[IP_CT_DIR_REPLY].tuple); | ||
447 | |||
448 | /* We're not in hash table, and we refuse to set up related | ||
449 | connections for unconfirmed conns. But packet copies and | ||
450 | REJECT will give spurious warnings here. */ | ||
451 | /* IP_NF_ASSERT(atomic_read(&ct->ct_general.use) == 1); */ | ||
452 | |||
453 | /* No external references means noone else could have | ||
454 | confirmed us. */ | ||
455 | IP_NF_ASSERT(!is_confirmed(ct)); | ||
456 | DEBUGP("Confirming conntrack %p\n", ct); | ||
457 | |||
458 | write_lock_bh(&ip_conntrack_lock); | ||
459 | |||
460 | /* See if there's one in the list already, including reverse: | ||
461 | NAT could have grabbed it without realizing, since we're | ||
462 | not in the hash. If there is, we lost race. */ | ||
463 | list_for_each_entry(h, &ip_conntrack_hash[hash], list) | ||
464 | if (ip_ct_tuple_equal(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple, | ||
465 | &h->tuple)) | ||
466 | goto out; | ||
467 | list_for_each_entry(h, &ip_conntrack_hash[repl_hash], list) | ||
468 | if (ip_ct_tuple_equal(&ct->tuplehash[IP_CT_DIR_REPLY].tuple, | ||
469 | &h->tuple)) | ||
470 | goto out; | ||
471 | |||
472 | /* Remove from unconfirmed list */ | ||
473 | list_del(&ct->tuplehash[IP_CT_DIR_ORIGINAL].list); | ||
474 | |||
475 | __ip_conntrack_hash_insert(ct, hash, repl_hash); | ||
476 | /* Timer relative to confirmation time, not original | ||
477 | setting time, otherwise we'd get timer wrap in | ||
478 | weird delay cases. */ | ||
479 | ct->timeout.expires += jiffies; | ||
480 | add_timer(&ct->timeout); | ||
481 | atomic_inc(&ct->ct_general.use); | ||
482 | set_bit(IPS_CONFIRMED_BIT, &ct->status); | ||
483 | CONNTRACK_STAT_INC(insert); | ||
484 | write_unlock_bh(&ip_conntrack_lock); | ||
485 | if (ct->helper) | ||
486 | ip_conntrack_event_cache(IPCT_HELPER, *pskb); | ||
487 | #ifdef CONFIG_IP_NF_NAT_NEEDED | ||
488 | if (test_bit(IPS_SRC_NAT_DONE_BIT, &ct->status) || | ||
489 | test_bit(IPS_DST_NAT_DONE_BIT, &ct->status)) | ||
490 | ip_conntrack_event_cache(IPCT_NATINFO, *pskb); | ||
491 | #endif | ||
492 | ip_conntrack_event_cache(master_ct(ct) ? | ||
493 | IPCT_RELATED : IPCT_NEW, *pskb); | ||
494 | |||
495 | return NF_ACCEPT; | ||
496 | |||
497 | out: | ||
498 | CONNTRACK_STAT_INC(insert_failed); | ||
499 | write_unlock_bh(&ip_conntrack_lock); | ||
500 | return NF_DROP; | ||
501 | } | ||
502 | |||
503 | /* Returns true if a connection correspondings to the tuple (required | ||
504 | for NAT). */ | ||
505 | int | ||
506 | ip_conntrack_tuple_taken(const struct ip_conntrack_tuple *tuple, | ||
507 | const struct ip_conntrack *ignored_conntrack) | ||
508 | { | ||
509 | struct ip_conntrack_tuple_hash *h; | ||
510 | |||
511 | read_lock_bh(&ip_conntrack_lock); | ||
512 | h = __ip_conntrack_find(tuple, ignored_conntrack); | ||
513 | read_unlock_bh(&ip_conntrack_lock); | ||
514 | |||
515 | return h != NULL; | ||
516 | } | ||
517 | |||
518 | /* There's a small race here where we may free a just-assured | ||
519 | connection. Too bad: we're in trouble anyway. */ | ||
520 | static int early_drop(struct list_head *chain) | ||
521 | { | ||
522 | /* Traverse backwards: gives us oldest, which is roughly LRU */ | ||
523 | struct ip_conntrack_tuple_hash *h; | ||
524 | struct ip_conntrack *ct = NULL, *tmp; | ||
525 | int dropped = 0; | ||
526 | |||
527 | read_lock_bh(&ip_conntrack_lock); | ||
528 | list_for_each_entry_reverse(h, chain, list) { | ||
529 | tmp = tuplehash_to_ctrack(h); | ||
530 | if (!test_bit(IPS_ASSURED_BIT, &tmp->status)) { | ||
531 | ct = tmp; | ||
532 | atomic_inc(&ct->ct_general.use); | ||
533 | break; | ||
534 | } | ||
535 | } | ||
536 | read_unlock_bh(&ip_conntrack_lock); | ||
537 | |||
538 | if (!ct) | ||
539 | return dropped; | ||
540 | |||
541 | if (del_timer(&ct->timeout)) { | ||
542 | death_by_timeout((unsigned long)ct); | ||
543 | dropped = 1; | ||
544 | CONNTRACK_STAT_INC_ATOMIC(early_drop); | ||
545 | } | ||
546 | ip_conntrack_put(ct); | ||
547 | return dropped; | ||
548 | } | ||
549 | |||
550 | static struct ip_conntrack_helper * | ||
551 | __ip_conntrack_helper_find( const struct ip_conntrack_tuple *tuple) | ||
552 | { | ||
553 | struct ip_conntrack_helper *h; | ||
554 | |||
555 | list_for_each_entry(h, &helpers, list) { | ||
556 | if (ip_ct_tuple_mask_cmp(tuple, &h->tuple, &h->mask)) | ||
557 | return h; | ||
558 | } | ||
559 | return NULL; | ||
560 | } | ||
561 | |||
562 | struct ip_conntrack_helper * | ||
563 | ip_conntrack_helper_find_get( const struct ip_conntrack_tuple *tuple) | ||
564 | { | ||
565 | struct ip_conntrack_helper *helper; | ||
566 | |||
567 | /* need ip_conntrack_lock to assure that helper exists until | ||
568 | * try_module_get() is called */ | ||
569 | read_lock_bh(&ip_conntrack_lock); | ||
570 | |||
571 | helper = __ip_conntrack_helper_find(tuple); | ||
572 | if (helper) { | ||
573 | /* need to increase module usage count to assure helper will | ||
574 | * not go away while the caller is e.g. busy putting a | ||
575 | * conntrack in the hash that uses the helper */ | ||
576 | if (!try_module_get(helper->me)) | ||
577 | helper = NULL; | ||
578 | } | ||
579 | |||
580 | read_unlock_bh(&ip_conntrack_lock); | ||
581 | |||
582 | return helper; | ||
583 | } | ||
584 | |||
585 | void ip_conntrack_helper_put(struct ip_conntrack_helper *helper) | ||
586 | { | ||
587 | module_put(helper->me); | ||
588 | } | ||
589 | |||
590 | struct ip_conntrack_protocol * | ||
591 | __ip_conntrack_proto_find(u_int8_t protocol) | ||
592 | { | ||
593 | return ip_ct_protos[protocol]; | ||
594 | } | ||
595 | |||
596 | /* this is guaranteed to always return a valid protocol helper, since | ||
597 | * it falls back to generic_protocol */ | ||
598 | struct ip_conntrack_protocol * | ||
599 | ip_conntrack_proto_find_get(u_int8_t protocol) | ||
600 | { | ||
601 | struct ip_conntrack_protocol *p; | ||
602 | |||
603 | rcu_read_lock(); | ||
604 | p = __ip_conntrack_proto_find(protocol); | ||
605 | if (p) { | ||
606 | if (!try_module_get(p->me)) | ||
607 | p = &ip_conntrack_generic_protocol; | ||
608 | } | ||
609 | rcu_read_unlock(); | ||
610 | |||
611 | return p; | ||
612 | } | ||
613 | |||
614 | void ip_conntrack_proto_put(struct ip_conntrack_protocol *p) | ||
615 | { | ||
616 | module_put(p->me); | ||
617 | } | ||
618 | |||
619 | struct ip_conntrack *ip_conntrack_alloc(struct ip_conntrack_tuple *orig, | ||
620 | struct ip_conntrack_tuple *repl) | ||
621 | { | ||
622 | struct ip_conntrack *conntrack; | ||
623 | |||
624 | if (!ip_conntrack_hash_rnd_initted) { | ||
625 | get_random_bytes(&ip_conntrack_hash_rnd, 4); | ||
626 | ip_conntrack_hash_rnd_initted = 1; | ||
627 | } | ||
628 | |||
629 | /* We don't want any race condition at early drop stage */ | ||
630 | atomic_inc(&ip_conntrack_count); | ||
631 | |||
632 | if (ip_conntrack_max | ||
633 | && atomic_read(&ip_conntrack_count) > ip_conntrack_max) { | ||
634 | unsigned int hash = hash_conntrack(orig); | ||
635 | /* Try dropping from this hash chain. */ | ||
636 | if (!early_drop(&ip_conntrack_hash[hash])) { | ||
637 | atomic_dec(&ip_conntrack_count); | ||
638 | if (net_ratelimit()) | ||
639 | printk(KERN_WARNING | ||
640 | "ip_conntrack: table full, dropping" | ||
641 | " packet.\n"); | ||
642 | return ERR_PTR(-ENOMEM); | ||
643 | } | ||
644 | } | ||
645 | |||
646 | conntrack = kmem_cache_zalloc(ip_conntrack_cachep, GFP_ATOMIC); | ||
647 | if (!conntrack) { | ||
648 | DEBUGP("Can't allocate conntrack.\n"); | ||
649 | atomic_dec(&ip_conntrack_count); | ||
650 | return ERR_PTR(-ENOMEM); | ||
651 | } | ||
652 | |||
653 | atomic_set(&conntrack->ct_general.use, 1); | ||
654 | conntrack->ct_general.destroy = destroy_conntrack; | ||
655 | conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple = *orig; | ||
656 | conntrack->tuplehash[IP_CT_DIR_REPLY].tuple = *repl; | ||
657 | /* Don't set timer yet: wait for confirmation */ | ||
658 | init_timer(&conntrack->timeout); | ||
659 | conntrack->timeout.data = (unsigned long)conntrack; | ||
660 | conntrack->timeout.function = death_by_timeout; | ||
661 | |||
662 | return conntrack; | ||
663 | } | ||
664 | |||
665 | void | ||
666 | ip_conntrack_free(struct ip_conntrack *conntrack) | ||
667 | { | ||
668 | atomic_dec(&ip_conntrack_count); | ||
669 | kmem_cache_free(ip_conntrack_cachep, conntrack); | ||
670 | } | ||
671 | |||
672 | /* Allocate a new conntrack: we return -ENOMEM if classification | ||
673 | * failed due to stress. Otherwise it really is unclassifiable */ | ||
674 | static struct ip_conntrack_tuple_hash * | ||
675 | init_conntrack(struct ip_conntrack_tuple *tuple, | ||
676 | struct ip_conntrack_protocol *protocol, | ||
677 | struct sk_buff *skb) | ||
678 | { | ||
679 | struct ip_conntrack *conntrack; | ||
680 | struct ip_conntrack_tuple repl_tuple; | ||
681 | struct ip_conntrack_expect *exp; | ||
682 | |||
683 | if (!ip_ct_invert_tuple(&repl_tuple, tuple, protocol)) { | ||
684 | DEBUGP("Can't invert tuple.\n"); | ||
685 | return NULL; | ||
686 | } | ||
687 | |||
688 | conntrack = ip_conntrack_alloc(tuple, &repl_tuple); | ||
689 | if (conntrack == NULL || IS_ERR(conntrack)) | ||
690 | return (struct ip_conntrack_tuple_hash *)conntrack; | ||
691 | |||
692 | if (!protocol->new(conntrack, skb)) { | ||
693 | ip_conntrack_free(conntrack); | ||
694 | return NULL; | ||
695 | } | ||
696 | |||
697 | write_lock_bh(&ip_conntrack_lock); | ||
698 | exp = find_expectation(tuple); | ||
699 | |||
700 | if (exp) { | ||
701 | DEBUGP("conntrack: expectation arrives ct=%p exp=%p\n", | ||
702 | conntrack, exp); | ||
703 | /* Welcome, Mr. Bond. We've been expecting you... */ | ||
704 | __set_bit(IPS_EXPECTED_BIT, &conntrack->status); | ||
705 | conntrack->master = exp->master; | ||
706 | #ifdef CONFIG_IP_NF_CONNTRACK_MARK | ||
707 | conntrack->mark = exp->master->mark; | ||
708 | #endif | ||
709 | #if defined(CONFIG_IP_NF_TARGET_MASQUERADE) || \ | ||
710 | defined(CONFIG_IP_NF_TARGET_MASQUERADE_MODULE) | ||
711 | /* this is ugly, but there is no other place where to put it */ | ||
712 | conntrack->nat.masq_index = exp->master->nat.masq_index; | ||
713 | #endif | ||
714 | #ifdef CONFIG_IP_NF_CONNTRACK_SECMARK | ||
715 | conntrack->secmark = exp->master->secmark; | ||
716 | #endif | ||
717 | nf_conntrack_get(&conntrack->master->ct_general); | ||
718 | CONNTRACK_STAT_INC(expect_new); | ||
719 | } else { | ||
720 | conntrack->helper = __ip_conntrack_helper_find(&repl_tuple); | ||
721 | |||
722 | CONNTRACK_STAT_INC(new); | ||
723 | } | ||
724 | |||
725 | /* Overload tuple linked list to put us in unconfirmed list. */ | ||
726 | list_add(&conntrack->tuplehash[IP_CT_DIR_ORIGINAL].list, &unconfirmed); | ||
727 | |||
728 | write_unlock_bh(&ip_conntrack_lock); | ||
729 | |||
730 | if (exp) { | ||
731 | if (exp->expectfn) | ||
732 | exp->expectfn(conntrack, exp); | ||
733 | ip_conntrack_expect_put(exp); | ||
734 | } | ||
735 | |||
736 | return &conntrack->tuplehash[IP_CT_DIR_ORIGINAL]; | ||
737 | } | ||
738 | |||
739 | /* On success, returns conntrack ptr, sets skb->nfct and ctinfo */ | ||
740 | static inline struct ip_conntrack * | ||
741 | resolve_normal_ct(struct sk_buff *skb, | ||
742 | struct ip_conntrack_protocol *proto, | ||
743 | int *set_reply, | ||
744 | unsigned int hooknum, | ||
745 | enum ip_conntrack_info *ctinfo) | ||
746 | { | ||
747 | struct ip_conntrack_tuple tuple; | ||
748 | struct ip_conntrack_tuple_hash *h; | ||
749 | struct ip_conntrack *ct; | ||
750 | |||
751 | IP_NF_ASSERT((ip_hdr(skb)->frag_off & htons(IP_OFFSET)) == 0); | ||
752 | |||
753 | if (!ip_ct_get_tuple(ip_hdr(skb), skb, ip_hdrlen(skb), &tuple,proto)) | ||
754 | return NULL; | ||
755 | |||
756 | /* look for tuple match */ | ||
757 | h = ip_conntrack_find_get(&tuple, NULL); | ||
758 | if (!h) { | ||
759 | h = init_conntrack(&tuple, proto, skb); | ||
760 | if (!h) | ||
761 | return NULL; | ||
762 | if (IS_ERR(h)) | ||
763 | return (void *)h; | ||
764 | } | ||
765 | ct = tuplehash_to_ctrack(h); | ||
766 | |||
767 | /* It exists; we have (non-exclusive) reference. */ | ||
768 | if (DIRECTION(h) == IP_CT_DIR_REPLY) { | ||
769 | *ctinfo = IP_CT_ESTABLISHED + IP_CT_IS_REPLY; | ||
770 | /* Please set reply bit if this packet OK */ | ||
771 | *set_reply = 1; | ||
772 | } else { | ||
773 | /* Once we've had two way comms, always ESTABLISHED. */ | ||
774 | if (test_bit(IPS_SEEN_REPLY_BIT, &ct->status)) { | ||
775 | DEBUGP("ip_conntrack_in: normal packet for %p\n", | ||
776 | ct); | ||
777 | *ctinfo = IP_CT_ESTABLISHED; | ||
778 | } else if (test_bit(IPS_EXPECTED_BIT, &ct->status)) { | ||
779 | DEBUGP("ip_conntrack_in: related packet for %p\n", | ||
780 | ct); | ||
781 | *ctinfo = IP_CT_RELATED; | ||
782 | } else { | ||
783 | DEBUGP("ip_conntrack_in: new packet for %p\n", | ||
784 | ct); | ||
785 | *ctinfo = IP_CT_NEW; | ||
786 | } | ||
787 | *set_reply = 0; | ||
788 | } | ||
789 | skb->nfct = &ct->ct_general; | ||
790 | skb->nfctinfo = *ctinfo; | ||
791 | return ct; | ||
792 | } | ||
793 | |||
794 | /* Netfilter hook itself. */ | ||
795 | unsigned int ip_conntrack_in(unsigned int hooknum, | ||
796 | struct sk_buff **pskb, | ||
797 | const struct net_device *in, | ||
798 | const struct net_device *out, | ||
799 | int (*okfn)(struct sk_buff *)) | ||
800 | { | ||
801 | struct ip_conntrack *ct; | ||
802 | enum ip_conntrack_info ctinfo; | ||
803 | struct ip_conntrack_protocol *proto; | ||
804 | int set_reply = 0; | ||
805 | int ret; | ||
806 | |||
807 | /* Previously seen (loopback or untracked)? Ignore. */ | ||
808 | if ((*pskb)->nfct) { | ||
809 | CONNTRACK_STAT_INC_ATOMIC(ignore); | ||
810 | return NF_ACCEPT; | ||
811 | } | ||
812 | |||
813 | /* Never happen */ | ||
814 | if (ip_hdr(*pskb)->frag_off & htons(IP_OFFSET)) { | ||
815 | if (net_ratelimit()) { | ||
816 | printk(KERN_ERR "ip_conntrack_in: Frag of proto %u (hook=%u)\n", | ||
817 | ip_hdr(*pskb)->protocol, hooknum); | ||
818 | } | ||
819 | return NF_DROP; | ||
820 | } | ||
821 | |||
822 | /* Doesn't cover locally-generated broadcast, so not worth it. */ | ||
823 | #if 0 | ||
824 | /* Ignore broadcast: no `connection'. */ | ||
825 | if ((*pskb)->pkt_type == PACKET_BROADCAST) { | ||
826 | printk("Broadcast packet!\n"); | ||
827 | return NF_ACCEPT; | ||
828 | } else if ((ip_hdr(*pskb)->daddr & htonl(0x000000FF)) | ||
829 | == htonl(0x000000FF)) { | ||
830 | printk("Should bcast: %u.%u.%u.%u->%u.%u.%u.%u (sk=%p, ptype=%u)\n", | ||
831 | NIPQUAD(ip_hdr(*pskb)->saddr), | ||
832 | NIPQUAD(ip_hdr(*pskb)->daddr), | ||
833 | (*pskb)->sk, (*pskb)->pkt_type); | ||
834 | } | ||
835 | #endif | ||
836 | |||
837 | /* rcu_read_lock()ed by nf_hook_slow */ | ||
838 | proto = __ip_conntrack_proto_find(ip_hdr(*pskb)->protocol); | ||
839 | |||
840 | /* It may be an special packet, error, unclean... | ||
841 | * inverse of the return code tells to the netfilter | ||
842 | * core what to do with the packet. */ | ||
843 | if (proto->error != NULL | ||
844 | && (ret = proto->error(*pskb, &ctinfo, hooknum)) <= 0) { | ||
845 | CONNTRACK_STAT_INC_ATOMIC(error); | ||
846 | CONNTRACK_STAT_INC_ATOMIC(invalid); | ||
847 | return -ret; | ||
848 | } | ||
849 | |||
850 | if (!(ct = resolve_normal_ct(*pskb, proto,&set_reply,hooknum,&ctinfo))) { | ||
851 | /* Not valid part of a connection */ | ||
852 | CONNTRACK_STAT_INC_ATOMIC(invalid); | ||
853 | return NF_ACCEPT; | ||
854 | } | ||
855 | |||
856 | if (IS_ERR(ct)) { | ||
857 | /* Too stressed to deal. */ | ||
858 | CONNTRACK_STAT_INC_ATOMIC(drop); | ||
859 | return NF_DROP; | ||
860 | } | ||
861 | |||
862 | IP_NF_ASSERT((*pskb)->nfct); | ||
863 | |||
864 | ret = proto->packet(ct, *pskb, ctinfo); | ||
865 | if (ret < 0) { | ||
866 | /* Invalid: inverse of the return code tells | ||
867 | * the netfilter core what to do*/ | ||
868 | nf_conntrack_put((*pskb)->nfct); | ||
869 | (*pskb)->nfct = NULL; | ||
870 | CONNTRACK_STAT_INC_ATOMIC(invalid); | ||
871 | return -ret; | ||
872 | } | ||
873 | |||
874 | if (set_reply && !test_and_set_bit(IPS_SEEN_REPLY_BIT, &ct->status)) | ||
875 | ip_conntrack_event_cache(IPCT_STATUS, *pskb); | ||
876 | |||
877 | return ret; | ||
878 | } | ||
879 | |||
880 | int invert_tuplepr(struct ip_conntrack_tuple *inverse, | ||
881 | const struct ip_conntrack_tuple *orig) | ||
882 | { | ||
883 | struct ip_conntrack_protocol *proto; | ||
884 | int ret; | ||
885 | |||
886 | rcu_read_lock(); | ||
887 | proto = __ip_conntrack_proto_find(orig->dst.protonum); | ||
888 | ret = ip_ct_invert_tuple(inverse, orig, proto); | ||
889 | rcu_read_unlock(); | ||
890 | |||
891 | return ret; | ||
892 | } | ||
893 | |||
894 | /* Would two expected things clash? */ | ||
895 | static inline int expect_clash(const struct ip_conntrack_expect *a, | ||
896 | const struct ip_conntrack_expect *b) | ||
897 | { | ||
898 | /* Part covered by intersection of masks must be unequal, | ||
899 | otherwise they clash */ | ||
900 | struct ip_conntrack_tuple intersect_mask | ||
901 | = { { a->mask.src.ip & b->mask.src.ip, | ||
902 | { a->mask.src.u.all & b->mask.src.u.all } }, | ||
903 | { a->mask.dst.ip & b->mask.dst.ip, | ||
904 | { a->mask.dst.u.all & b->mask.dst.u.all }, | ||
905 | a->mask.dst.protonum & b->mask.dst.protonum } }; | ||
906 | |||
907 | return ip_ct_tuple_mask_cmp(&a->tuple, &b->tuple, &intersect_mask); | ||
908 | } | ||
909 | |||
910 | static inline int expect_matches(const struct ip_conntrack_expect *a, | ||
911 | const struct ip_conntrack_expect *b) | ||
912 | { | ||
913 | return a->master == b->master | ||
914 | && ip_ct_tuple_equal(&a->tuple, &b->tuple) | ||
915 | && ip_ct_tuple_equal(&a->mask, &b->mask); | ||
916 | } | ||
917 | |||
918 | /* Generally a bad idea to call this: could have matched already. */ | ||
919 | void ip_conntrack_unexpect_related(struct ip_conntrack_expect *exp) | ||
920 | { | ||
921 | struct ip_conntrack_expect *i; | ||
922 | |||
923 | write_lock_bh(&ip_conntrack_lock); | ||
924 | /* choose the the oldest expectation to evict */ | ||
925 | list_for_each_entry_reverse(i, &ip_conntrack_expect_list, list) { | ||
926 | if (expect_matches(i, exp) && del_timer(&i->timeout)) { | ||
927 | ip_ct_unlink_expect(i); | ||
928 | write_unlock_bh(&ip_conntrack_lock); | ||
929 | ip_conntrack_expect_put(i); | ||
930 | return; | ||
931 | } | ||
932 | } | ||
933 | write_unlock_bh(&ip_conntrack_lock); | ||
934 | } | ||
935 | |||
936 | /* We don't increase the master conntrack refcount for non-fulfilled | ||
937 | * conntracks. During the conntrack destruction, the expectations are | ||
938 | * always killed before the conntrack itself */ | ||
939 | struct ip_conntrack_expect *ip_conntrack_expect_alloc(struct ip_conntrack *me) | ||
940 | { | ||
941 | struct ip_conntrack_expect *new; | ||
942 | |||
943 | new = kmem_cache_alloc(ip_conntrack_expect_cachep, GFP_ATOMIC); | ||
944 | if (!new) { | ||
945 | DEBUGP("expect_related: OOM allocating expect\n"); | ||
946 | return NULL; | ||
947 | } | ||
948 | new->master = me; | ||
949 | atomic_set(&new->use, 1); | ||
950 | return new; | ||
951 | } | ||
952 | |||
953 | void ip_conntrack_expect_put(struct ip_conntrack_expect *exp) | ||
954 | { | ||
955 | if (atomic_dec_and_test(&exp->use)) | ||
956 | kmem_cache_free(ip_conntrack_expect_cachep, exp); | ||
957 | } | ||
958 | |||
959 | static void ip_conntrack_expect_insert(struct ip_conntrack_expect *exp) | ||
960 | { | ||
961 | atomic_inc(&exp->use); | ||
962 | exp->master->expecting++; | ||
963 | list_add(&exp->list, &ip_conntrack_expect_list); | ||
964 | |||
965 | init_timer(&exp->timeout); | ||
966 | exp->timeout.data = (unsigned long)exp; | ||
967 | exp->timeout.function = expectation_timed_out; | ||
968 | exp->timeout.expires = jiffies + exp->master->helper->timeout * HZ; | ||
969 | add_timer(&exp->timeout); | ||
970 | |||
971 | exp->id = ++ip_conntrack_expect_next_id; | ||
972 | atomic_inc(&exp->use); | ||
973 | CONNTRACK_STAT_INC(expect_create); | ||
974 | } | ||
975 | |||
976 | /* Race with expectations being used means we could have none to find; OK. */ | ||
977 | static void evict_oldest_expect(struct ip_conntrack *master) | ||
978 | { | ||
979 | struct ip_conntrack_expect *i; | ||
980 | |||
981 | list_for_each_entry_reverse(i, &ip_conntrack_expect_list, list) { | ||
982 | if (i->master == master) { | ||
983 | if (del_timer(&i->timeout)) { | ||
984 | ip_ct_unlink_expect(i); | ||
985 | ip_conntrack_expect_put(i); | ||
986 | } | ||
987 | break; | ||
988 | } | ||
989 | } | ||
990 | } | ||
991 | |||
992 | static inline int refresh_timer(struct ip_conntrack_expect *i) | ||
993 | { | ||
994 | if (!del_timer(&i->timeout)) | ||
995 | return 0; | ||
996 | |||
997 | i->timeout.expires = jiffies + i->master->helper->timeout*HZ; | ||
998 | add_timer(&i->timeout); | ||
999 | return 1; | ||
1000 | } | ||
1001 | |||
1002 | int ip_conntrack_expect_related(struct ip_conntrack_expect *expect) | ||
1003 | { | ||
1004 | struct ip_conntrack_expect *i; | ||
1005 | int ret; | ||
1006 | |||
1007 | DEBUGP("ip_conntrack_expect_related %p\n", related_to); | ||
1008 | DEBUGP("tuple: "); DUMP_TUPLE(&expect->tuple); | ||
1009 | DEBUGP("mask: "); DUMP_TUPLE(&expect->mask); | ||
1010 | |||
1011 | write_lock_bh(&ip_conntrack_lock); | ||
1012 | list_for_each_entry(i, &ip_conntrack_expect_list, list) { | ||
1013 | if (expect_matches(i, expect)) { | ||
1014 | /* Refresh timer: if it's dying, ignore.. */ | ||
1015 | if (refresh_timer(i)) { | ||
1016 | ret = 0; | ||
1017 | goto out; | ||
1018 | } | ||
1019 | } else if (expect_clash(i, expect)) { | ||
1020 | ret = -EBUSY; | ||
1021 | goto out; | ||
1022 | } | ||
1023 | } | ||
1024 | |||
1025 | /* Will be over limit? */ | ||
1026 | if (expect->master->helper->max_expected && | ||
1027 | expect->master->expecting >= expect->master->helper->max_expected) | ||
1028 | evict_oldest_expect(expect->master); | ||
1029 | |||
1030 | ip_conntrack_expect_insert(expect); | ||
1031 | ip_conntrack_expect_event(IPEXP_NEW, expect); | ||
1032 | ret = 0; | ||
1033 | out: | ||
1034 | write_unlock_bh(&ip_conntrack_lock); | ||
1035 | return ret; | ||
1036 | } | ||
1037 | |||
1038 | /* Alter reply tuple (maybe alter helper). This is for NAT, and is | ||
1039 | implicitly racy: see __ip_conntrack_confirm */ | ||
1040 | void ip_conntrack_alter_reply(struct ip_conntrack *conntrack, | ||
1041 | const struct ip_conntrack_tuple *newreply) | ||
1042 | { | ||
1043 | write_lock_bh(&ip_conntrack_lock); | ||
1044 | /* Should be unconfirmed, so not in hash table yet */ | ||
1045 | IP_NF_ASSERT(!is_confirmed(conntrack)); | ||
1046 | |||
1047 | DEBUGP("Altering reply tuple of %p to ", conntrack); | ||
1048 | DUMP_TUPLE(newreply); | ||
1049 | |||
1050 | conntrack->tuplehash[IP_CT_DIR_REPLY].tuple = *newreply; | ||
1051 | if (!conntrack->master && conntrack->expecting == 0) | ||
1052 | conntrack->helper = __ip_conntrack_helper_find(newreply); | ||
1053 | write_unlock_bh(&ip_conntrack_lock); | ||
1054 | } | ||
1055 | |||
1056 | int ip_conntrack_helper_register(struct ip_conntrack_helper *me) | ||
1057 | { | ||
1058 | BUG_ON(me->timeout == 0); | ||
1059 | write_lock_bh(&ip_conntrack_lock); | ||
1060 | list_add(&me->list, &helpers); | ||
1061 | write_unlock_bh(&ip_conntrack_lock); | ||
1062 | |||
1063 | return 0; | ||
1064 | } | ||
1065 | |||
1066 | struct ip_conntrack_helper * | ||
1067 | __ip_conntrack_helper_find_byname(const char *name) | ||
1068 | { | ||
1069 | struct ip_conntrack_helper *h; | ||
1070 | |||
1071 | list_for_each_entry(h, &helpers, list) { | ||
1072 | if (!strcmp(h->name, name)) | ||
1073 | return h; | ||
1074 | } | ||
1075 | |||
1076 | return NULL; | ||
1077 | } | ||
1078 | |||
1079 | static inline void unhelp(struct ip_conntrack_tuple_hash *i, | ||
1080 | const struct ip_conntrack_helper *me) | ||
1081 | { | ||
1082 | if (tuplehash_to_ctrack(i)->helper == me) { | ||
1083 | ip_conntrack_event(IPCT_HELPER, tuplehash_to_ctrack(i)); | ||
1084 | tuplehash_to_ctrack(i)->helper = NULL; | ||
1085 | } | ||
1086 | } | ||
1087 | |||
1088 | void ip_conntrack_helper_unregister(struct ip_conntrack_helper *me) | ||
1089 | { | ||
1090 | unsigned int i; | ||
1091 | struct ip_conntrack_tuple_hash *h; | ||
1092 | struct ip_conntrack_expect *exp, *tmp; | ||
1093 | |||
1094 | /* Need write lock here, to delete helper. */ | ||
1095 | write_lock_bh(&ip_conntrack_lock); | ||
1096 | list_del(&me->list); | ||
1097 | |||
1098 | /* Get rid of expectations */ | ||
1099 | list_for_each_entry_safe(exp, tmp, &ip_conntrack_expect_list, list) { | ||
1100 | if (exp->master->helper == me && del_timer(&exp->timeout)) { | ||
1101 | ip_ct_unlink_expect(exp); | ||
1102 | ip_conntrack_expect_put(exp); | ||
1103 | } | ||
1104 | } | ||
1105 | /* Get rid of expecteds, set helpers to NULL. */ | ||
1106 | list_for_each_entry(h, &unconfirmed, list) | ||
1107 | unhelp(h, me); | ||
1108 | for (i = 0; i < ip_conntrack_htable_size; i++) { | ||
1109 | list_for_each_entry(h, &ip_conntrack_hash[i], list) | ||
1110 | unhelp(h, me); | ||
1111 | } | ||
1112 | write_unlock_bh(&ip_conntrack_lock); | ||
1113 | |||
1114 | /* Someone could be still looking at the helper in a bh. */ | ||
1115 | synchronize_net(); | ||
1116 | } | ||
1117 | |||
1118 | /* Refresh conntrack for this many jiffies and do accounting if do_acct is 1 */ | ||
1119 | void __ip_ct_refresh_acct(struct ip_conntrack *ct, | ||
1120 | enum ip_conntrack_info ctinfo, | ||
1121 | const struct sk_buff *skb, | ||
1122 | unsigned long extra_jiffies, | ||
1123 | int do_acct) | ||
1124 | { | ||
1125 | int event = 0; | ||
1126 | |||
1127 | IP_NF_ASSERT(ct->timeout.data == (unsigned long)ct); | ||
1128 | IP_NF_ASSERT(skb); | ||
1129 | |||
1130 | write_lock_bh(&ip_conntrack_lock); | ||
1131 | |||
1132 | /* Only update if this is not a fixed timeout */ | ||
1133 | if (test_bit(IPS_FIXED_TIMEOUT_BIT, &ct->status)) { | ||
1134 | write_unlock_bh(&ip_conntrack_lock); | ||
1135 | return; | ||
1136 | } | ||
1137 | |||
1138 | /* If not in hash table, timer will not be active yet */ | ||
1139 | if (!is_confirmed(ct)) { | ||
1140 | ct->timeout.expires = extra_jiffies; | ||
1141 | event = IPCT_REFRESH; | ||
1142 | } else { | ||
1143 | /* Need del_timer for race avoidance (may already be dying). */ | ||
1144 | if (del_timer(&ct->timeout)) { | ||
1145 | ct->timeout.expires = jiffies + extra_jiffies; | ||
1146 | add_timer(&ct->timeout); | ||
1147 | event = IPCT_REFRESH; | ||
1148 | } | ||
1149 | } | ||
1150 | |||
1151 | #ifdef CONFIG_IP_NF_CT_ACCT | ||
1152 | if (do_acct) { | ||
1153 | ct->counters[CTINFO2DIR(ctinfo)].packets++; | ||
1154 | ct->counters[CTINFO2DIR(ctinfo)].bytes += | ||
1155 | ntohs(ip_hdr(skb)->tot_len); | ||
1156 | if ((ct->counters[CTINFO2DIR(ctinfo)].packets & 0x80000000) | ||
1157 | || (ct->counters[CTINFO2DIR(ctinfo)].bytes & 0x80000000)) | ||
1158 | event |= IPCT_COUNTER_FILLING; | ||
1159 | } | ||
1160 | #endif | ||
1161 | |||
1162 | write_unlock_bh(&ip_conntrack_lock); | ||
1163 | |||
1164 | /* must be unlocked when calling event cache */ | ||
1165 | if (event) | ||
1166 | ip_conntrack_event_cache(event, skb); | ||
1167 | } | ||
1168 | |||
1169 | #if defined(CONFIG_IP_NF_CONNTRACK_NETLINK) || \ | ||
1170 | defined(CONFIG_IP_NF_CONNTRACK_NETLINK_MODULE) | ||
1171 | /* Generic function for tcp/udp/sctp/dccp and alike. This needs to be | ||
1172 | * in ip_conntrack_core, since we don't want the protocols to autoload | ||
1173 | * or depend on ctnetlink */ | ||
1174 | int ip_ct_port_tuple_to_nfattr(struct sk_buff *skb, | ||
1175 | const struct ip_conntrack_tuple *tuple) | ||
1176 | { | ||
1177 | NFA_PUT(skb, CTA_PROTO_SRC_PORT, sizeof(__be16), | ||
1178 | &tuple->src.u.tcp.port); | ||
1179 | NFA_PUT(skb, CTA_PROTO_DST_PORT, sizeof(__be16), | ||
1180 | &tuple->dst.u.tcp.port); | ||
1181 | return 0; | ||
1182 | |||
1183 | nfattr_failure: | ||
1184 | return -1; | ||
1185 | } | ||
1186 | |||
1187 | int ip_ct_port_nfattr_to_tuple(struct nfattr *tb[], | ||
1188 | struct ip_conntrack_tuple *t) | ||
1189 | { | ||
1190 | if (!tb[CTA_PROTO_SRC_PORT-1] || !tb[CTA_PROTO_DST_PORT-1]) | ||
1191 | return -EINVAL; | ||
1192 | |||
1193 | t->src.u.tcp.port = | ||
1194 | *(__be16 *)NFA_DATA(tb[CTA_PROTO_SRC_PORT-1]); | ||
1195 | t->dst.u.tcp.port = | ||
1196 | *(__be16 *)NFA_DATA(tb[CTA_PROTO_DST_PORT-1]); | ||
1197 | |||
1198 | return 0; | ||
1199 | } | ||
1200 | #endif | ||
1201 | |||
1202 | /* Returns new sk_buff, or NULL */ | ||
1203 | struct sk_buff * | ||
1204 | ip_ct_gather_frags(struct sk_buff *skb, u_int32_t user) | ||
1205 | { | ||
1206 | skb_orphan(skb); | ||
1207 | |||
1208 | local_bh_disable(); | ||
1209 | skb = ip_defrag(skb, user); | ||
1210 | local_bh_enable(); | ||
1211 | |||
1212 | if (skb) | ||
1213 | ip_send_check(ip_hdr(skb)); | ||
1214 | return skb; | ||
1215 | } | ||
1216 | |||
1217 | /* Used by ipt_REJECT. */ | ||
1218 | static void ip_conntrack_attach(struct sk_buff *nskb, struct sk_buff *skb) | ||
1219 | { | ||
1220 | struct ip_conntrack *ct; | ||
1221 | enum ip_conntrack_info ctinfo; | ||
1222 | |||
1223 | /* This ICMP is in reverse direction to the packet which caused it */ | ||
1224 | ct = ip_conntrack_get(skb, &ctinfo); | ||
1225 | |||
1226 | if (CTINFO2DIR(ctinfo) == IP_CT_DIR_ORIGINAL) | ||
1227 | ctinfo = IP_CT_RELATED + IP_CT_IS_REPLY; | ||
1228 | else | ||
1229 | ctinfo = IP_CT_RELATED; | ||
1230 | |||
1231 | /* Attach to new skbuff, and increment count */ | ||
1232 | nskb->nfct = &ct->ct_general; | ||
1233 | nskb->nfctinfo = ctinfo; | ||
1234 | nf_conntrack_get(nskb->nfct); | ||
1235 | } | ||
1236 | |||
1237 | /* Bring out ya dead! */ | ||
1238 | static struct ip_conntrack * | ||
1239 | get_next_corpse(int (*iter)(struct ip_conntrack *i, void *data), | ||
1240 | void *data, unsigned int *bucket) | ||
1241 | { | ||
1242 | struct ip_conntrack_tuple_hash *h; | ||
1243 | struct ip_conntrack *ct; | ||
1244 | |||
1245 | write_lock_bh(&ip_conntrack_lock); | ||
1246 | for (; *bucket < ip_conntrack_htable_size; (*bucket)++) { | ||
1247 | list_for_each_entry(h, &ip_conntrack_hash[*bucket], list) { | ||
1248 | ct = tuplehash_to_ctrack(h); | ||
1249 | if (iter(ct, data)) | ||
1250 | goto found; | ||
1251 | } | ||
1252 | } | ||
1253 | list_for_each_entry(h, &unconfirmed, list) { | ||
1254 | ct = tuplehash_to_ctrack(h); | ||
1255 | if (iter(ct, data)) | ||
1256 | set_bit(IPS_DYING_BIT, &ct->status); | ||
1257 | } | ||
1258 | write_unlock_bh(&ip_conntrack_lock); | ||
1259 | return NULL; | ||
1260 | |||
1261 | found: | ||
1262 | atomic_inc(&ct->ct_general.use); | ||
1263 | write_unlock_bh(&ip_conntrack_lock); | ||
1264 | return ct; | ||
1265 | } | ||
1266 | |||
1267 | void | ||
1268 | ip_ct_iterate_cleanup(int (*iter)(struct ip_conntrack *i, void *), void *data) | ||
1269 | { | ||
1270 | struct ip_conntrack *ct; | ||
1271 | unsigned int bucket = 0; | ||
1272 | |||
1273 | while ((ct = get_next_corpse(iter, data, &bucket)) != NULL) { | ||
1274 | /* Time to push up daises... */ | ||
1275 | if (del_timer(&ct->timeout)) | ||
1276 | death_by_timeout((unsigned long)ct); | ||
1277 | /* ... else the timer will get him soon. */ | ||
1278 | |||
1279 | ip_conntrack_put(ct); | ||
1280 | } | ||
1281 | } | ||
1282 | |||
1283 | /* Fast function for those who don't want to parse /proc (and I don't | ||
1284 | blame them). */ | ||
1285 | /* Reversing the socket's dst/src point of view gives us the reply | ||
1286 | mapping. */ | ||
1287 | static int | ||
1288 | getorigdst(struct sock *sk, int optval, void __user *user, int *len) | ||
1289 | { | ||
1290 | struct inet_sock *inet = inet_sk(sk); | ||
1291 | struct ip_conntrack_tuple_hash *h; | ||
1292 | struct ip_conntrack_tuple tuple; | ||
1293 | |||
1294 | IP_CT_TUPLE_U_BLANK(&tuple); | ||
1295 | tuple.src.ip = inet->rcv_saddr; | ||
1296 | tuple.src.u.tcp.port = inet->sport; | ||
1297 | tuple.dst.ip = inet->daddr; | ||
1298 | tuple.dst.u.tcp.port = inet->dport; | ||
1299 | tuple.dst.protonum = IPPROTO_TCP; | ||
1300 | |||
1301 | /* We only do TCP at the moment: is there a better way? */ | ||
1302 | if (strcmp(sk->sk_prot->name, "TCP")) { | ||
1303 | DEBUGP("SO_ORIGINAL_DST: Not a TCP socket\n"); | ||
1304 | return -ENOPROTOOPT; | ||
1305 | } | ||
1306 | |||
1307 | if ((unsigned int) *len < sizeof(struct sockaddr_in)) { | ||
1308 | DEBUGP("SO_ORIGINAL_DST: len %u not %u\n", | ||
1309 | *len, sizeof(struct sockaddr_in)); | ||
1310 | return -EINVAL; | ||
1311 | } | ||
1312 | |||
1313 | h = ip_conntrack_find_get(&tuple, NULL); | ||
1314 | if (h) { | ||
1315 | struct sockaddr_in sin; | ||
1316 | struct ip_conntrack *ct = tuplehash_to_ctrack(h); | ||
1317 | |||
1318 | sin.sin_family = AF_INET; | ||
1319 | sin.sin_port = ct->tuplehash[IP_CT_DIR_ORIGINAL] | ||
1320 | .tuple.dst.u.tcp.port; | ||
1321 | sin.sin_addr.s_addr = ct->tuplehash[IP_CT_DIR_ORIGINAL] | ||
1322 | .tuple.dst.ip; | ||
1323 | memset(sin.sin_zero, 0, sizeof(sin.sin_zero)); | ||
1324 | |||
1325 | DEBUGP("SO_ORIGINAL_DST: %u.%u.%u.%u %u\n", | ||
1326 | NIPQUAD(sin.sin_addr.s_addr), ntohs(sin.sin_port)); | ||
1327 | ip_conntrack_put(ct); | ||
1328 | if (copy_to_user(user, &sin, sizeof(sin)) != 0) | ||
1329 | return -EFAULT; | ||
1330 | else | ||
1331 | return 0; | ||
1332 | } | ||
1333 | DEBUGP("SO_ORIGINAL_DST: Can't find %u.%u.%u.%u/%u-%u.%u.%u.%u/%u.\n", | ||
1334 | NIPQUAD(tuple.src.ip), ntohs(tuple.src.u.tcp.port), | ||
1335 | NIPQUAD(tuple.dst.ip), ntohs(tuple.dst.u.tcp.port)); | ||
1336 | return -ENOENT; | ||
1337 | } | ||
1338 | |||
1339 | static struct nf_sockopt_ops so_getorigdst = { | ||
1340 | .pf = PF_INET, | ||
1341 | .get_optmin = SO_ORIGINAL_DST, | ||
1342 | .get_optmax = SO_ORIGINAL_DST+1, | ||
1343 | .get = &getorigdst, | ||
1344 | }; | ||
1345 | |||
1346 | static int kill_all(struct ip_conntrack *i, void *data) | ||
1347 | { | ||
1348 | return 1; | ||
1349 | } | ||
1350 | |||
1351 | void ip_conntrack_flush(void) | ||
1352 | { | ||
1353 | ip_ct_iterate_cleanup(kill_all, NULL); | ||
1354 | } | ||
1355 | |||
1356 | static void free_conntrack_hash(struct list_head *hash, int vmalloced,int size) | ||
1357 | { | ||
1358 | if (vmalloced) | ||
1359 | vfree(hash); | ||
1360 | else | ||
1361 | free_pages((unsigned long)hash, | ||
1362 | get_order(sizeof(struct list_head) * size)); | ||
1363 | } | ||
1364 | |||
1365 | /* Mishearing the voices in his head, our hero wonders how he's | ||
1366 | supposed to kill the mall. */ | ||
1367 | void ip_conntrack_cleanup(void) | ||
1368 | { | ||
1369 | rcu_assign_pointer(ip_ct_attach, NULL); | ||
1370 | |||
1371 | /* This makes sure all current packets have passed through | ||
1372 | netfilter framework. Roll on, two-stage module | ||
1373 | delete... */ | ||
1374 | synchronize_net(); | ||
1375 | |||
1376 | ip_ct_event_cache_flush(); | ||
1377 | i_see_dead_people: | ||
1378 | ip_conntrack_flush(); | ||
1379 | if (atomic_read(&ip_conntrack_count) != 0) { | ||
1380 | schedule(); | ||
1381 | goto i_see_dead_people; | ||
1382 | } | ||
1383 | /* wait until all references to ip_conntrack_untracked are dropped */ | ||
1384 | while (atomic_read(&ip_conntrack_untracked.ct_general.use) > 1) | ||
1385 | schedule(); | ||
1386 | |||
1387 | kmem_cache_destroy(ip_conntrack_cachep); | ||
1388 | kmem_cache_destroy(ip_conntrack_expect_cachep); | ||
1389 | free_conntrack_hash(ip_conntrack_hash, ip_conntrack_vmalloc, | ||
1390 | ip_conntrack_htable_size); | ||
1391 | nf_unregister_sockopt(&so_getorigdst); | ||
1392 | } | ||
1393 | |||
1394 | static struct list_head *alloc_hashtable(int size, int *vmalloced) | ||
1395 | { | ||
1396 | struct list_head *hash; | ||
1397 | unsigned int i; | ||
1398 | |||
1399 | *vmalloced = 0; | ||
1400 | hash = (void*)__get_free_pages(GFP_KERNEL, | ||
1401 | get_order(sizeof(struct list_head) | ||
1402 | * size)); | ||
1403 | if (!hash) { | ||
1404 | *vmalloced = 1; | ||
1405 | printk(KERN_WARNING"ip_conntrack: falling back to vmalloc.\n"); | ||
1406 | hash = vmalloc(sizeof(struct list_head) * size); | ||
1407 | } | ||
1408 | |||
1409 | if (hash) | ||
1410 | for (i = 0; i < size; i++) | ||
1411 | INIT_LIST_HEAD(&hash[i]); | ||
1412 | |||
1413 | return hash; | ||
1414 | } | ||
1415 | |||
1416 | static int set_hashsize(const char *val, struct kernel_param *kp) | ||
1417 | { | ||
1418 | int i, bucket, hashsize, vmalloced; | ||
1419 | int old_vmalloced, old_size; | ||
1420 | int rnd; | ||
1421 | struct list_head *hash, *old_hash; | ||
1422 | struct ip_conntrack_tuple_hash *h; | ||
1423 | |||
1424 | /* On boot, we can set this without any fancy locking. */ | ||
1425 | if (!ip_conntrack_htable_size) | ||
1426 | return param_set_int(val, kp); | ||
1427 | |||
1428 | hashsize = simple_strtol(val, NULL, 0); | ||
1429 | if (!hashsize) | ||
1430 | return -EINVAL; | ||
1431 | |||
1432 | hash = alloc_hashtable(hashsize, &vmalloced); | ||
1433 | if (!hash) | ||
1434 | return -ENOMEM; | ||
1435 | |||
1436 | /* We have to rehash for the new table anyway, so we also can | ||
1437 | * use a new random seed */ | ||
1438 | get_random_bytes(&rnd, 4); | ||
1439 | |||
1440 | write_lock_bh(&ip_conntrack_lock); | ||
1441 | for (i = 0; i < ip_conntrack_htable_size; i++) { | ||
1442 | while (!list_empty(&ip_conntrack_hash[i])) { | ||
1443 | h = list_entry(ip_conntrack_hash[i].next, | ||
1444 | struct ip_conntrack_tuple_hash, list); | ||
1445 | list_del(&h->list); | ||
1446 | bucket = __hash_conntrack(&h->tuple, hashsize, rnd); | ||
1447 | list_add_tail(&h->list, &hash[bucket]); | ||
1448 | } | ||
1449 | } | ||
1450 | old_size = ip_conntrack_htable_size; | ||
1451 | old_vmalloced = ip_conntrack_vmalloc; | ||
1452 | old_hash = ip_conntrack_hash; | ||
1453 | |||
1454 | ip_conntrack_htable_size = hashsize; | ||
1455 | ip_conntrack_vmalloc = vmalloced; | ||
1456 | ip_conntrack_hash = hash; | ||
1457 | ip_conntrack_hash_rnd = rnd; | ||
1458 | write_unlock_bh(&ip_conntrack_lock); | ||
1459 | |||
1460 | free_conntrack_hash(old_hash, old_vmalloced, old_size); | ||
1461 | return 0; | ||
1462 | } | ||
1463 | |||
1464 | module_param_call(hashsize, set_hashsize, param_get_uint, | ||
1465 | &ip_conntrack_htable_size, 0600); | ||
1466 | |||
1467 | int __init ip_conntrack_init(void) | ||
1468 | { | ||
1469 | unsigned int i; | ||
1470 | int ret; | ||
1471 | |||
1472 | /* Idea from tcp.c: use 1/16384 of memory. On i386: 32MB | ||
1473 | * machine has 256 buckets. >= 1GB machines have 8192 buckets. */ | ||
1474 | if (!ip_conntrack_htable_size) { | ||
1475 | ip_conntrack_htable_size | ||
1476 | = (((num_physpages << PAGE_SHIFT) / 16384) | ||
1477 | / sizeof(struct list_head)); | ||
1478 | if (num_physpages > (1024 * 1024 * 1024 / PAGE_SIZE)) | ||
1479 | ip_conntrack_htable_size = 8192; | ||
1480 | if (ip_conntrack_htable_size < 16) | ||
1481 | ip_conntrack_htable_size = 16; | ||
1482 | } | ||
1483 | ip_conntrack_max = 8 * ip_conntrack_htable_size; | ||
1484 | |||
1485 | printk("ip_conntrack version %s (%u buckets, %d max)" | ||
1486 | " - %Zd bytes per conntrack\n", IP_CONNTRACK_VERSION, | ||
1487 | ip_conntrack_htable_size, ip_conntrack_max, | ||
1488 | sizeof(struct ip_conntrack)); | ||
1489 | |||
1490 | ret = nf_register_sockopt(&so_getorigdst); | ||
1491 | if (ret != 0) { | ||
1492 | printk(KERN_ERR "Unable to register netfilter socket option\n"); | ||
1493 | return ret; | ||
1494 | } | ||
1495 | |||
1496 | ip_conntrack_hash = alloc_hashtable(ip_conntrack_htable_size, | ||
1497 | &ip_conntrack_vmalloc); | ||
1498 | if (!ip_conntrack_hash) { | ||
1499 | printk(KERN_ERR "Unable to create ip_conntrack_hash\n"); | ||
1500 | goto err_unreg_sockopt; | ||
1501 | } | ||
1502 | |||
1503 | ip_conntrack_cachep = kmem_cache_create("ip_conntrack", | ||
1504 | sizeof(struct ip_conntrack), 0, | ||
1505 | 0, NULL, NULL); | ||
1506 | if (!ip_conntrack_cachep) { | ||
1507 | printk(KERN_ERR "Unable to create ip_conntrack slab cache\n"); | ||
1508 | goto err_free_hash; | ||
1509 | } | ||
1510 | |||
1511 | ip_conntrack_expect_cachep = kmem_cache_create("ip_conntrack_expect", | ||
1512 | sizeof(struct ip_conntrack_expect), | ||
1513 | 0, 0, NULL, NULL); | ||
1514 | if (!ip_conntrack_expect_cachep) { | ||
1515 | printk(KERN_ERR "Unable to create ip_expect slab cache\n"); | ||
1516 | goto err_free_conntrack_slab; | ||
1517 | } | ||
1518 | |||
1519 | /* Don't NEED lock here, but good form anyway. */ | ||
1520 | write_lock_bh(&ip_conntrack_lock); | ||
1521 | for (i = 0; i < MAX_IP_CT_PROTO; i++) | ||
1522 | rcu_assign_pointer(ip_ct_protos[i], &ip_conntrack_generic_protocol); | ||
1523 | /* Sew in builtin protocols. */ | ||
1524 | rcu_assign_pointer(ip_ct_protos[IPPROTO_TCP], &ip_conntrack_protocol_tcp); | ||
1525 | rcu_assign_pointer(ip_ct_protos[IPPROTO_UDP], &ip_conntrack_protocol_udp); | ||
1526 | rcu_assign_pointer(ip_ct_protos[IPPROTO_ICMP], &ip_conntrack_protocol_icmp); | ||
1527 | write_unlock_bh(&ip_conntrack_lock); | ||
1528 | |||
1529 | /* For use by ipt_REJECT */ | ||
1530 | rcu_assign_pointer(ip_ct_attach, ip_conntrack_attach); | ||
1531 | |||
1532 | /* Set up fake conntrack: | ||
1533 | - to never be deleted, not in any hashes */ | ||
1534 | atomic_set(&ip_conntrack_untracked.ct_general.use, 1); | ||
1535 | /* - and look it like as a confirmed connection */ | ||
1536 | set_bit(IPS_CONFIRMED_BIT, &ip_conntrack_untracked.status); | ||
1537 | |||
1538 | return ret; | ||
1539 | |||
1540 | err_free_conntrack_slab: | ||
1541 | kmem_cache_destroy(ip_conntrack_cachep); | ||
1542 | err_free_hash: | ||
1543 | free_conntrack_hash(ip_conntrack_hash, ip_conntrack_vmalloc, | ||
1544 | ip_conntrack_htable_size); | ||
1545 | err_unreg_sockopt: | ||
1546 | nf_unregister_sockopt(&so_getorigdst); | ||
1547 | |||
1548 | return -ENOMEM; | ||
1549 | } | ||
diff --git a/net/ipv4/netfilter/ip_conntrack_ftp.c b/net/ipv4/netfilter/ip_conntrack_ftp.c deleted file mode 100644 index 92389987e789..000000000000 --- a/net/ipv4/netfilter/ip_conntrack_ftp.c +++ /dev/null | |||
@@ -1,520 +0,0 @@ | |||
1 | /* FTP extension for IP connection tracking. */ | ||
2 | |||
3 | /* (C) 1999-2001 Paul `Rusty' Russell | ||
4 | * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | */ | ||
10 | |||
11 | #include <linux/module.h> | ||
12 | #include <linux/netfilter.h> | ||
13 | #include <linux/ip.h> | ||
14 | #include <linux/ctype.h> | ||
15 | #include <net/checksum.h> | ||
16 | #include <net/tcp.h> | ||
17 | |||
18 | #include <linux/netfilter_ipv4/ip_conntrack_helper.h> | ||
19 | #include <linux/netfilter_ipv4/ip_conntrack_ftp.h> | ||
20 | #include <linux/moduleparam.h> | ||
21 | |||
22 | MODULE_LICENSE("GPL"); | ||
23 | MODULE_AUTHOR("Rusty Russell <rusty@rustcorp.com.au>"); | ||
24 | MODULE_DESCRIPTION("ftp connection tracking helper"); | ||
25 | |||
26 | /* This is slow, but it's simple. --RR */ | ||
27 | static char *ftp_buffer; | ||
28 | static DEFINE_SPINLOCK(ip_ftp_lock); | ||
29 | |||
30 | #define MAX_PORTS 8 | ||
31 | static unsigned short ports[MAX_PORTS]; | ||
32 | static int ports_c; | ||
33 | module_param_array(ports, ushort, &ports_c, 0400); | ||
34 | |||
35 | static int loose; | ||
36 | module_param(loose, bool, 0600); | ||
37 | |||
38 | unsigned int (*ip_nat_ftp_hook)(struct sk_buff **pskb, | ||
39 | enum ip_conntrack_info ctinfo, | ||
40 | enum ip_ct_ftp_type type, | ||
41 | unsigned int matchoff, | ||
42 | unsigned int matchlen, | ||
43 | struct ip_conntrack_expect *exp, | ||
44 | u32 *seq); | ||
45 | EXPORT_SYMBOL_GPL(ip_nat_ftp_hook); | ||
46 | |||
47 | #if 0 | ||
48 | #define DEBUGP printk | ||
49 | #else | ||
50 | #define DEBUGP(format, args...) | ||
51 | #endif | ||
52 | |||
53 | static int try_rfc959(const char *, size_t, u_int32_t [], char); | ||
54 | static int try_eprt(const char *, size_t, u_int32_t [], char); | ||
55 | static int try_epsv_response(const char *, size_t, u_int32_t [], char); | ||
56 | |||
57 | static const struct ftp_search { | ||
58 | const char *pattern; | ||
59 | size_t plen; | ||
60 | char skip; | ||
61 | char term; | ||
62 | enum ip_ct_ftp_type ftptype; | ||
63 | int (*getnum)(const char *, size_t, u_int32_t[], char); | ||
64 | } search[IP_CT_DIR_MAX][2] = { | ||
65 | [IP_CT_DIR_ORIGINAL] = { | ||
66 | { | ||
67 | .pattern = "PORT", | ||
68 | .plen = sizeof("PORT") - 1, | ||
69 | .skip = ' ', | ||
70 | .term = '\r', | ||
71 | .ftptype = IP_CT_FTP_PORT, | ||
72 | .getnum = try_rfc959, | ||
73 | }, | ||
74 | { | ||
75 | .pattern = "EPRT", | ||
76 | .plen = sizeof("EPRT") - 1, | ||
77 | .skip = ' ', | ||
78 | .term = '\r', | ||
79 | .ftptype = IP_CT_FTP_EPRT, | ||
80 | .getnum = try_eprt, | ||
81 | }, | ||
82 | }, | ||
83 | [IP_CT_DIR_REPLY] = { | ||
84 | { | ||
85 | .pattern = "227 ", | ||
86 | .plen = sizeof("227 ") - 1, | ||
87 | .skip = '(', | ||
88 | .term = ')', | ||
89 | .ftptype = IP_CT_FTP_PASV, | ||
90 | .getnum = try_rfc959, | ||
91 | }, | ||
92 | { | ||
93 | .pattern = "229 ", | ||
94 | .plen = sizeof("229 ") - 1, | ||
95 | .skip = '(', | ||
96 | .term = ')', | ||
97 | .ftptype = IP_CT_FTP_EPSV, | ||
98 | .getnum = try_epsv_response, | ||
99 | }, | ||
100 | }, | ||
101 | }; | ||
102 | |||
103 | static int try_number(const char *data, size_t dlen, u_int32_t array[], | ||
104 | int array_size, char sep, char term) | ||
105 | { | ||
106 | u_int32_t i, len; | ||
107 | |||
108 | memset(array, 0, sizeof(array[0])*array_size); | ||
109 | |||
110 | /* Keep data pointing at next char. */ | ||
111 | for (i = 0, len = 0; len < dlen && i < array_size; len++, data++) { | ||
112 | if (*data >= '0' && *data <= '9') { | ||
113 | array[i] = array[i]*10 + *data - '0'; | ||
114 | } | ||
115 | else if (*data == sep) | ||
116 | i++; | ||
117 | else { | ||
118 | /* Unexpected character; true if it's the | ||
119 | terminator and we're finished. */ | ||
120 | if (*data == term && i == array_size - 1) | ||
121 | return len; | ||
122 | |||
123 | DEBUGP("Char %u (got %u nums) `%u' unexpected\n", | ||
124 | len, i, *data); | ||
125 | return 0; | ||
126 | } | ||
127 | } | ||
128 | DEBUGP("Failed to fill %u numbers separated by %c\n", array_size, sep); | ||
129 | |||
130 | return 0; | ||
131 | } | ||
132 | |||
133 | /* Returns 0, or length of numbers: 192,168,1,1,5,6 */ | ||
134 | static int try_rfc959(const char *data, size_t dlen, u_int32_t array[6], | ||
135 | char term) | ||
136 | { | ||
137 | return try_number(data, dlen, array, 6, ',', term); | ||
138 | } | ||
139 | |||
140 | /* Grab port: number up to delimiter */ | ||
141 | static int get_port(const char *data, int start, size_t dlen, char delim, | ||
142 | u_int32_t array[2]) | ||
143 | { | ||
144 | u_int16_t port = 0; | ||
145 | int i; | ||
146 | |||
147 | for (i = start; i < dlen; i++) { | ||
148 | /* Finished? */ | ||
149 | if (data[i] == delim) { | ||
150 | if (port == 0) | ||
151 | break; | ||
152 | array[0] = port >> 8; | ||
153 | array[1] = port; | ||
154 | return i + 1; | ||
155 | } | ||
156 | else if (data[i] >= '0' && data[i] <= '9') | ||
157 | port = port*10 + data[i] - '0'; | ||
158 | else /* Some other crap */ | ||
159 | break; | ||
160 | } | ||
161 | return 0; | ||
162 | } | ||
163 | |||
164 | /* Returns 0, or length of numbers: |1|132.235.1.2|6275| */ | ||
165 | static int try_eprt(const char *data, size_t dlen, u_int32_t array[6], | ||
166 | char term) | ||
167 | { | ||
168 | char delim; | ||
169 | int length; | ||
170 | |||
171 | /* First character is delimiter, then "1" for IPv4, then | ||
172 | delimiter again. */ | ||
173 | if (dlen <= 3) return 0; | ||
174 | delim = data[0]; | ||
175 | if (isdigit(delim) || delim < 33 || delim > 126 | ||
176 | || data[1] != '1' || data[2] != delim) | ||
177 | return 0; | ||
178 | |||
179 | DEBUGP("EPRT: Got |1|!\n"); | ||
180 | /* Now we have IP address. */ | ||
181 | length = try_number(data + 3, dlen - 3, array, 4, '.', delim); | ||
182 | if (length == 0) | ||
183 | return 0; | ||
184 | |||
185 | DEBUGP("EPRT: Got IP address!\n"); | ||
186 | /* Start offset includes initial "|1|", and trailing delimiter */ | ||
187 | return get_port(data, 3 + length + 1, dlen, delim, array+4); | ||
188 | } | ||
189 | |||
190 | /* Returns 0, or length of numbers: |||6446| */ | ||
191 | static int try_epsv_response(const char *data, size_t dlen, u_int32_t array[6], | ||
192 | char term) | ||
193 | { | ||
194 | char delim; | ||
195 | |||
196 | /* Three delimiters. */ | ||
197 | if (dlen <= 3) return 0; | ||
198 | delim = data[0]; | ||
199 | if (isdigit(delim) || delim < 33 || delim > 126 | ||
200 | || data[1] != delim || data[2] != delim) | ||
201 | return 0; | ||
202 | |||
203 | return get_port(data, 3, dlen, delim, array+4); | ||
204 | } | ||
205 | |||
206 | /* Return 1 for match, 0 for accept, -1 for partial. */ | ||
207 | static int find_pattern(const char *data, size_t dlen, | ||
208 | const char *pattern, size_t plen, | ||
209 | char skip, char term, | ||
210 | unsigned int *numoff, | ||
211 | unsigned int *numlen, | ||
212 | u_int32_t array[6], | ||
213 | int (*getnum)(const char *, size_t, u_int32_t[], char)) | ||
214 | { | ||
215 | size_t i; | ||
216 | |||
217 | DEBUGP("find_pattern `%s': dlen = %u\n", pattern, dlen); | ||
218 | if (dlen == 0) | ||
219 | return 0; | ||
220 | |||
221 | if (dlen <= plen) { | ||
222 | /* Short packet: try for partial? */ | ||
223 | if (strnicmp(data, pattern, dlen) == 0) | ||
224 | return -1; | ||
225 | else return 0; | ||
226 | } | ||
227 | |||
228 | if (strnicmp(data, pattern, plen) != 0) { | ||
229 | #if 0 | ||
230 | size_t i; | ||
231 | |||
232 | DEBUGP("ftp: string mismatch\n"); | ||
233 | for (i = 0; i < plen; i++) { | ||
234 | DEBUGP("ftp:char %u `%c'(%u) vs `%c'(%u)\n", | ||
235 | i, data[i], data[i], | ||
236 | pattern[i], pattern[i]); | ||
237 | } | ||
238 | #endif | ||
239 | return 0; | ||
240 | } | ||
241 | |||
242 | DEBUGP("Pattern matches!\n"); | ||
243 | /* Now we've found the constant string, try to skip | ||
244 | to the 'skip' character */ | ||
245 | for (i = plen; data[i] != skip; i++) | ||
246 | if (i == dlen - 1) return -1; | ||
247 | |||
248 | /* Skip over the last character */ | ||
249 | i++; | ||
250 | |||
251 | DEBUGP("Skipped up to `%c'!\n", skip); | ||
252 | |||
253 | *numoff = i; | ||
254 | *numlen = getnum(data + i, dlen - i, array, term); | ||
255 | if (!*numlen) | ||
256 | return -1; | ||
257 | |||
258 | DEBUGP("Match succeeded!\n"); | ||
259 | return 1; | ||
260 | } | ||
261 | |||
262 | /* Look up to see if we're just after a \n. */ | ||
263 | static int find_nl_seq(u32 seq, const struct ip_ct_ftp_master *info, int dir) | ||
264 | { | ||
265 | unsigned int i; | ||
266 | |||
267 | for (i = 0; i < info->seq_aft_nl_num[dir]; i++) | ||
268 | if (info->seq_aft_nl[dir][i] == seq) | ||
269 | return 1; | ||
270 | return 0; | ||
271 | } | ||
272 | |||
273 | /* We don't update if it's older than what we have. */ | ||
274 | static void update_nl_seq(u32 nl_seq, struct ip_ct_ftp_master *info, int dir, | ||
275 | struct sk_buff *skb) | ||
276 | { | ||
277 | unsigned int i, oldest = NUM_SEQ_TO_REMEMBER; | ||
278 | |||
279 | /* Look for oldest: if we find exact match, we're done. */ | ||
280 | for (i = 0; i < info->seq_aft_nl_num[dir]; i++) { | ||
281 | if (info->seq_aft_nl[dir][i] == nl_seq) | ||
282 | return; | ||
283 | |||
284 | if (oldest == info->seq_aft_nl_num[dir] | ||
285 | || before(info->seq_aft_nl[dir][i], oldest)) | ||
286 | oldest = i; | ||
287 | } | ||
288 | |||
289 | if (info->seq_aft_nl_num[dir] < NUM_SEQ_TO_REMEMBER) { | ||
290 | info->seq_aft_nl[dir][info->seq_aft_nl_num[dir]++] = nl_seq; | ||
291 | ip_conntrack_event_cache(IPCT_HELPINFO_VOLATILE, skb); | ||
292 | } else if (oldest != NUM_SEQ_TO_REMEMBER) { | ||
293 | info->seq_aft_nl[dir][oldest] = nl_seq; | ||
294 | ip_conntrack_event_cache(IPCT_HELPINFO_VOLATILE, skb); | ||
295 | } | ||
296 | } | ||
297 | |||
298 | static int help(struct sk_buff **pskb, | ||
299 | struct ip_conntrack *ct, | ||
300 | enum ip_conntrack_info ctinfo) | ||
301 | { | ||
302 | unsigned int dataoff, datalen; | ||
303 | struct tcphdr _tcph, *th; | ||
304 | char *fb_ptr; | ||
305 | int ret; | ||
306 | u32 seq, array[6] = { 0 }; | ||
307 | int dir = CTINFO2DIR(ctinfo); | ||
308 | unsigned int matchlen, matchoff; | ||
309 | struct ip_ct_ftp_master *ct_ftp_info = &ct->help.ct_ftp_info; | ||
310 | struct ip_conntrack_expect *exp; | ||
311 | unsigned int i; | ||
312 | int found = 0, ends_in_nl; | ||
313 | typeof(ip_nat_ftp_hook) ip_nat_ftp; | ||
314 | |||
315 | /* Until there's been traffic both ways, don't look in packets. */ | ||
316 | if (ctinfo != IP_CT_ESTABLISHED | ||
317 | && ctinfo != IP_CT_ESTABLISHED+IP_CT_IS_REPLY) { | ||
318 | DEBUGP("ftp: Conntrackinfo = %u\n", ctinfo); | ||
319 | return NF_ACCEPT; | ||
320 | } | ||
321 | |||
322 | th = skb_header_pointer(*pskb, ip_hdrlen(*pskb), | ||
323 | sizeof(_tcph), &_tcph); | ||
324 | if (th == NULL) | ||
325 | return NF_ACCEPT; | ||
326 | |||
327 | dataoff = ip_hdrlen(*pskb) + th->doff * 4; | ||
328 | /* No data? */ | ||
329 | if (dataoff >= (*pskb)->len) { | ||
330 | DEBUGP("ftp: pskblen = %u\n", (*pskb)->len); | ||
331 | return NF_ACCEPT; | ||
332 | } | ||
333 | datalen = (*pskb)->len - dataoff; | ||
334 | |||
335 | spin_lock_bh(&ip_ftp_lock); | ||
336 | fb_ptr = skb_header_pointer(*pskb, dataoff, | ||
337 | (*pskb)->len - dataoff, ftp_buffer); | ||
338 | BUG_ON(fb_ptr == NULL); | ||
339 | |||
340 | ends_in_nl = (fb_ptr[datalen - 1] == '\n'); | ||
341 | seq = ntohl(th->seq) + datalen; | ||
342 | |||
343 | /* Look up to see if we're just after a \n. */ | ||
344 | if (!find_nl_seq(ntohl(th->seq), ct_ftp_info, dir)) { | ||
345 | /* Now if this ends in \n, update ftp info. */ | ||
346 | DEBUGP("ip_conntrack_ftp_help: wrong seq pos %s(%u) or %s(%u)\n", | ||
347 | ct_ftp_info->seq_aft_nl[0][dir] | ||
348 | old_seq_aft_nl_set ? "":"(UNSET) ", old_seq_aft_nl); | ||
349 | ret = NF_ACCEPT; | ||
350 | goto out_update_nl; | ||
351 | } | ||
352 | |||
353 | /* Initialize IP array to expected address (it's not mentioned | ||
354 | in EPSV responses) */ | ||
355 | array[0] = (ntohl(ct->tuplehash[dir].tuple.src.ip) >> 24) & 0xFF; | ||
356 | array[1] = (ntohl(ct->tuplehash[dir].tuple.src.ip) >> 16) & 0xFF; | ||
357 | array[2] = (ntohl(ct->tuplehash[dir].tuple.src.ip) >> 8) & 0xFF; | ||
358 | array[3] = ntohl(ct->tuplehash[dir].tuple.src.ip) & 0xFF; | ||
359 | |||
360 | for (i = 0; i < ARRAY_SIZE(search[dir]); i++) { | ||
361 | found = find_pattern(fb_ptr, (*pskb)->len - dataoff, | ||
362 | search[dir][i].pattern, | ||
363 | search[dir][i].plen, | ||
364 | search[dir][i].skip, | ||
365 | search[dir][i].term, | ||
366 | &matchoff, &matchlen, | ||
367 | array, | ||
368 | search[dir][i].getnum); | ||
369 | if (found) break; | ||
370 | } | ||
371 | if (found == -1) { | ||
372 | /* We don't usually drop packets. After all, this is | ||
373 | connection tracking, not packet filtering. | ||
374 | However, it is necessary for accurate tracking in | ||
375 | this case. */ | ||
376 | if (net_ratelimit()) | ||
377 | printk("conntrack_ftp: partial %s %u+%u\n", | ||
378 | search[dir][i].pattern, | ||
379 | ntohl(th->seq), datalen); | ||
380 | ret = NF_DROP; | ||
381 | goto out; | ||
382 | } else if (found == 0) { /* No match */ | ||
383 | ret = NF_ACCEPT; | ||
384 | goto out_update_nl; | ||
385 | } | ||
386 | |||
387 | DEBUGP("conntrack_ftp: match `%s' (%u bytes at %u)\n", | ||
388 | fb_ptr + matchoff, matchlen, ntohl(th->seq) + matchoff); | ||
389 | |||
390 | /* Allocate expectation which will be inserted */ | ||
391 | exp = ip_conntrack_expect_alloc(ct); | ||
392 | if (exp == NULL) { | ||
393 | ret = NF_DROP; | ||
394 | goto out; | ||
395 | } | ||
396 | |||
397 | /* We refer to the reverse direction ("!dir") tuples here, | ||
398 | * because we're expecting something in the other direction. | ||
399 | * Doesn't matter unless NAT is happening. */ | ||
400 | exp->tuple.dst.ip = ct->tuplehash[!dir].tuple.dst.ip; | ||
401 | |||
402 | if (htonl((array[0] << 24) | (array[1] << 16) | (array[2] << 8) | array[3]) | ||
403 | != ct->tuplehash[dir].tuple.src.ip) { | ||
404 | /* Enrico Scholz's passive FTP to partially RNAT'd ftp | ||
405 | server: it really wants us to connect to a | ||
406 | different IP address. Simply don't record it for | ||
407 | NAT. */ | ||
408 | DEBUGP("conntrack_ftp: NOT RECORDING: %u,%u,%u,%u != %u.%u.%u.%u\n", | ||
409 | array[0], array[1], array[2], array[3], | ||
410 | NIPQUAD(ct->tuplehash[dir].tuple.src.ip)); | ||
411 | |||
412 | /* Thanks to Cristiano Lincoln Mattos | ||
413 | <lincoln@cesar.org.br> for reporting this potential | ||
414 | problem (DMZ machines opening holes to internal | ||
415 | networks, or the packet filter itself). */ | ||
416 | if (!loose) { | ||
417 | ret = NF_ACCEPT; | ||
418 | goto out_put_expect; | ||
419 | } | ||
420 | exp->tuple.dst.ip = htonl((array[0] << 24) | (array[1] << 16) | ||
421 | | (array[2] << 8) | array[3]); | ||
422 | } | ||
423 | |||
424 | exp->tuple.src.ip = ct->tuplehash[!dir].tuple.src.ip; | ||
425 | exp->tuple.dst.u.tcp.port = htons(array[4] << 8 | array[5]); | ||
426 | exp->tuple.src.u.tcp.port = 0; /* Don't care. */ | ||
427 | exp->tuple.dst.protonum = IPPROTO_TCP; | ||
428 | exp->mask = ((struct ip_conntrack_tuple) | ||
429 | { { htonl(0xFFFFFFFF), { 0 } }, | ||
430 | { htonl(0xFFFFFFFF), { .tcp = { htons(0xFFFF) } }, 0xFF }}); | ||
431 | |||
432 | exp->expectfn = NULL; | ||
433 | exp->flags = 0; | ||
434 | |||
435 | /* Now, NAT might want to mangle the packet, and register the | ||
436 | * (possibly changed) expectation itself. */ | ||
437 | ip_nat_ftp = rcu_dereference(ip_nat_ftp_hook); | ||
438 | if (ip_nat_ftp) | ||
439 | ret = ip_nat_ftp(pskb, ctinfo, search[dir][i].ftptype, | ||
440 | matchoff, matchlen, exp, &seq); | ||
441 | else { | ||
442 | /* Can't expect this? Best to drop packet now. */ | ||
443 | if (ip_conntrack_expect_related(exp) != 0) | ||
444 | ret = NF_DROP; | ||
445 | else | ||
446 | ret = NF_ACCEPT; | ||
447 | } | ||
448 | |||
449 | out_put_expect: | ||
450 | ip_conntrack_expect_put(exp); | ||
451 | |||
452 | out_update_nl: | ||
453 | /* Now if this ends in \n, update ftp info. Seq may have been | ||
454 | * adjusted by NAT code. */ | ||
455 | if (ends_in_nl) | ||
456 | update_nl_seq(seq, ct_ftp_info,dir, *pskb); | ||
457 | out: | ||
458 | spin_unlock_bh(&ip_ftp_lock); | ||
459 | return ret; | ||
460 | } | ||
461 | |||
462 | static struct ip_conntrack_helper ftp[MAX_PORTS]; | ||
463 | static char ftp_names[MAX_PORTS][sizeof("ftp-65535")]; | ||
464 | |||
465 | /* Not __exit: called from init() */ | ||
466 | static void ip_conntrack_ftp_fini(void) | ||
467 | { | ||
468 | int i; | ||
469 | for (i = 0; i < ports_c; i++) { | ||
470 | DEBUGP("ip_ct_ftp: unregistering helper for port %d\n", | ||
471 | ports[i]); | ||
472 | ip_conntrack_helper_unregister(&ftp[i]); | ||
473 | } | ||
474 | |||
475 | kfree(ftp_buffer); | ||
476 | } | ||
477 | |||
478 | static int __init ip_conntrack_ftp_init(void) | ||
479 | { | ||
480 | int i, ret; | ||
481 | char *tmpname; | ||
482 | |||
483 | ftp_buffer = kmalloc(65536, GFP_KERNEL); | ||
484 | if (!ftp_buffer) | ||
485 | return -ENOMEM; | ||
486 | |||
487 | if (ports_c == 0) | ||
488 | ports[ports_c++] = FTP_PORT; | ||
489 | |||
490 | for (i = 0; i < ports_c; i++) { | ||
491 | ftp[i].tuple.src.u.tcp.port = htons(ports[i]); | ||
492 | ftp[i].tuple.dst.protonum = IPPROTO_TCP; | ||
493 | ftp[i].mask.src.u.tcp.port = htons(0xFFFF); | ||
494 | ftp[i].mask.dst.protonum = 0xFF; | ||
495 | ftp[i].max_expected = 1; | ||
496 | ftp[i].timeout = 5 * 60; /* 5 minutes */ | ||
497 | ftp[i].me = THIS_MODULE; | ||
498 | ftp[i].help = help; | ||
499 | |||
500 | tmpname = &ftp_names[i][0]; | ||
501 | if (ports[i] == FTP_PORT) | ||
502 | sprintf(tmpname, "ftp"); | ||
503 | else | ||
504 | sprintf(tmpname, "ftp-%d", ports[i]); | ||
505 | ftp[i].name = tmpname; | ||
506 | |||
507 | DEBUGP("ip_ct_ftp: registering helper for port %d\n", | ||
508 | ports[i]); | ||
509 | ret = ip_conntrack_helper_register(&ftp[i]); | ||
510 | |||
511 | if (ret) { | ||
512 | ip_conntrack_ftp_fini(); | ||
513 | return ret; | ||
514 | } | ||
515 | } | ||
516 | return 0; | ||
517 | } | ||
518 | |||
519 | module_init(ip_conntrack_ftp_init); | ||
520 | module_exit(ip_conntrack_ftp_fini); | ||
diff --git a/net/ipv4/netfilter/ip_conntrack_helper_h323.c b/net/ipv4/netfilter/ip_conntrack_helper_h323.c deleted file mode 100644 index cecb6e0c8ed0..000000000000 --- a/net/ipv4/netfilter/ip_conntrack_helper_h323.c +++ /dev/null | |||
@@ -1,1840 +0,0 @@ | |||
1 | /* | ||
2 | * H.323 connection tracking helper | ||
3 | * | ||
4 | * Copyright (c) 2006 Jing Min Zhao <zhaojingmin@users.sourceforge.net> | ||
5 | * | ||
6 | * This source code is licensed under General Public License version 2. | ||
7 | * | ||
8 | * Based on the 'brute force' H.323 connection tracking module by | ||
9 | * Jozsef Kadlecsik <kadlec@blackhole.kfki.hu> | ||
10 | * | ||
11 | * For more information, please see http://nath323.sourceforge.net/ | ||
12 | */ | ||
13 | |||
14 | #include <linux/module.h> | ||
15 | #include <linux/netfilter.h> | ||
16 | #include <linux/ip.h> | ||
17 | #include <net/tcp.h> | ||
18 | #include <linux/netfilter_ipv4/ip_conntrack.h> | ||
19 | #include <linux/netfilter_ipv4/ip_conntrack_core.h> | ||
20 | #include <linux/netfilter_ipv4/ip_conntrack_helper.h> | ||
21 | #include <linux/netfilter_ipv4/ip_conntrack_tuple.h> | ||
22 | #include <linux/netfilter_ipv4/ip_conntrack_h323.h> | ||
23 | #include <linux/moduleparam.h> | ||
24 | #include <linux/ctype.h> | ||
25 | #include <linux/inet.h> | ||
26 | |||
27 | #if 0 | ||
28 | #define DEBUGP printk | ||
29 | #else | ||
30 | #define DEBUGP(format, args...) | ||
31 | #endif | ||
32 | |||
33 | /* Parameters */ | ||
34 | static unsigned int default_rrq_ttl = 300; | ||
35 | module_param(default_rrq_ttl, uint, 0600); | ||
36 | MODULE_PARM_DESC(default_rrq_ttl, "use this TTL if it's missing in RRQ"); | ||
37 | |||
38 | static int gkrouted_only = 1; | ||
39 | module_param(gkrouted_only, int, 0600); | ||
40 | MODULE_PARM_DESC(gkrouted_only, "only accept calls from gatekeeper"); | ||
41 | |||
42 | static int callforward_filter = 1; | ||
43 | module_param(callforward_filter, bool, 0600); | ||
44 | MODULE_PARM_DESC(callforward_filter, "only create call forwarding expectations " | ||
45 | "if both endpoints are on different sides " | ||
46 | "(determined by routing information)"); | ||
47 | |||
48 | /* Hooks for NAT */ | ||
49 | int (*set_h245_addr_hook) (struct sk_buff ** pskb, | ||
50 | unsigned char **data, int dataoff, | ||
51 | H245_TransportAddress * addr, | ||
52 | __be32 ip, u_int16_t port); | ||
53 | int (*set_h225_addr_hook) (struct sk_buff ** pskb, | ||
54 | unsigned char **data, int dataoff, | ||
55 | TransportAddress * addr, | ||
56 | __be32 ip, u_int16_t port); | ||
57 | int (*set_sig_addr_hook) (struct sk_buff ** pskb, | ||
58 | struct ip_conntrack * ct, | ||
59 | enum ip_conntrack_info ctinfo, | ||
60 | unsigned char **data, | ||
61 | TransportAddress * addr, int count); | ||
62 | int (*set_ras_addr_hook) (struct sk_buff ** pskb, | ||
63 | struct ip_conntrack * ct, | ||
64 | enum ip_conntrack_info ctinfo, | ||
65 | unsigned char **data, | ||
66 | TransportAddress * addr, int count); | ||
67 | int (*nat_rtp_rtcp_hook) (struct sk_buff ** pskb, | ||
68 | struct ip_conntrack * ct, | ||
69 | enum ip_conntrack_info ctinfo, | ||
70 | unsigned char **data, int dataoff, | ||
71 | H245_TransportAddress * addr, | ||
72 | u_int16_t port, u_int16_t rtp_port, | ||
73 | struct ip_conntrack_expect * rtp_exp, | ||
74 | struct ip_conntrack_expect * rtcp_exp); | ||
75 | int (*nat_t120_hook) (struct sk_buff ** pskb, | ||
76 | struct ip_conntrack * ct, | ||
77 | enum ip_conntrack_info ctinfo, | ||
78 | unsigned char **data, int dataoff, | ||
79 | H245_TransportAddress * addr, u_int16_t port, | ||
80 | struct ip_conntrack_expect * exp); | ||
81 | int (*nat_h245_hook) (struct sk_buff ** pskb, | ||
82 | struct ip_conntrack * ct, | ||
83 | enum ip_conntrack_info ctinfo, | ||
84 | unsigned char **data, int dataoff, | ||
85 | TransportAddress * addr, u_int16_t port, | ||
86 | struct ip_conntrack_expect * exp); | ||
87 | int (*nat_callforwarding_hook) (struct sk_buff ** pskb, | ||
88 | struct ip_conntrack * ct, | ||
89 | enum ip_conntrack_info ctinfo, | ||
90 | unsigned char **data, int dataoff, | ||
91 | TransportAddress * addr, u_int16_t port, | ||
92 | struct ip_conntrack_expect * exp); | ||
93 | int (*nat_q931_hook) (struct sk_buff ** pskb, | ||
94 | struct ip_conntrack * ct, | ||
95 | enum ip_conntrack_info ctinfo, | ||
96 | unsigned char **data, TransportAddress * addr, int idx, | ||
97 | u_int16_t port, struct ip_conntrack_expect * exp); | ||
98 | |||
99 | |||
100 | static DEFINE_SPINLOCK(ip_h323_lock); | ||
101 | static char *h323_buffer; | ||
102 | |||
103 | /****************************************************************************/ | ||
104 | static int get_tpkt_data(struct sk_buff **pskb, struct ip_conntrack *ct, | ||
105 | enum ip_conntrack_info ctinfo, | ||
106 | unsigned char **data, int *datalen, int *dataoff) | ||
107 | { | ||
108 | struct ip_ct_h323_master *info = &ct->help.ct_h323_info; | ||
109 | int dir = CTINFO2DIR(ctinfo); | ||
110 | struct tcphdr _tcph, *th; | ||
111 | int tcpdatalen; | ||
112 | int tcpdataoff; | ||
113 | unsigned char *tpkt; | ||
114 | int tpktlen; | ||
115 | int tpktoff; | ||
116 | |||
117 | /* Get TCP header */ | ||
118 | th = skb_header_pointer(*pskb, ip_hdrlen(*pskb), | ||
119 | sizeof(_tcph), &_tcph); | ||
120 | if (th == NULL) | ||
121 | return 0; | ||
122 | |||
123 | /* Get TCP data offset */ | ||
124 | tcpdataoff = ip_hdrlen(*pskb) + th->doff * 4; | ||
125 | |||
126 | /* Get TCP data length */ | ||
127 | tcpdatalen = (*pskb)->len - tcpdataoff; | ||
128 | if (tcpdatalen <= 0) /* No TCP data */ | ||
129 | goto clear_out; | ||
130 | |||
131 | if (*data == NULL) { /* first TPKT */ | ||
132 | /* Get first TPKT pointer */ | ||
133 | tpkt = skb_header_pointer(*pskb, tcpdataoff, tcpdatalen, | ||
134 | h323_buffer); | ||
135 | BUG_ON(tpkt == NULL); | ||
136 | |||
137 | /* Validate TPKT identifier */ | ||
138 | if (tcpdatalen < 4 || tpkt[0] != 0x03 || tpkt[1] != 0) { | ||
139 | /* Netmeeting sends TPKT header and data separately */ | ||
140 | if (info->tpkt_len[dir] > 0) { | ||
141 | DEBUGP("ip_ct_h323: previous packet " | ||
142 | "indicated separate TPKT data of %hu " | ||
143 | "bytes\n", info->tpkt_len[dir]); | ||
144 | if (info->tpkt_len[dir] <= tcpdatalen) { | ||
145 | /* Yes, there was a TPKT header | ||
146 | * received */ | ||
147 | *data = tpkt; | ||
148 | *datalen = info->tpkt_len[dir]; | ||
149 | *dataoff = 0; | ||
150 | goto out; | ||
151 | } | ||
152 | |||
153 | /* Fragmented TPKT */ | ||
154 | if (net_ratelimit()) | ||
155 | printk("ip_ct_h323: " | ||
156 | "fragmented TPKT\n"); | ||
157 | goto clear_out; | ||
158 | } | ||
159 | |||
160 | /* It is not even a TPKT */ | ||
161 | return 0; | ||
162 | } | ||
163 | tpktoff = 0; | ||
164 | } else { /* Next TPKT */ | ||
165 | tpktoff = *dataoff + *datalen; | ||
166 | tcpdatalen -= tpktoff; | ||
167 | if (tcpdatalen <= 4) /* No more TPKT */ | ||
168 | goto clear_out; | ||
169 | tpkt = *data + *datalen; | ||
170 | |||
171 | /* Validate TPKT identifier */ | ||
172 | if (tpkt[0] != 0x03 || tpkt[1] != 0) | ||
173 | goto clear_out; | ||
174 | } | ||
175 | |||
176 | /* Validate TPKT length */ | ||
177 | tpktlen = tpkt[2] * 256 + tpkt[3]; | ||
178 | if (tpktlen < 4) | ||
179 | goto clear_out; | ||
180 | if (tpktlen > tcpdatalen) { | ||
181 | if (tcpdatalen == 4) { /* Separate TPKT header */ | ||
182 | /* Netmeeting sends TPKT header and data separately */ | ||
183 | DEBUGP("ip_ct_h323: separate TPKT header indicates " | ||
184 | "there will be TPKT data of %hu bytes\n", | ||
185 | tpktlen - 4); | ||
186 | info->tpkt_len[dir] = tpktlen - 4; | ||
187 | return 0; | ||
188 | } | ||
189 | |||
190 | if (net_ratelimit()) | ||
191 | printk("ip_ct_h323: incomplete TPKT (fragmented?)\n"); | ||
192 | goto clear_out; | ||
193 | } | ||
194 | |||
195 | /* This is the encapsulated data */ | ||
196 | *data = tpkt + 4; | ||
197 | *datalen = tpktlen - 4; | ||
198 | *dataoff = tpktoff + 4; | ||
199 | |||
200 | out: | ||
201 | /* Clear TPKT length */ | ||
202 | info->tpkt_len[dir] = 0; | ||
203 | return 1; | ||
204 | |||
205 | clear_out: | ||
206 | info->tpkt_len[dir] = 0; | ||
207 | return 0; | ||
208 | } | ||
209 | |||
210 | /****************************************************************************/ | ||
211 | static int get_h245_addr(unsigned char *data, H245_TransportAddress * addr, | ||
212 | __be32 * ip, u_int16_t * port) | ||
213 | { | ||
214 | unsigned char *p; | ||
215 | |||
216 | if (addr->choice != eH245_TransportAddress_unicastAddress || | ||
217 | addr->unicastAddress.choice != eUnicastAddress_iPAddress) | ||
218 | return 0; | ||
219 | |||
220 | p = data + addr->unicastAddress.iPAddress.network; | ||
221 | *ip = htonl((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | (p[3])); | ||
222 | *port = (p[4] << 8) | (p[5]); | ||
223 | |||
224 | return 1; | ||
225 | } | ||
226 | |||
227 | /****************************************************************************/ | ||
228 | static int expect_rtp_rtcp(struct sk_buff **pskb, struct ip_conntrack *ct, | ||
229 | enum ip_conntrack_info ctinfo, | ||
230 | unsigned char **data, int dataoff, | ||
231 | H245_TransportAddress * addr) | ||
232 | { | ||
233 | int dir = CTINFO2DIR(ctinfo); | ||
234 | int ret = 0; | ||
235 | __be32 ip; | ||
236 | u_int16_t port; | ||
237 | u_int16_t rtp_port; | ||
238 | struct ip_conntrack_expect *rtp_exp; | ||
239 | struct ip_conntrack_expect *rtcp_exp; | ||
240 | typeof(nat_rtp_rtcp_hook) nat_rtp_rtcp; | ||
241 | |||
242 | /* Read RTP or RTCP address */ | ||
243 | if (!get_h245_addr(*data, addr, &ip, &port) || | ||
244 | ip != ct->tuplehash[dir].tuple.src.ip || port == 0) | ||
245 | return 0; | ||
246 | |||
247 | /* RTP port is even */ | ||
248 | rtp_port = port & (~1); | ||
249 | |||
250 | /* Create expect for RTP */ | ||
251 | if ((rtp_exp = ip_conntrack_expect_alloc(ct)) == NULL) | ||
252 | return -1; | ||
253 | rtp_exp->tuple.src.ip = ct->tuplehash[!dir].tuple.src.ip; | ||
254 | rtp_exp->tuple.src.u.udp.port = 0; | ||
255 | rtp_exp->tuple.dst.ip = ct->tuplehash[!dir].tuple.dst.ip; | ||
256 | rtp_exp->tuple.dst.u.udp.port = htons(rtp_port); | ||
257 | rtp_exp->tuple.dst.protonum = IPPROTO_UDP; | ||
258 | rtp_exp->mask.src.ip = htonl(0xFFFFFFFF); | ||
259 | rtp_exp->mask.src.u.udp.port = 0; | ||
260 | rtp_exp->mask.dst.ip = htonl(0xFFFFFFFF); | ||
261 | rtp_exp->mask.dst.u.udp.port = htons(0xFFFF); | ||
262 | rtp_exp->mask.dst.protonum = 0xFF; | ||
263 | rtp_exp->flags = 0; | ||
264 | |||
265 | /* Create expect for RTCP */ | ||
266 | if ((rtcp_exp = ip_conntrack_expect_alloc(ct)) == NULL) { | ||
267 | ip_conntrack_expect_put(rtp_exp); | ||
268 | return -1; | ||
269 | } | ||
270 | rtcp_exp->tuple.src.ip = ct->tuplehash[!dir].tuple.src.ip; | ||
271 | rtcp_exp->tuple.src.u.udp.port = 0; | ||
272 | rtcp_exp->tuple.dst.ip = ct->tuplehash[!dir].tuple.dst.ip; | ||
273 | rtcp_exp->tuple.dst.u.udp.port = htons(rtp_port + 1); | ||
274 | rtcp_exp->tuple.dst.protonum = IPPROTO_UDP; | ||
275 | rtcp_exp->mask.src.ip = htonl(0xFFFFFFFF); | ||
276 | rtcp_exp->mask.src.u.udp.port = 0; | ||
277 | rtcp_exp->mask.dst.ip = htonl(0xFFFFFFFF); | ||
278 | rtcp_exp->mask.dst.u.udp.port = htons(0xFFFF); | ||
279 | rtcp_exp->mask.dst.protonum = 0xFF; | ||
280 | rtcp_exp->flags = 0; | ||
281 | |||
282 | if (ct->tuplehash[dir].tuple.src.ip != | ||
283 | ct->tuplehash[!dir].tuple.dst.ip && | ||
284 | (nat_rtp_rtcp = rcu_dereference(nat_rtp_rtcp_hook))) { | ||
285 | /* NAT needed */ | ||
286 | ret = nat_rtp_rtcp(pskb, ct, ctinfo, data, dataoff, | ||
287 | addr, port, rtp_port, rtp_exp, rtcp_exp); | ||
288 | } else { /* Conntrack only */ | ||
289 | rtp_exp->expectfn = NULL; | ||
290 | rtcp_exp->expectfn = NULL; | ||
291 | |||
292 | if (ip_conntrack_expect_related(rtp_exp) == 0) { | ||
293 | if (ip_conntrack_expect_related(rtcp_exp) == 0) { | ||
294 | DEBUGP("ip_ct_h323: expect RTP " | ||
295 | "%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n", | ||
296 | NIPQUAD(rtp_exp->tuple.src.ip), | ||
297 | ntohs(rtp_exp->tuple.src.u.udp.port), | ||
298 | NIPQUAD(rtp_exp->tuple.dst.ip), | ||
299 | ntohs(rtp_exp->tuple.dst.u.udp.port)); | ||
300 | DEBUGP("ip_ct_h323: expect RTCP " | ||
301 | "%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n", | ||
302 | NIPQUAD(rtcp_exp->tuple.src.ip), | ||
303 | ntohs(rtcp_exp->tuple.src.u.udp.port), | ||
304 | NIPQUAD(rtcp_exp->tuple.dst.ip), | ||
305 | ntohs(rtcp_exp->tuple.dst.u.udp.port)); | ||
306 | } else { | ||
307 | ip_conntrack_unexpect_related(rtp_exp); | ||
308 | ret = -1; | ||
309 | } | ||
310 | } else | ||
311 | ret = -1; | ||
312 | } | ||
313 | |||
314 | ip_conntrack_expect_put(rtp_exp); | ||
315 | ip_conntrack_expect_put(rtcp_exp); | ||
316 | |||
317 | return ret; | ||
318 | } | ||
319 | |||
320 | /****************************************************************************/ | ||
321 | static int expect_t120(struct sk_buff **pskb, | ||
322 | struct ip_conntrack *ct, | ||
323 | enum ip_conntrack_info ctinfo, | ||
324 | unsigned char **data, int dataoff, | ||
325 | H245_TransportAddress * addr) | ||
326 | { | ||
327 | int dir = CTINFO2DIR(ctinfo); | ||
328 | int ret = 0; | ||
329 | __be32 ip; | ||
330 | u_int16_t port; | ||
331 | struct ip_conntrack_expect *exp = NULL; | ||
332 | typeof(nat_t120_hook) nat_t120; | ||
333 | |||
334 | /* Read T.120 address */ | ||
335 | if (!get_h245_addr(*data, addr, &ip, &port) || | ||
336 | ip != ct->tuplehash[dir].tuple.src.ip || port == 0) | ||
337 | return 0; | ||
338 | |||
339 | /* Create expect for T.120 connections */ | ||
340 | if ((exp = ip_conntrack_expect_alloc(ct)) == NULL) | ||
341 | return -1; | ||
342 | exp->tuple.src.ip = ct->tuplehash[!dir].tuple.src.ip; | ||
343 | exp->tuple.src.u.tcp.port = 0; | ||
344 | exp->tuple.dst.ip = ct->tuplehash[!dir].tuple.dst.ip; | ||
345 | exp->tuple.dst.u.tcp.port = htons(port); | ||
346 | exp->tuple.dst.protonum = IPPROTO_TCP; | ||
347 | exp->mask.src.ip = htonl(0xFFFFFFFF); | ||
348 | exp->mask.src.u.tcp.port = 0; | ||
349 | exp->mask.dst.ip = htonl(0xFFFFFFFF); | ||
350 | exp->mask.dst.u.tcp.port = htons(0xFFFF); | ||
351 | exp->mask.dst.protonum = 0xFF; | ||
352 | exp->flags = IP_CT_EXPECT_PERMANENT; /* Accept multiple channels */ | ||
353 | |||
354 | if (ct->tuplehash[dir].tuple.src.ip != | ||
355 | ct->tuplehash[!dir].tuple.dst.ip && | ||
356 | (nat_t120 = rcu_dereference(nat_t120_hook))) { | ||
357 | /* NAT needed */ | ||
358 | ret = nat_t120(pskb, ct, ctinfo, data, dataoff, addr, | ||
359 | port, exp); | ||
360 | } else { /* Conntrack only */ | ||
361 | exp->expectfn = NULL; | ||
362 | if (ip_conntrack_expect_related(exp) == 0) { | ||
363 | DEBUGP("ip_ct_h323: expect T.120 " | ||
364 | "%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n", | ||
365 | NIPQUAD(exp->tuple.src.ip), | ||
366 | ntohs(exp->tuple.src.u.tcp.port), | ||
367 | NIPQUAD(exp->tuple.dst.ip), | ||
368 | ntohs(exp->tuple.dst.u.tcp.port)); | ||
369 | } else | ||
370 | ret = -1; | ||
371 | } | ||
372 | |||
373 | ip_conntrack_expect_put(exp); | ||
374 | |||
375 | return ret; | ||
376 | } | ||
377 | |||
378 | /****************************************************************************/ | ||
379 | static int process_h245_channel(struct sk_buff **pskb, | ||
380 | struct ip_conntrack *ct, | ||
381 | enum ip_conntrack_info ctinfo, | ||
382 | unsigned char **data, int dataoff, | ||
383 | H2250LogicalChannelParameters * channel) | ||
384 | { | ||
385 | int ret; | ||
386 | |||
387 | if (channel->options & eH2250LogicalChannelParameters_mediaChannel) { | ||
388 | /* RTP */ | ||
389 | ret = expect_rtp_rtcp(pskb, ct, ctinfo, data, dataoff, | ||
390 | &channel->mediaChannel); | ||
391 | if (ret < 0) | ||
392 | return -1; | ||
393 | } | ||
394 | |||
395 | if (channel-> | ||
396 | options & eH2250LogicalChannelParameters_mediaControlChannel) { | ||
397 | /* RTCP */ | ||
398 | ret = expect_rtp_rtcp(pskb, ct, ctinfo, data, dataoff, | ||
399 | &channel->mediaControlChannel); | ||
400 | if (ret < 0) | ||
401 | return -1; | ||
402 | } | ||
403 | |||
404 | return 0; | ||
405 | } | ||
406 | |||
407 | /****************************************************************************/ | ||
408 | static int process_olc(struct sk_buff **pskb, struct ip_conntrack *ct, | ||
409 | enum ip_conntrack_info ctinfo, | ||
410 | unsigned char **data, int dataoff, | ||
411 | OpenLogicalChannel * olc) | ||
412 | { | ||
413 | int ret; | ||
414 | |||
415 | DEBUGP("ip_ct_h323: OpenLogicalChannel\n"); | ||
416 | |||
417 | if (olc->forwardLogicalChannelParameters.multiplexParameters.choice == | ||
418 | eOpenLogicalChannel_forwardLogicalChannelParameters_multiplexParameters_h2250LogicalChannelParameters) | ||
419 | { | ||
420 | ret = process_h245_channel(pskb, ct, ctinfo, data, dataoff, | ||
421 | &olc-> | ||
422 | forwardLogicalChannelParameters. | ||
423 | multiplexParameters. | ||
424 | h2250LogicalChannelParameters); | ||
425 | if (ret < 0) | ||
426 | return -1; | ||
427 | } | ||
428 | |||
429 | if ((olc->options & | ||
430 | eOpenLogicalChannel_reverseLogicalChannelParameters) && | ||
431 | (olc->reverseLogicalChannelParameters.options & | ||
432 | eOpenLogicalChannel_reverseLogicalChannelParameters_multiplexParameters) | ||
433 | && (olc->reverseLogicalChannelParameters.multiplexParameters. | ||
434 | choice == | ||
435 | eOpenLogicalChannel_reverseLogicalChannelParameters_multiplexParameters_h2250LogicalChannelParameters)) | ||
436 | { | ||
437 | ret = | ||
438 | process_h245_channel(pskb, ct, ctinfo, data, dataoff, | ||
439 | &olc-> | ||
440 | reverseLogicalChannelParameters. | ||
441 | multiplexParameters. | ||
442 | h2250LogicalChannelParameters); | ||
443 | if (ret < 0) | ||
444 | return -1; | ||
445 | } | ||
446 | |||
447 | if ((olc->options & eOpenLogicalChannel_separateStack) && | ||
448 | olc->forwardLogicalChannelParameters.dataType.choice == | ||
449 | eDataType_data && | ||
450 | olc->forwardLogicalChannelParameters.dataType.data.application. | ||
451 | choice == eDataApplicationCapability_application_t120 && | ||
452 | olc->forwardLogicalChannelParameters.dataType.data.application. | ||
453 | t120.choice == eDataProtocolCapability_separateLANStack && | ||
454 | olc->separateStack.networkAddress.choice == | ||
455 | eNetworkAccessParameters_networkAddress_localAreaAddress) { | ||
456 | ret = expect_t120(pskb, ct, ctinfo, data, dataoff, | ||
457 | &olc->separateStack.networkAddress. | ||
458 | localAreaAddress); | ||
459 | if (ret < 0) | ||
460 | return -1; | ||
461 | } | ||
462 | |||
463 | return 0; | ||
464 | } | ||
465 | |||
466 | /****************************************************************************/ | ||
467 | static int process_olca(struct sk_buff **pskb, struct ip_conntrack *ct, | ||
468 | enum ip_conntrack_info ctinfo, | ||
469 | unsigned char **data, int dataoff, | ||
470 | OpenLogicalChannelAck * olca) | ||
471 | { | ||
472 | H2250LogicalChannelAckParameters *ack; | ||
473 | int ret; | ||
474 | |||
475 | DEBUGP("ip_ct_h323: OpenLogicalChannelAck\n"); | ||
476 | |||
477 | if ((olca->options & | ||
478 | eOpenLogicalChannelAck_reverseLogicalChannelParameters) && | ||
479 | (olca->reverseLogicalChannelParameters.options & | ||
480 | eOpenLogicalChannelAck_reverseLogicalChannelParameters_multiplexParameters) | ||
481 | && (olca->reverseLogicalChannelParameters.multiplexParameters. | ||
482 | choice == | ||
483 | eOpenLogicalChannelAck_reverseLogicalChannelParameters_multiplexParameters_h2250LogicalChannelParameters)) | ||
484 | { | ||
485 | ret = process_h245_channel(pskb, ct, ctinfo, data, dataoff, | ||
486 | &olca-> | ||
487 | reverseLogicalChannelParameters. | ||
488 | multiplexParameters. | ||
489 | h2250LogicalChannelParameters); | ||
490 | if (ret < 0) | ||
491 | return -1; | ||
492 | } | ||
493 | |||
494 | if ((olca->options & | ||
495 | eOpenLogicalChannelAck_forwardMultiplexAckParameters) && | ||
496 | (olca->forwardMultiplexAckParameters.choice == | ||
497 | eOpenLogicalChannelAck_forwardMultiplexAckParameters_h2250LogicalChannelAckParameters)) | ||
498 | { | ||
499 | ack = &olca->forwardMultiplexAckParameters. | ||
500 | h2250LogicalChannelAckParameters; | ||
501 | if (ack->options & | ||
502 | eH2250LogicalChannelAckParameters_mediaChannel) { | ||
503 | /* RTP */ | ||
504 | ret = expect_rtp_rtcp(pskb, ct, ctinfo, data, dataoff, | ||
505 | &ack->mediaChannel); | ||
506 | if (ret < 0) | ||
507 | return -1; | ||
508 | } | ||
509 | |||
510 | if (ack->options & | ||
511 | eH2250LogicalChannelAckParameters_mediaControlChannel) { | ||
512 | /* RTCP */ | ||
513 | ret = expect_rtp_rtcp(pskb, ct, ctinfo, data, dataoff, | ||
514 | &ack->mediaControlChannel); | ||
515 | if (ret < 0) | ||
516 | return -1; | ||
517 | } | ||
518 | } | ||
519 | |||
520 | return 0; | ||
521 | } | ||
522 | |||
523 | /****************************************************************************/ | ||
524 | static int process_h245(struct sk_buff **pskb, struct ip_conntrack *ct, | ||
525 | enum ip_conntrack_info ctinfo, | ||
526 | unsigned char **data, int dataoff, | ||
527 | MultimediaSystemControlMessage * mscm) | ||
528 | { | ||
529 | switch (mscm->choice) { | ||
530 | case eMultimediaSystemControlMessage_request: | ||
531 | if (mscm->request.choice == | ||
532 | eRequestMessage_openLogicalChannel) { | ||
533 | return process_olc(pskb, ct, ctinfo, data, dataoff, | ||
534 | &mscm->request.openLogicalChannel); | ||
535 | } | ||
536 | DEBUGP("ip_ct_h323: H.245 Request %d\n", | ||
537 | mscm->request.choice); | ||
538 | break; | ||
539 | case eMultimediaSystemControlMessage_response: | ||
540 | if (mscm->response.choice == | ||
541 | eResponseMessage_openLogicalChannelAck) { | ||
542 | return process_olca(pskb, ct, ctinfo, data, dataoff, | ||
543 | &mscm->response. | ||
544 | openLogicalChannelAck); | ||
545 | } | ||
546 | DEBUGP("ip_ct_h323: H.245 Response %d\n", | ||
547 | mscm->response.choice); | ||
548 | break; | ||
549 | default: | ||
550 | DEBUGP("ip_ct_h323: H.245 signal %d\n", mscm->choice); | ||
551 | break; | ||
552 | } | ||
553 | |||
554 | return 0; | ||
555 | } | ||
556 | |||
557 | /****************************************************************************/ | ||
558 | static int h245_help(struct sk_buff **pskb, struct ip_conntrack *ct, | ||
559 | enum ip_conntrack_info ctinfo) | ||
560 | { | ||
561 | static MultimediaSystemControlMessage mscm; | ||
562 | unsigned char *data = NULL; | ||
563 | int datalen; | ||
564 | int dataoff; | ||
565 | int ret; | ||
566 | |||
567 | /* Until there's been traffic both ways, don't look in packets. */ | ||
568 | if (ctinfo != IP_CT_ESTABLISHED | ||
569 | && ctinfo != IP_CT_ESTABLISHED + IP_CT_IS_REPLY) { | ||
570 | return NF_ACCEPT; | ||
571 | } | ||
572 | DEBUGP("ip_ct_h245: skblen = %u\n", (*pskb)->len); | ||
573 | |||
574 | spin_lock_bh(&ip_h323_lock); | ||
575 | |||
576 | /* Process each TPKT */ | ||
577 | while (get_tpkt_data(pskb, ct, ctinfo, &data, &datalen, &dataoff)) { | ||
578 | DEBUGP("ip_ct_h245: TPKT %u.%u.%u.%u->%u.%u.%u.%u, len=%d\n", | ||
579 | NIPQUAD(ip_hdr(*pskb)->saddr), | ||
580 | NIPQUAD(ip_hdr(*pskb)->daddr), datalen); | ||
581 | |||
582 | /* Decode H.245 signal */ | ||
583 | ret = DecodeMultimediaSystemControlMessage(data, datalen, | ||
584 | &mscm); | ||
585 | if (ret < 0) { | ||
586 | if (net_ratelimit()) | ||
587 | printk("ip_ct_h245: decoding error: %s\n", | ||
588 | ret == H323_ERROR_BOUND ? | ||
589 | "out of bound" : "out of range"); | ||
590 | /* We don't drop when decoding error */ | ||
591 | break; | ||
592 | } | ||
593 | |||
594 | /* Process H.245 signal */ | ||
595 | if (process_h245(pskb, ct, ctinfo, &data, dataoff, &mscm) < 0) | ||
596 | goto drop; | ||
597 | } | ||
598 | |||
599 | spin_unlock_bh(&ip_h323_lock); | ||
600 | return NF_ACCEPT; | ||
601 | |||
602 | drop: | ||
603 | spin_unlock_bh(&ip_h323_lock); | ||
604 | if (net_ratelimit()) | ||
605 | printk("ip_ct_h245: packet dropped\n"); | ||
606 | return NF_DROP; | ||
607 | } | ||
608 | |||
609 | /****************************************************************************/ | ||
610 | static struct ip_conntrack_helper ip_conntrack_helper_h245 = { | ||
611 | .name = "H.245", | ||
612 | .me = THIS_MODULE, | ||
613 | .max_expected = H323_RTP_CHANNEL_MAX * 4 + 2 /* T.120 */ , | ||
614 | .timeout = 240, | ||
615 | .tuple = {.dst = {.protonum = IPPROTO_TCP}}, | ||
616 | .mask = {.src = {.u = {0xFFFF}}, | ||
617 | .dst = {.protonum = 0xFF}}, | ||
618 | .help = h245_help | ||
619 | }; | ||
620 | |||
621 | /****************************************************************************/ | ||
622 | void ip_conntrack_h245_expect(struct ip_conntrack *new, | ||
623 | struct ip_conntrack_expect *this) | ||
624 | { | ||
625 | write_lock_bh(&ip_conntrack_lock); | ||
626 | new->helper = &ip_conntrack_helper_h245; | ||
627 | write_unlock_bh(&ip_conntrack_lock); | ||
628 | } | ||
629 | |||
630 | /****************************************************************************/ | ||
631 | int get_h225_addr(unsigned char *data, TransportAddress * addr, | ||
632 | __be32 * ip, u_int16_t * port) | ||
633 | { | ||
634 | unsigned char *p; | ||
635 | |||
636 | if (addr->choice != eTransportAddress_ipAddress) | ||
637 | return 0; | ||
638 | |||
639 | p = data + addr->ipAddress.ip; | ||
640 | *ip = htonl((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | (p[3])); | ||
641 | *port = (p[4] << 8) | (p[5]); | ||
642 | |||
643 | return 1; | ||
644 | } | ||
645 | |||
646 | /****************************************************************************/ | ||
647 | static int expect_h245(struct sk_buff **pskb, struct ip_conntrack *ct, | ||
648 | enum ip_conntrack_info ctinfo, | ||
649 | unsigned char **data, int dataoff, | ||
650 | TransportAddress * addr) | ||
651 | { | ||
652 | int dir = CTINFO2DIR(ctinfo); | ||
653 | int ret = 0; | ||
654 | __be32 ip; | ||
655 | u_int16_t port; | ||
656 | struct ip_conntrack_expect *exp = NULL; | ||
657 | typeof(nat_h245_hook) nat_h245; | ||
658 | |||
659 | /* Read h245Address */ | ||
660 | if (!get_h225_addr(*data, addr, &ip, &port) || | ||
661 | ip != ct->tuplehash[dir].tuple.src.ip || port == 0) | ||
662 | return 0; | ||
663 | |||
664 | /* Create expect for h245 connection */ | ||
665 | if ((exp = ip_conntrack_expect_alloc(ct)) == NULL) | ||
666 | return -1; | ||
667 | exp->tuple.src.ip = ct->tuplehash[!dir].tuple.src.ip; | ||
668 | exp->tuple.src.u.tcp.port = 0; | ||
669 | exp->tuple.dst.ip = ct->tuplehash[!dir].tuple.dst.ip; | ||
670 | exp->tuple.dst.u.tcp.port = htons(port); | ||
671 | exp->tuple.dst.protonum = IPPROTO_TCP; | ||
672 | exp->mask.src.ip = htonl(0xFFFFFFFF); | ||
673 | exp->mask.src.u.tcp.port = 0; | ||
674 | exp->mask.dst.ip = htonl(0xFFFFFFFF); | ||
675 | exp->mask.dst.u.tcp.port = htons(0xFFFF); | ||
676 | exp->mask.dst.protonum = 0xFF; | ||
677 | exp->flags = 0; | ||
678 | |||
679 | if (ct->tuplehash[dir].tuple.src.ip != | ||
680 | ct->tuplehash[!dir].tuple.dst.ip && | ||
681 | (nat_h245 = rcu_dereference(nat_h245_hook))) { | ||
682 | /* NAT needed */ | ||
683 | ret = nat_h245(pskb, ct, ctinfo, data, dataoff, addr, | ||
684 | port, exp); | ||
685 | } else { /* Conntrack only */ | ||
686 | exp->expectfn = ip_conntrack_h245_expect; | ||
687 | |||
688 | if (ip_conntrack_expect_related(exp) == 0) { | ||
689 | DEBUGP("ip_ct_q931: expect H.245 " | ||
690 | "%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n", | ||
691 | NIPQUAD(exp->tuple.src.ip), | ||
692 | ntohs(exp->tuple.src.u.tcp.port), | ||
693 | NIPQUAD(exp->tuple.dst.ip), | ||
694 | ntohs(exp->tuple.dst.u.tcp.port)); | ||
695 | } else | ||
696 | ret = -1; | ||
697 | } | ||
698 | |||
699 | ip_conntrack_expect_put(exp); | ||
700 | |||
701 | return ret; | ||
702 | } | ||
703 | |||
704 | /* Forwarding declaration */ | ||
705 | void ip_conntrack_q931_expect(struct ip_conntrack *new, | ||
706 | struct ip_conntrack_expect *this); | ||
707 | |||
708 | /****************************************************************************/ | ||
709 | static int expect_callforwarding(struct sk_buff **pskb, | ||
710 | struct ip_conntrack *ct, | ||
711 | enum ip_conntrack_info ctinfo, | ||
712 | unsigned char **data, int dataoff, | ||
713 | TransportAddress * addr) | ||
714 | { | ||
715 | int dir = CTINFO2DIR(ctinfo); | ||
716 | int ret = 0; | ||
717 | __be32 ip; | ||
718 | u_int16_t port; | ||
719 | struct ip_conntrack_expect *exp = NULL; | ||
720 | typeof(nat_callforwarding_hook) nat_callforwarding; | ||
721 | |||
722 | /* Read alternativeAddress */ | ||
723 | if (!get_h225_addr(*data, addr, &ip, &port) || port == 0) | ||
724 | return 0; | ||
725 | |||
726 | /* If the calling party is on the same side of the forward-to party, | ||
727 | * we don't need to track the second call */ | ||
728 | if (callforward_filter) { | ||
729 | struct rtable *rt1, *rt2; | ||
730 | struct flowi fl1 = { | ||
731 | .fl4_dst = ip, | ||
732 | }; | ||
733 | struct flowi fl2 = { | ||
734 | .fl4_dst = ct->tuplehash[!dir].tuple.src.ip, | ||
735 | }; | ||
736 | |||
737 | if (ip_route_output_key(&rt1, &fl1) == 0) { | ||
738 | if (ip_route_output_key(&rt2, &fl2) == 0) { | ||
739 | if (rt1->rt_gateway == rt2->rt_gateway && | ||
740 | rt1->u.dst.dev == rt2->u.dst.dev) | ||
741 | ret = 1; | ||
742 | dst_release(&rt2->u.dst); | ||
743 | } | ||
744 | dst_release(&rt1->u.dst); | ||
745 | } | ||
746 | if (ret) { | ||
747 | DEBUGP("ip_ct_q931: Call Forwarding not tracked\n"); | ||
748 | return 0; | ||
749 | } | ||
750 | } | ||
751 | |||
752 | /* Create expect for the second call leg */ | ||
753 | if ((exp = ip_conntrack_expect_alloc(ct)) == NULL) | ||
754 | return -1; | ||
755 | exp->tuple.src.ip = ct->tuplehash[!dir].tuple.src.ip; | ||
756 | exp->tuple.src.u.tcp.port = 0; | ||
757 | exp->tuple.dst.ip = ip; | ||
758 | exp->tuple.dst.u.tcp.port = htons(port); | ||
759 | exp->tuple.dst.protonum = IPPROTO_TCP; | ||
760 | exp->mask.src.ip = htonl(0xFFFFFFFF); | ||
761 | exp->mask.src.u.tcp.port = 0; | ||
762 | exp->mask.dst.ip = htonl(0xFFFFFFFF); | ||
763 | exp->mask.dst.u.tcp.port = htons(0xFFFF); | ||
764 | exp->mask.dst.protonum = 0xFF; | ||
765 | exp->flags = 0; | ||
766 | |||
767 | if (ct->tuplehash[dir].tuple.src.ip != | ||
768 | ct->tuplehash[!dir].tuple.dst.ip && | ||
769 | (nat_callforwarding = rcu_dereference(nat_callforwarding_hook))) { | ||
770 | /* Need NAT */ | ||
771 | ret = nat_callforwarding(pskb, ct, ctinfo, data, dataoff, | ||
772 | addr, port, exp); | ||
773 | } else { /* Conntrack only */ | ||
774 | exp->expectfn = ip_conntrack_q931_expect; | ||
775 | |||
776 | if (ip_conntrack_expect_related(exp) == 0) { | ||
777 | DEBUGP("ip_ct_q931: expect Call Forwarding " | ||
778 | "%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n", | ||
779 | NIPQUAD(exp->tuple.src.ip), | ||
780 | ntohs(exp->tuple.src.u.tcp.port), | ||
781 | NIPQUAD(exp->tuple.dst.ip), | ||
782 | ntohs(exp->tuple.dst.u.tcp.port)); | ||
783 | } else | ||
784 | ret = -1; | ||
785 | } | ||
786 | |||
787 | ip_conntrack_expect_put(exp); | ||
788 | |||
789 | return ret; | ||
790 | } | ||
791 | |||
792 | /****************************************************************************/ | ||
793 | static int process_setup(struct sk_buff **pskb, struct ip_conntrack *ct, | ||
794 | enum ip_conntrack_info ctinfo, | ||
795 | unsigned char **data, int dataoff, | ||
796 | Setup_UUIE * setup) | ||
797 | { | ||
798 | int dir = CTINFO2DIR(ctinfo); | ||
799 | int ret; | ||
800 | int i; | ||
801 | __be32 ip; | ||
802 | u_int16_t port; | ||
803 | typeof(set_h225_addr_hook) set_h225_addr; | ||
804 | |||
805 | DEBUGP("ip_ct_q931: Setup\n"); | ||
806 | |||
807 | if (setup->options & eSetup_UUIE_h245Address) { | ||
808 | ret = expect_h245(pskb, ct, ctinfo, data, dataoff, | ||
809 | &setup->h245Address); | ||
810 | if (ret < 0) | ||
811 | return -1; | ||
812 | } | ||
813 | |||
814 | set_h225_addr = rcu_dereference(set_h225_addr_hook); | ||
815 | |||
816 | if ((setup->options & eSetup_UUIE_destCallSignalAddress) && | ||
817 | (set_h225_addr) && | ||
818 | get_h225_addr(*data, &setup->destCallSignalAddress, &ip, &port) && | ||
819 | ip != ct->tuplehash[!dir].tuple.src.ip) { | ||
820 | DEBUGP("ip_ct_q931: set destCallSignalAddress " | ||
821 | "%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n", | ||
822 | NIPQUAD(ip), port, | ||
823 | NIPQUAD(ct->tuplehash[!dir].tuple.src.ip), | ||
824 | ntohs(ct->tuplehash[!dir].tuple.src.u.tcp.port)); | ||
825 | ret = set_h225_addr(pskb, data, dataoff, | ||
826 | &setup->destCallSignalAddress, | ||
827 | ct->tuplehash[!dir].tuple.src.ip, | ||
828 | ntohs(ct->tuplehash[!dir].tuple.src. | ||
829 | u.tcp.port)); | ||
830 | if (ret < 0) | ||
831 | return -1; | ||
832 | } | ||
833 | |||
834 | if ((setup->options & eSetup_UUIE_sourceCallSignalAddress) && | ||
835 | (set_h225_addr) && | ||
836 | get_h225_addr(*data, &setup->sourceCallSignalAddress, &ip, &port) | ||
837 | && ip != ct->tuplehash[!dir].tuple.dst.ip) { | ||
838 | DEBUGP("ip_ct_q931: set sourceCallSignalAddress " | ||
839 | "%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n", | ||
840 | NIPQUAD(ip), port, | ||
841 | NIPQUAD(ct->tuplehash[!dir].tuple.dst.ip), | ||
842 | ntohs(ct->tuplehash[!dir].tuple.dst.u.tcp.port)); | ||
843 | ret = set_h225_addr(pskb, data, dataoff, | ||
844 | &setup->sourceCallSignalAddress, | ||
845 | ct->tuplehash[!dir].tuple.dst.ip, | ||
846 | ntohs(ct->tuplehash[!dir].tuple.dst. | ||
847 | u.tcp.port)); | ||
848 | if (ret < 0) | ||
849 | return -1; | ||
850 | } | ||
851 | |||
852 | if (setup->options & eSetup_UUIE_fastStart) { | ||
853 | for (i = 0; i < setup->fastStart.count; i++) { | ||
854 | ret = process_olc(pskb, ct, ctinfo, data, dataoff, | ||
855 | &setup->fastStart.item[i]); | ||
856 | if (ret < 0) | ||
857 | return -1; | ||
858 | } | ||
859 | } | ||
860 | |||
861 | return 0; | ||
862 | } | ||
863 | |||
864 | /****************************************************************************/ | ||
865 | static int process_callproceeding(struct sk_buff **pskb, | ||
866 | struct ip_conntrack *ct, | ||
867 | enum ip_conntrack_info ctinfo, | ||
868 | unsigned char **data, int dataoff, | ||
869 | CallProceeding_UUIE * callproc) | ||
870 | { | ||
871 | int ret; | ||
872 | int i; | ||
873 | |||
874 | DEBUGP("ip_ct_q931: CallProceeding\n"); | ||
875 | |||
876 | if (callproc->options & eCallProceeding_UUIE_h245Address) { | ||
877 | ret = expect_h245(pskb, ct, ctinfo, data, dataoff, | ||
878 | &callproc->h245Address); | ||
879 | if (ret < 0) | ||
880 | return -1; | ||
881 | } | ||
882 | |||
883 | if (callproc->options & eCallProceeding_UUIE_fastStart) { | ||
884 | for (i = 0; i < callproc->fastStart.count; i++) { | ||
885 | ret = process_olc(pskb, ct, ctinfo, data, dataoff, | ||
886 | &callproc->fastStart.item[i]); | ||
887 | if (ret < 0) | ||
888 | return -1; | ||
889 | } | ||
890 | } | ||
891 | |||
892 | return 0; | ||
893 | } | ||
894 | |||
895 | /****************************************************************************/ | ||
896 | static int process_connect(struct sk_buff **pskb, struct ip_conntrack *ct, | ||
897 | enum ip_conntrack_info ctinfo, | ||
898 | unsigned char **data, int dataoff, | ||
899 | Connect_UUIE * connect) | ||
900 | { | ||
901 | int ret; | ||
902 | int i; | ||
903 | |||
904 | DEBUGP("ip_ct_q931: Connect\n"); | ||
905 | |||
906 | if (connect->options & eConnect_UUIE_h245Address) { | ||
907 | ret = expect_h245(pskb, ct, ctinfo, data, dataoff, | ||
908 | &connect->h245Address); | ||
909 | if (ret < 0) | ||
910 | return -1; | ||
911 | } | ||
912 | |||
913 | if (connect->options & eConnect_UUIE_fastStart) { | ||
914 | for (i = 0; i < connect->fastStart.count; i++) { | ||
915 | ret = process_olc(pskb, ct, ctinfo, data, dataoff, | ||
916 | &connect->fastStart.item[i]); | ||
917 | if (ret < 0) | ||
918 | return -1; | ||
919 | } | ||
920 | } | ||
921 | |||
922 | return 0; | ||
923 | } | ||
924 | |||
925 | /****************************************************************************/ | ||
926 | static int process_alerting(struct sk_buff **pskb, struct ip_conntrack *ct, | ||
927 | enum ip_conntrack_info ctinfo, | ||
928 | unsigned char **data, int dataoff, | ||
929 | Alerting_UUIE * alert) | ||
930 | { | ||
931 | int ret; | ||
932 | int i; | ||
933 | |||
934 | DEBUGP("ip_ct_q931: Alerting\n"); | ||
935 | |||
936 | if (alert->options & eAlerting_UUIE_h245Address) { | ||
937 | ret = expect_h245(pskb, ct, ctinfo, data, dataoff, | ||
938 | &alert->h245Address); | ||
939 | if (ret < 0) | ||
940 | return -1; | ||
941 | } | ||
942 | |||
943 | if (alert->options & eAlerting_UUIE_fastStart) { | ||
944 | for (i = 0; i < alert->fastStart.count; i++) { | ||
945 | ret = process_olc(pskb, ct, ctinfo, data, dataoff, | ||
946 | &alert->fastStart.item[i]); | ||
947 | if (ret < 0) | ||
948 | return -1; | ||
949 | } | ||
950 | } | ||
951 | |||
952 | return 0; | ||
953 | } | ||
954 | |||
955 | /****************************************************************************/ | ||
956 | static int process_information(struct sk_buff **pskb, | ||
957 | struct ip_conntrack *ct, | ||
958 | enum ip_conntrack_info ctinfo, | ||
959 | unsigned char **data, int dataoff, | ||
960 | Information_UUIE * info) | ||
961 | { | ||
962 | int ret; | ||
963 | int i; | ||
964 | |||
965 | DEBUGP("ip_ct_q931: Information\n"); | ||
966 | |||
967 | if (info->options & eInformation_UUIE_fastStart) { | ||
968 | for (i = 0; i < info->fastStart.count; i++) { | ||
969 | ret = process_olc(pskb, ct, ctinfo, data, dataoff, | ||
970 | &info->fastStart.item[i]); | ||
971 | if (ret < 0) | ||
972 | return -1; | ||
973 | } | ||
974 | } | ||
975 | |||
976 | return 0; | ||
977 | } | ||
978 | |||
979 | /****************************************************************************/ | ||
980 | static int process_facility(struct sk_buff **pskb, struct ip_conntrack *ct, | ||
981 | enum ip_conntrack_info ctinfo, | ||
982 | unsigned char **data, int dataoff, | ||
983 | Facility_UUIE * facility) | ||
984 | { | ||
985 | int ret; | ||
986 | int i; | ||
987 | |||
988 | DEBUGP("ip_ct_q931: Facility\n"); | ||
989 | |||
990 | if (facility->reason.choice == eFacilityReason_callForwarded) { | ||
991 | if (facility->options & eFacility_UUIE_alternativeAddress) | ||
992 | return expect_callforwarding(pskb, ct, ctinfo, data, | ||
993 | dataoff, | ||
994 | &facility-> | ||
995 | alternativeAddress); | ||
996 | return 0; | ||
997 | } | ||
998 | |||
999 | if (facility->options & eFacility_UUIE_h245Address) { | ||
1000 | ret = expect_h245(pskb, ct, ctinfo, data, dataoff, | ||
1001 | &facility->h245Address); | ||
1002 | if (ret < 0) | ||
1003 | return -1; | ||
1004 | } | ||
1005 | |||
1006 | if (facility->options & eFacility_UUIE_fastStart) { | ||
1007 | for (i = 0; i < facility->fastStart.count; i++) { | ||
1008 | ret = process_olc(pskb, ct, ctinfo, data, dataoff, | ||
1009 | &facility->fastStart.item[i]); | ||
1010 | if (ret < 0) | ||
1011 | return -1; | ||
1012 | } | ||
1013 | } | ||
1014 | |||
1015 | return 0; | ||
1016 | } | ||
1017 | |||
1018 | /****************************************************************************/ | ||
1019 | static int process_progress(struct sk_buff **pskb, struct ip_conntrack *ct, | ||
1020 | enum ip_conntrack_info ctinfo, | ||
1021 | unsigned char **data, int dataoff, | ||
1022 | Progress_UUIE * progress) | ||
1023 | { | ||
1024 | int ret; | ||
1025 | int i; | ||
1026 | |||
1027 | DEBUGP("ip_ct_q931: Progress\n"); | ||
1028 | |||
1029 | if (progress->options & eProgress_UUIE_h245Address) { | ||
1030 | ret = expect_h245(pskb, ct, ctinfo, data, dataoff, | ||
1031 | &progress->h245Address); | ||
1032 | if (ret < 0) | ||
1033 | return -1; | ||
1034 | } | ||
1035 | |||
1036 | if (progress->options & eProgress_UUIE_fastStart) { | ||
1037 | for (i = 0; i < progress->fastStart.count; i++) { | ||
1038 | ret = process_olc(pskb, ct, ctinfo, data, dataoff, | ||
1039 | &progress->fastStart.item[i]); | ||
1040 | if (ret < 0) | ||
1041 | return -1; | ||
1042 | } | ||
1043 | } | ||
1044 | |||
1045 | return 0; | ||
1046 | } | ||
1047 | |||
1048 | /****************************************************************************/ | ||
1049 | static int process_q931(struct sk_buff **pskb, struct ip_conntrack *ct, | ||
1050 | enum ip_conntrack_info ctinfo, | ||
1051 | unsigned char **data, int dataoff, Q931 * q931) | ||
1052 | { | ||
1053 | H323_UU_PDU *pdu = &q931->UUIE.h323_uu_pdu; | ||
1054 | int i; | ||
1055 | int ret = 0; | ||
1056 | |||
1057 | switch (pdu->h323_message_body.choice) { | ||
1058 | case eH323_UU_PDU_h323_message_body_setup: | ||
1059 | ret = process_setup(pskb, ct, ctinfo, data, dataoff, | ||
1060 | &pdu->h323_message_body.setup); | ||
1061 | break; | ||
1062 | case eH323_UU_PDU_h323_message_body_callProceeding: | ||
1063 | ret = process_callproceeding(pskb, ct, ctinfo, data, dataoff, | ||
1064 | &pdu->h323_message_body. | ||
1065 | callProceeding); | ||
1066 | break; | ||
1067 | case eH323_UU_PDU_h323_message_body_connect: | ||
1068 | ret = process_connect(pskb, ct, ctinfo, data, dataoff, | ||
1069 | &pdu->h323_message_body.connect); | ||
1070 | break; | ||
1071 | case eH323_UU_PDU_h323_message_body_alerting: | ||
1072 | ret = process_alerting(pskb, ct, ctinfo, data, dataoff, | ||
1073 | &pdu->h323_message_body.alerting); | ||
1074 | break; | ||
1075 | case eH323_UU_PDU_h323_message_body_information: | ||
1076 | ret = process_information(pskb, ct, ctinfo, data, dataoff, | ||
1077 | &pdu->h323_message_body. | ||
1078 | information); | ||
1079 | break; | ||
1080 | case eH323_UU_PDU_h323_message_body_facility: | ||
1081 | ret = process_facility(pskb, ct, ctinfo, data, dataoff, | ||
1082 | &pdu->h323_message_body.facility); | ||
1083 | break; | ||
1084 | case eH323_UU_PDU_h323_message_body_progress: | ||
1085 | ret = process_progress(pskb, ct, ctinfo, data, dataoff, | ||
1086 | &pdu->h323_message_body.progress); | ||
1087 | break; | ||
1088 | default: | ||
1089 | DEBUGP("ip_ct_q931: Q.931 signal %d\n", | ||
1090 | pdu->h323_message_body.choice); | ||
1091 | break; | ||
1092 | } | ||
1093 | |||
1094 | if (ret < 0) | ||
1095 | return -1; | ||
1096 | |||
1097 | if (pdu->options & eH323_UU_PDU_h245Control) { | ||
1098 | for (i = 0; i < pdu->h245Control.count; i++) { | ||
1099 | ret = process_h245(pskb, ct, ctinfo, data, dataoff, | ||
1100 | &pdu->h245Control.item[i]); | ||
1101 | if (ret < 0) | ||
1102 | return -1; | ||
1103 | } | ||
1104 | } | ||
1105 | |||
1106 | return 0; | ||
1107 | } | ||
1108 | |||
1109 | /****************************************************************************/ | ||
1110 | static int q931_help(struct sk_buff **pskb, struct ip_conntrack *ct, | ||
1111 | enum ip_conntrack_info ctinfo) | ||
1112 | { | ||
1113 | static Q931 q931; | ||
1114 | unsigned char *data = NULL; | ||
1115 | int datalen; | ||
1116 | int dataoff; | ||
1117 | int ret; | ||
1118 | |||
1119 | /* Until there's been traffic both ways, don't look in packets. */ | ||
1120 | if (ctinfo != IP_CT_ESTABLISHED | ||
1121 | && ctinfo != IP_CT_ESTABLISHED + IP_CT_IS_REPLY) { | ||
1122 | return NF_ACCEPT; | ||
1123 | } | ||
1124 | DEBUGP("ip_ct_q931: skblen = %u\n", (*pskb)->len); | ||
1125 | |||
1126 | spin_lock_bh(&ip_h323_lock); | ||
1127 | |||
1128 | /* Process each TPKT */ | ||
1129 | while (get_tpkt_data(pskb, ct, ctinfo, &data, &datalen, &dataoff)) { | ||
1130 | DEBUGP("ip_ct_q931: TPKT %u.%u.%u.%u->%u.%u.%u.%u, len=%d\n", | ||
1131 | NIPQUAD(ip_hdr(*pskb)->saddr), | ||
1132 | NIPQUAD(ip_hdr(*pskb)->daddr), datalen); | ||
1133 | |||
1134 | /* Decode Q.931 signal */ | ||
1135 | ret = DecodeQ931(data, datalen, &q931); | ||
1136 | if (ret < 0) { | ||
1137 | if (net_ratelimit()) | ||
1138 | printk("ip_ct_q931: decoding error: %s\n", | ||
1139 | ret == H323_ERROR_BOUND ? | ||
1140 | "out of bound" : "out of range"); | ||
1141 | /* We don't drop when decoding error */ | ||
1142 | break; | ||
1143 | } | ||
1144 | |||
1145 | /* Process Q.931 signal */ | ||
1146 | if (process_q931(pskb, ct, ctinfo, &data, dataoff, &q931) < 0) | ||
1147 | goto drop; | ||
1148 | } | ||
1149 | |||
1150 | spin_unlock_bh(&ip_h323_lock); | ||
1151 | return NF_ACCEPT; | ||
1152 | |||
1153 | drop: | ||
1154 | spin_unlock_bh(&ip_h323_lock); | ||
1155 | if (net_ratelimit()) | ||
1156 | printk("ip_ct_q931: packet dropped\n"); | ||
1157 | return NF_DROP; | ||
1158 | } | ||
1159 | |||
1160 | /****************************************************************************/ | ||
1161 | static struct ip_conntrack_helper ip_conntrack_helper_q931 = { | ||
1162 | .name = "Q.931", | ||
1163 | .me = THIS_MODULE, | ||
1164 | .max_expected = H323_RTP_CHANNEL_MAX * 4 + 4 /* T.120 and H.245 */ , | ||
1165 | .timeout = 240, | ||
1166 | .tuple = {.src = {.u = {.tcp = {.port = __constant_htons(Q931_PORT)}}}, | ||
1167 | .dst = {.protonum = IPPROTO_TCP}}, | ||
1168 | .mask = {.src = {.u = {0xFFFF}}, | ||
1169 | .dst = {.protonum = 0xFF}}, | ||
1170 | .help = q931_help | ||
1171 | }; | ||
1172 | |||
1173 | /****************************************************************************/ | ||
1174 | void ip_conntrack_q931_expect(struct ip_conntrack *new, | ||
1175 | struct ip_conntrack_expect *this) | ||
1176 | { | ||
1177 | write_lock_bh(&ip_conntrack_lock); | ||
1178 | new->helper = &ip_conntrack_helper_q931; | ||
1179 | write_unlock_bh(&ip_conntrack_lock); | ||
1180 | } | ||
1181 | |||
1182 | /****************************************************************************/ | ||
1183 | static unsigned char *get_udp_data(struct sk_buff **pskb, int *datalen) | ||
1184 | { | ||
1185 | struct udphdr _uh, *uh; | ||
1186 | int dataoff; | ||
1187 | |||
1188 | uh = skb_header_pointer(*pskb, ip_hdrlen(*pskb), sizeof(_uh), &_uh); | ||
1189 | if (uh == NULL) | ||
1190 | return NULL; | ||
1191 | dataoff = ip_hdrlen(*pskb) + sizeof(_uh); | ||
1192 | if (dataoff >= (*pskb)->len) | ||
1193 | return NULL; | ||
1194 | *datalen = (*pskb)->len - dataoff; | ||
1195 | return skb_header_pointer(*pskb, dataoff, *datalen, h323_buffer); | ||
1196 | } | ||
1197 | |||
1198 | /****************************************************************************/ | ||
1199 | static struct ip_conntrack_expect *find_expect(struct ip_conntrack *ct, | ||
1200 | __be32 ip, u_int16_t port) | ||
1201 | { | ||
1202 | struct ip_conntrack_expect *exp; | ||
1203 | struct ip_conntrack_tuple tuple; | ||
1204 | |||
1205 | tuple.src.ip = 0; | ||
1206 | tuple.src.u.tcp.port = 0; | ||
1207 | tuple.dst.ip = ip; | ||
1208 | tuple.dst.u.tcp.port = htons(port); | ||
1209 | tuple.dst.protonum = IPPROTO_TCP; | ||
1210 | |||
1211 | exp = __ip_conntrack_expect_find(&tuple); | ||
1212 | if (exp && exp->master == ct) | ||
1213 | return exp; | ||
1214 | return NULL; | ||
1215 | } | ||
1216 | |||
1217 | /****************************************************************************/ | ||
1218 | static int set_expect_timeout(struct ip_conntrack_expect *exp, | ||
1219 | unsigned timeout) | ||
1220 | { | ||
1221 | if (!exp || !del_timer(&exp->timeout)) | ||
1222 | return 0; | ||
1223 | |||
1224 | exp->timeout.expires = jiffies + timeout * HZ; | ||
1225 | add_timer(&exp->timeout); | ||
1226 | |||
1227 | return 1; | ||
1228 | } | ||
1229 | |||
1230 | /****************************************************************************/ | ||
1231 | static int expect_q931(struct sk_buff **pskb, struct ip_conntrack *ct, | ||
1232 | enum ip_conntrack_info ctinfo, | ||
1233 | unsigned char **data, | ||
1234 | TransportAddress * addr, int count) | ||
1235 | { | ||
1236 | struct ip_ct_h323_master *info = &ct->help.ct_h323_info; | ||
1237 | int dir = CTINFO2DIR(ctinfo); | ||
1238 | int ret = 0; | ||
1239 | int i; | ||
1240 | __be32 ip; | ||
1241 | u_int16_t port; | ||
1242 | struct ip_conntrack_expect *exp; | ||
1243 | typeof(nat_q931_hook) nat_q931; | ||
1244 | |||
1245 | /* Look for the first related address */ | ||
1246 | for (i = 0; i < count; i++) { | ||
1247 | if (get_h225_addr(*data, &addr[i], &ip, &port) && | ||
1248 | ip == ct->tuplehash[dir].tuple.src.ip && port != 0) | ||
1249 | break; | ||
1250 | } | ||
1251 | |||
1252 | if (i >= count) /* Not found */ | ||
1253 | return 0; | ||
1254 | |||
1255 | /* Create expect for Q.931 */ | ||
1256 | if ((exp = ip_conntrack_expect_alloc(ct)) == NULL) | ||
1257 | return -1; | ||
1258 | exp->tuple.src.ip = gkrouted_only ? /* only accept calls from GK? */ | ||
1259 | ct->tuplehash[!dir].tuple.src.ip : 0; | ||
1260 | exp->tuple.src.u.tcp.port = 0; | ||
1261 | exp->tuple.dst.ip = ct->tuplehash[!dir].tuple.dst.ip; | ||
1262 | exp->tuple.dst.u.tcp.port = htons(port); | ||
1263 | exp->tuple.dst.protonum = IPPROTO_TCP; | ||
1264 | exp->mask.src.ip = gkrouted_only ? htonl(0xFFFFFFFF) : 0; | ||
1265 | exp->mask.src.u.tcp.port = 0; | ||
1266 | exp->mask.dst.ip = htonl(0xFFFFFFFF); | ||
1267 | exp->mask.dst.u.tcp.port = htons(0xFFFF); | ||
1268 | exp->mask.dst.protonum = 0xFF; | ||
1269 | exp->flags = IP_CT_EXPECT_PERMANENT; /* Accept multiple calls */ | ||
1270 | |||
1271 | nat_q931 = rcu_dereference(nat_q931_hook); | ||
1272 | if (nat_q931) { /* Need NAT */ | ||
1273 | ret = nat_q931(pskb, ct, ctinfo, data, addr, i, port, exp); | ||
1274 | } else { /* Conntrack only */ | ||
1275 | exp->expectfn = ip_conntrack_q931_expect; | ||
1276 | |||
1277 | if (ip_conntrack_expect_related(exp) == 0) { | ||
1278 | DEBUGP("ip_ct_ras: expect Q.931 " | ||
1279 | "%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n", | ||
1280 | NIPQUAD(exp->tuple.src.ip), | ||
1281 | ntohs(exp->tuple.src.u.tcp.port), | ||
1282 | NIPQUAD(exp->tuple.dst.ip), | ||
1283 | ntohs(exp->tuple.dst.u.tcp.port)); | ||
1284 | |||
1285 | /* Save port for looking up expect in processing RCF */ | ||
1286 | info->sig_port[dir] = port; | ||
1287 | } else | ||
1288 | ret = -1; | ||
1289 | } | ||
1290 | |||
1291 | ip_conntrack_expect_put(exp); | ||
1292 | |||
1293 | return ret; | ||
1294 | } | ||
1295 | |||
1296 | /****************************************************************************/ | ||
1297 | static int process_grq(struct sk_buff **pskb, struct ip_conntrack *ct, | ||
1298 | enum ip_conntrack_info ctinfo, | ||
1299 | unsigned char **data, GatekeeperRequest * grq) | ||
1300 | { | ||
1301 | typeof(set_ras_addr_hook) set_ras_addr; | ||
1302 | |||
1303 | DEBUGP("ip_ct_ras: GRQ\n"); | ||
1304 | |||
1305 | set_ras_addr = rcu_dereference(set_ras_addr_hook); | ||
1306 | if (set_ras_addr) /* NATed */ | ||
1307 | return set_ras_addr(pskb, ct, ctinfo, data, | ||
1308 | &grq->rasAddress, 1); | ||
1309 | return 0; | ||
1310 | } | ||
1311 | |||
1312 | /* Declare before using */ | ||
1313 | static void ip_conntrack_ras_expect(struct ip_conntrack *new, | ||
1314 | struct ip_conntrack_expect *this); | ||
1315 | |||
1316 | /****************************************************************************/ | ||
1317 | static int process_gcf(struct sk_buff **pskb, struct ip_conntrack *ct, | ||
1318 | enum ip_conntrack_info ctinfo, | ||
1319 | unsigned char **data, GatekeeperConfirm * gcf) | ||
1320 | { | ||
1321 | int dir = CTINFO2DIR(ctinfo); | ||
1322 | int ret = 0; | ||
1323 | __be32 ip; | ||
1324 | u_int16_t port; | ||
1325 | struct ip_conntrack_expect *exp; | ||
1326 | |||
1327 | DEBUGP("ip_ct_ras: GCF\n"); | ||
1328 | |||
1329 | if (!get_h225_addr(*data, &gcf->rasAddress, &ip, &port)) | ||
1330 | return 0; | ||
1331 | |||
1332 | /* Registration port is the same as discovery port */ | ||
1333 | if (ip == ct->tuplehash[dir].tuple.src.ip && | ||
1334 | port == ntohs(ct->tuplehash[dir].tuple.src.u.udp.port)) | ||
1335 | return 0; | ||
1336 | |||
1337 | /* Avoid RAS expectation loops. A GCF is never expected. */ | ||
1338 | if (test_bit(IPS_EXPECTED_BIT, &ct->status)) | ||
1339 | return 0; | ||
1340 | |||
1341 | /* Need new expect */ | ||
1342 | if ((exp = ip_conntrack_expect_alloc(ct)) == NULL) | ||
1343 | return -1; | ||
1344 | exp->tuple.src.ip = ct->tuplehash[!dir].tuple.src.ip; | ||
1345 | exp->tuple.src.u.tcp.port = 0; | ||
1346 | exp->tuple.dst.ip = ip; | ||
1347 | exp->tuple.dst.u.tcp.port = htons(port); | ||
1348 | exp->tuple.dst.protonum = IPPROTO_UDP; | ||
1349 | exp->mask.src.ip = htonl(0xFFFFFFFF); | ||
1350 | exp->mask.src.u.tcp.port = 0; | ||
1351 | exp->mask.dst.ip = htonl(0xFFFFFFFF); | ||
1352 | exp->mask.dst.u.tcp.port = htons(0xFFFF); | ||
1353 | exp->mask.dst.protonum = 0xFF; | ||
1354 | exp->flags = 0; | ||
1355 | exp->expectfn = ip_conntrack_ras_expect; | ||
1356 | if (ip_conntrack_expect_related(exp) == 0) { | ||
1357 | DEBUGP("ip_ct_ras: expect RAS " | ||
1358 | "%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n", | ||
1359 | NIPQUAD(exp->tuple.src.ip), | ||
1360 | ntohs(exp->tuple.src.u.tcp.port), | ||
1361 | NIPQUAD(exp->tuple.dst.ip), | ||
1362 | ntohs(exp->tuple.dst.u.tcp.port)); | ||
1363 | } else | ||
1364 | ret = -1; | ||
1365 | |||
1366 | ip_conntrack_expect_put(exp); | ||
1367 | |||
1368 | return ret; | ||
1369 | } | ||
1370 | |||
1371 | /****************************************************************************/ | ||
1372 | static int process_rrq(struct sk_buff **pskb, struct ip_conntrack *ct, | ||
1373 | enum ip_conntrack_info ctinfo, | ||
1374 | unsigned char **data, RegistrationRequest * rrq) | ||
1375 | { | ||
1376 | struct ip_ct_h323_master *info = &ct->help.ct_h323_info; | ||
1377 | int ret; | ||
1378 | typeof(set_ras_addr_hook) set_ras_addr; | ||
1379 | |||
1380 | DEBUGP("ip_ct_ras: RRQ\n"); | ||
1381 | |||
1382 | ret = expect_q931(pskb, ct, ctinfo, data, | ||
1383 | rrq->callSignalAddress.item, | ||
1384 | rrq->callSignalAddress.count); | ||
1385 | if (ret < 0) | ||
1386 | return -1; | ||
1387 | |||
1388 | set_ras_addr = rcu_dereference(set_ras_addr_hook); | ||
1389 | if (set_ras_addr) { | ||
1390 | ret = set_ras_addr(pskb, ct, ctinfo, data, | ||
1391 | rrq->rasAddress.item, | ||
1392 | rrq->rasAddress.count); | ||
1393 | if (ret < 0) | ||
1394 | return -1; | ||
1395 | } | ||
1396 | |||
1397 | if (rrq->options & eRegistrationRequest_timeToLive) { | ||
1398 | DEBUGP("ip_ct_ras: RRQ TTL = %u seconds\n", rrq->timeToLive); | ||
1399 | info->timeout = rrq->timeToLive; | ||
1400 | } else | ||
1401 | info->timeout = default_rrq_ttl; | ||
1402 | |||
1403 | return 0; | ||
1404 | } | ||
1405 | |||
1406 | /****************************************************************************/ | ||
1407 | static int process_rcf(struct sk_buff **pskb, struct ip_conntrack *ct, | ||
1408 | enum ip_conntrack_info ctinfo, | ||
1409 | unsigned char **data, RegistrationConfirm * rcf) | ||
1410 | { | ||
1411 | struct ip_ct_h323_master *info = &ct->help.ct_h323_info; | ||
1412 | int dir = CTINFO2DIR(ctinfo); | ||
1413 | int ret; | ||
1414 | struct ip_conntrack_expect *exp; | ||
1415 | typeof(set_sig_addr_hook) set_sig_addr; | ||
1416 | |||
1417 | DEBUGP("ip_ct_ras: RCF\n"); | ||
1418 | |||
1419 | set_sig_addr = rcu_dereference(set_sig_addr_hook); | ||
1420 | if (set_sig_addr) { | ||
1421 | ret = set_sig_addr(pskb, ct, ctinfo, data, | ||
1422 | rcf->callSignalAddress.item, | ||
1423 | rcf->callSignalAddress.count); | ||
1424 | if (ret < 0) | ||
1425 | return -1; | ||
1426 | } | ||
1427 | |||
1428 | if (rcf->options & eRegistrationConfirm_timeToLive) { | ||
1429 | DEBUGP("ip_ct_ras: RCF TTL = %u seconds\n", rcf->timeToLive); | ||
1430 | info->timeout = rcf->timeToLive; | ||
1431 | } | ||
1432 | |||
1433 | if (info->timeout > 0) { | ||
1434 | DEBUGP | ||
1435 | ("ip_ct_ras: set RAS connection timeout to %u seconds\n", | ||
1436 | info->timeout); | ||
1437 | ip_ct_refresh(ct, *pskb, info->timeout * HZ); | ||
1438 | |||
1439 | /* Set expect timeout */ | ||
1440 | read_lock_bh(&ip_conntrack_lock); | ||
1441 | exp = find_expect(ct, ct->tuplehash[dir].tuple.dst.ip, | ||
1442 | info->sig_port[!dir]); | ||
1443 | if (exp) { | ||
1444 | DEBUGP("ip_ct_ras: set Q.931 expect " | ||
1445 | "(%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu) " | ||
1446 | "timeout to %u seconds\n", | ||
1447 | NIPQUAD(exp->tuple.src.ip), | ||
1448 | ntohs(exp->tuple.src.u.tcp.port), | ||
1449 | NIPQUAD(exp->tuple.dst.ip), | ||
1450 | ntohs(exp->tuple.dst.u.tcp.port), | ||
1451 | info->timeout); | ||
1452 | set_expect_timeout(exp, info->timeout); | ||
1453 | } | ||
1454 | read_unlock_bh(&ip_conntrack_lock); | ||
1455 | } | ||
1456 | |||
1457 | return 0; | ||
1458 | } | ||
1459 | |||
1460 | /****************************************************************************/ | ||
1461 | static int process_urq(struct sk_buff **pskb, struct ip_conntrack *ct, | ||
1462 | enum ip_conntrack_info ctinfo, | ||
1463 | unsigned char **data, UnregistrationRequest * urq) | ||
1464 | { | ||
1465 | struct ip_ct_h323_master *info = &ct->help.ct_h323_info; | ||
1466 | int dir = CTINFO2DIR(ctinfo); | ||
1467 | int ret; | ||
1468 | typeof(set_sig_addr_hook) set_sig_addr; | ||
1469 | |||
1470 | DEBUGP("ip_ct_ras: URQ\n"); | ||
1471 | |||
1472 | set_sig_addr = rcu_dereference(set_sig_addr_hook); | ||
1473 | if (set_sig_addr) { | ||
1474 | ret = set_sig_addr(pskb, ct, ctinfo, data, | ||
1475 | urq->callSignalAddress.item, | ||
1476 | urq->callSignalAddress.count); | ||
1477 | if (ret < 0) | ||
1478 | return -1; | ||
1479 | } | ||
1480 | |||
1481 | /* Clear old expect */ | ||
1482 | ip_ct_remove_expectations(ct); | ||
1483 | info->sig_port[dir] = 0; | ||
1484 | info->sig_port[!dir] = 0; | ||
1485 | |||
1486 | /* Give it 30 seconds for UCF or URJ */ | ||
1487 | ip_ct_refresh(ct, *pskb, 30 * HZ); | ||
1488 | |||
1489 | return 0; | ||
1490 | } | ||
1491 | |||
1492 | /****************************************************************************/ | ||
1493 | static int process_arq(struct sk_buff **pskb, struct ip_conntrack *ct, | ||
1494 | enum ip_conntrack_info ctinfo, | ||
1495 | unsigned char **data, AdmissionRequest * arq) | ||
1496 | { | ||
1497 | struct ip_ct_h323_master *info = &ct->help.ct_h323_info; | ||
1498 | int dir = CTINFO2DIR(ctinfo); | ||
1499 | __be32 ip; | ||
1500 | u_int16_t port; | ||
1501 | typeof(set_h225_addr_hook) set_h225_addr; | ||
1502 | |||
1503 | DEBUGP("ip_ct_ras: ARQ\n"); | ||
1504 | |||
1505 | set_h225_addr = rcu_dereference(set_h225_addr_hook); | ||
1506 | if ((arq->options & eAdmissionRequest_destCallSignalAddress) && | ||
1507 | get_h225_addr(*data, &arq->destCallSignalAddress, &ip, &port) && | ||
1508 | ip == ct->tuplehash[dir].tuple.src.ip && | ||
1509 | port == info->sig_port[dir] && set_h225_addr) { | ||
1510 | /* Answering ARQ */ | ||
1511 | return set_h225_addr(pskb, data, 0, | ||
1512 | &arq->destCallSignalAddress, | ||
1513 | ct->tuplehash[!dir].tuple.dst.ip, | ||
1514 | info->sig_port[!dir]); | ||
1515 | } | ||
1516 | |||
1517 | if ((arq->options & eAdmissionRequest_srcCallSignalAddress) && | ||
1518 | get_h225_addr(*data, &arq->srcCallSignalAddress, &ip, &port) && | ||
1519 | ip == ct->tuplehash[dir].tuple.src.ip && set_h225_addr) { | ||
1520 | /* Calling ARQ */ | ||
1521 | return set_h225_addr(pskb, data, 0, | ||
1522 | &arq->srcCallSignalAddress, | ||
1523 | ct->tuplehash[!dir].tuple.dst.ip, | ||
1524 | port); | ||
1525 | } | ||
1526 | |||
1527 | return 0; | ||
1528 | } | ||
1529 | |||
1530 | /****************************************************************************/ | ||
1531 | static int process_acf(struct sk_buff **pskb, struct ip_conntrack *ct, | ||
1532 | enum ip_conntrack_info ctinfo, | ||
1533 | unsigned char **data, AdmissionConfirm * acf) | ||
1534 | { | ||
1535 | int dir = CTINFO2DIR(ctinfo); | ||
1536 | int ret = 0; | ||
1537 | __be32 ip; | ||
1538 | u_int16_t port; | ||
1539 | struct ip_conntrack_expect *exp; | ||
1540 | typeof(set_sig_addr_hook) set_sig_addr; | ||
1541 | |||
1542 | DEBUGP("ip_ct_ras: ACF\n"); | ||
1543 | |||
1544 | if (!get_h225_addr(*data, &acf->destCallSignalAddress, &ip, &port)) | ||
1545 | return 0; | ||
1546 | |||
1547 | if (ip == ct->tuplehash[dir].tuple.dst.ip) { /* Answering ACF */ | ||
1548 | set_sig_addr = rcu_dereference(set_sig_addr_hook); | ||
1549 | if (set_sig_addr) | ||
1550 | return set_sig_addr(pskb, ct, ctinfo, data, | ||
1551 | &acf->destCallSignalAddress, 1); | ||
1552 | return 0; | ||
1553 | } | ||
1554 | |||
1555 | /* Need new expect */ | ||
1556 | if ((exp = ip_conntrack_expect_alloc(ct)) == NULL) | ||
1557 | return -1; | ||
1558 | exp->tuple.src.ip = ct->tuplehash[!dir].tuple.src.ip; | ||
1559 | exp->tuple.src.u.tcp.port = 0; | ||
1560 | exp->tuple.dst.ip = ip; | ||
1561 | exp->tuple.dst.u.tcp.port = htons(port); | ||
1562 | exp->tuple.dst.protonum = IPPROTO_TCP; | ||
1563 | exp->mask.src.ip = htonl(0xFFFFFFFF); | ||
1564 | exp->mask.src.u.tcp.port = 0; | ||
1565 | exp->mask.dst.ip = htonl(0xFFFFFFFF); | ||
1566 | exp->mask.dst.u.tcp.port = htons(0xFFFF); | ||
1567 | exp->mask.dst.protonum = 0xFF; | ||
1568 | exp->flags = IP_CT_EXPECT_PERMANENT; | ||
1569 | exp->expectfn = ip_conntrack_q931_expect; | ||
1570 | |||
1571 | if (ip_conntrack_expect_related(exp) == 0) { | ||
1572 | DEBUGP("ip_ct_ras: expect Q.931 " | ||
1573 | "%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n", | ||
1574 | NIPQUAD(exp->tuple.src.ip), | ||
1575 | ntohs(exp->tuple.src.u.tcp.port), | ||
1576 | NIPQUAD(exp->tuple.dst.ip), | ||
1577 | ntohs(exp->tuple.dst.u.tcp.port)); | ||
1578 | } else | ||
1579 | ret = -1; | ||
1580 | |||
1581 | ip_conntrack_expect_put(exp); | ||
1582 | |||
1583 | return ret; | ||
1584 | } | ||
1585 | |||
1586 | /****************************************************************************/ | ||
1587 | static int process_lrq(struct sk_buff **pskb, struct ip_conntrack *ct, | ||
1588 | enum ip_conntrack_info ctinfo, | ||
1589 | unsigned char **data, LocationRequest * lrq) | ||
1590 | { | ||
1591 | typeof(set_ras_addr_hook) set_ras_addr; | ||
1592 | |||
1593 | DEBUGP("ip_ct_ras: LRQ\n"); | ||
1594 | |||
1595 | set_ras_addr = rcu_dereference(set_ras_addr_hook); | ||
1596 | if (set_ras_addr) | ||
1597 | return set_ras_addr(pskb, ct, ctinfo, data, | ||
1598 | &lrq->replyAddress, 1); | ||
1599 | return 0; | ||
1600 | } | ||
1601 | |||
1602 | /****************************************************************************/ | ||
1603 | static int process_lcf(struct sk_buff **pskb, struct ip_conntrack *ct, | ||
1604 | enum ip_conntrack_info ctinfo, | ||
1605 | unsigned char **data, LocationConfirm * lcf) | ||
1606 | { | ||
1607 | int dir = CTINFO2DIR(ctinfo); | ||
1608 | int ret = 0; | ||
1609 | __be32 ip; | ||
1610 | u_int16_t port; | ||
1611 | struct ip_conntrack_expect *exp = NULL; | ||
1612 | |||
1613 | DEBUGP("ip_ct_ras: LCF\n"); | ||
1614 | |||
1615 | if (!get_h225_addr(*data, &lcf->callSignalAddress, &ip, &port)) | ||
1616 | return 0; | ||
1617 | |||
1618 | /* Need new expect for call signal */ | ||
1619 | if ((exp = ip_conntrack_expect_alloc(ct)) == NULL) | ||
1620 | return -1; | ||
1621 | exp->tuple.src.ip = ct->tuplehash[!dir].tuple.src.ip; | ||
1622 | exp->tuple.src.u.tcp.port = 0; | ||
1623 | exp->tuple.dst.ip = ip; | ||
1624 | exp->tuple.dst.u.tcp.port = htons(port); | ||
1625 | exp->tuple.dst.protonum = IPPROTO_TCP; | ||
1626 | exp->mask.src.ip = htonl(0xFFFFFFFF); | ||
1627 | exp->mask.src.u.tcp.port = 0; | ||
1628 | exp->mask.dst.ip = htonl(0xFFFFFFFF); | ||
1629 | exp->mask.dst.u.tcp.port = htons(0xFFFF); | ||
1630 | exp->mask.dst.protonum = 0xFF; | ||
1631 | exp->flags = IP_CT_EXPECT_PERMANENT; | ||
1632 | exp->expectfn = ip_conntrack_q931_expect; | ||
1633 | |||
1634 | if (ip_conntrack_expect_related(exp) == 0) { | ||
1635 | DEBUGP("ip_ct_ras: expect Q.931 " | ||
1636 | "%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n", | ||
1637 | NIPQUAD(exp->tuple.src.ip), | ||
1638 | ntohs(exp->tuple.src.u.tcp.port), | ||
1639 | NIPQUAD(exp->tuple.dst.ip), | ||
1640 | ntohs(exp->tuple.dst.u.tcp.port)); | ||
1641 | } else | ||
1642 | ret = -1; | ||
1643 | |||
1644 | ip_conntrack_expect_put(exp); | ||
1645 | |||
1646 | /* Ignore rasAddress */ | ||
1647 | |||
1648 | return ret; | ||
1649 | } | ||
1650 | |||
1651 | /****************************************************************************/ | ||
1652 | static int process_irr(struct sk_buff **pskb, struct ip_conntrack *ct, | ||
1653 | enum ip_conntrack_info ctinfo, | ||
1654 | unsigned char **data, InfoRequestResponse * irr) | ||
1655 | { | ||
1656 | int ret; | ||
1657 | typeof(set_ras_addr_hook) set_ras_addr; | ||
1658 | typeof(set_sig_addr_hook) set_sig_addr; | ||
1659 | |||
1660 | DEBUGP("ip_ct_ras: IRR\n"); | ||
1661 | |||
1662 | set_ras_addr = rcu_dereference(set_ras_addr_hook); | ||
1663 | if (set_ras_addr) { | ||
1664 | ret = set_ras_addr(pskb, ct, ctinfo, data, | ||
1665 | &irr->rasAddress, 1); | ||
1666 | if (ret < 0) | ||
1667 | return -1; | ||
1668 | } | ||
1669 | |||
1670 | set_sig_addr = rcu_dereference(set_sig_addr_hook); | ||
1671 | if (set_sig_addr) { | ||
1672 | ret = set_sig_addr(pskb, ct, ctinfo, data, | ||
1673 | irr->callSignalAddress.item, | ||
1674 | irr->callSignalAddress.count); | ||
1675 | if (ret < 0) | ||
1676 | return -1; | ||
1677 | } | ||
1678 | |||
1679 | return 0; | ||
1680 | } | ||
1681 | |||
1682 | /****************************************************************************/ | ||
1683 | static int process_ras(struct sk_buff **pskb, struct ip_conntrack *ct, | ||
1684 | enum ip_conntrack_info ctinfo, | ||
1685 | unsigned char **data, RasMessage * ras) | ||
1686 | { | ||
1687 | switch (ras->choice) { | ||
1688 | case eRasMessage_gatekeeperRequest: | ||
1689 | return process_grq(pskb, ct, ctinfo, data, | ||
1690 | &ras->gatekeeperRequest); | ||
1691 | case eRasMessage_gatekeeperConfirm: | ||
1692 | return process_gcf(pskb, ct, ctinfo, data, | ||
1693 | &ras->gatekeeperConfirm); | ||
1694 | case eRasMessage_registrationRequest: | ||
1695 | return process_rrq(pskb, ct, ctinfo, data, | ||
1696 | &ras->registrationRequest); | ||
1697 | case eRasMessage_registrationConfirm: | ||
1698 | return process_rcf(pskb, ct, ctinfo, data, | ||
1699 | &ras->registrationConfirm); | ||
1700 | case eRasMessage_unregistrationRequest: | ||
1701 | return process_urq(pskb, ct, ctinfo, data, | ||
1702 | &ras->unregistrationRequest); | ||
1703 | case eRasMessage_admissionRequest: | ||
1704 | return process_arq(pskb, ct, ctinfo, data, | ||
1705 | &ras->admissionRequest); | ||
1706 | case eRasMessage_admissionConfirm: | ||
1707 | return process_acf(pskb, ct, ctinfo, data, | ||
1708 | &ras->admissionConfirm); | ||
1709 | case eRasMessage_locationRequest: | ||
1710 | return process_lrq(pskb, ct, ctinfo, data, | ||
1711 | &ras->locationRequest); | ||
1712 | case eRasMessage_locationConfirm: | ||
1713 | return process_lcf(pskb, ct, ctinfo, data, | ||
1714 | &ras->locationConfirm); | ||
1715 | case eRasMessage_infoRequestResponse: | ||
1716 | return process_irr(pskb, ct, ctinfo, data, | ||
1717 | &ras->infoRequestResponse); | ||
1718 | default: | ||
1719 | DEBUGP("ip_ct_ras: RAS message %d\n", ras->choice); | ||
1720 | break; | ||
1721 | } | ||
1722 | |||
1723 | return 0; | ||
1724 | } | ||
1725 | |||
1726 | /****************************************************************************/ | ||
1727 | static int ras_help(struct sk_buff **pskb, struct ip_conntrack *ct, | ||
1728 | enum ip_conntrack_info ctinfo) | ||
1729 | { | ||
1730 | static RasMessage ras; | ||
1731 | unsigned char *data; | ||
1732 | int datalen = 0; | ||
1733 | int ret; | ||
1734 | |||
1735 | DEBUGP("ip_ct_ras: skblen = %u\n", (*pskb)->len); | ||
1736 | |||
1737 | spin_lock_bh(&ip_h323_lock); | ||
1738 | |||
1739 | /* Get UDP data */ | ||
1740 | data = get_udp_data(pskb, &datalen); | ||
1741 | if (data == NULL) | ||
1742 | goto accept; | ||
1743 | DEBUGP("ip_ct_ras: RAS message %u.%u.%u.%u->%u.%u.%u.%u, len=%d\n", | ||
1744 | NIPQUAD(ip_hdr(*pskb)->saddr), | ||
1745 | NIPQUAD(ip_hdr(*pskb)->daddr), datalen); | ||
1746 | |||
1747 | /* Decode RAS message */ | ||
1748 | ret = DecodeRasMessage(data, datalen, &ras); | ||
1749 | if (ret < 0) { | ||
1750 | if (net_ratelimit()) | ||
1751 | printk("ip_ct_ras: decoding error: %s\n", | ||
1752 | ret == H323_ERROR_BOUND ? | ||
1753 | "out of bound" : "out of range"); | ||
1754 | goto accept; | ||
1755 | } | ||
1756 | |||
1757 | /* Process RAS message */ | ||
1758 | if (process_ras(pskb, ct, ctinfo, &data, &ras) < 0) | ||
1759 | goto drop; | ||
1760 | |||
1761 | accept: | ||
1762 | spin_unlock_bh(&ip_h323_lock); | ||
1763 | return NF_ACCEPT; | ||
1764 | |||
1765 | drop: | ||
1766 | spin_unlock_bh(&ip_h323_lock); | ||
1767 | if (net_ratelimit()) | ||
1768 | printk("ip_ct_ras: packet dropped\n"); | ||
1769 | return NF_DROP; | ||
1770 | } | ||
1771 | |||
1772 | /****************************************************************************/ | ||
1773 | static struct ip_conntrack_helper ip_conntrack_helper_ras = { | ||
1774 | .name = "RAS", | ||
1775 | .me = THIS_MODULE, | ||
1776 | .max_expected = 32, | ||
1777 | .timeout = 240, | ||
1778 | .tuple = {.src = {.u = {.tcp = {.port = __constant_htons(RAS_PORT)}}}, | ||
1779 | .dst = {.protonum = IPPROTO_UDP}}, | ||
1780 | .mask = {.src = {.u = {0xFFFE}}, | ||
1781 | .dst = {.protonum = 0xFF}}, | ||
1782 | .help = ras_help, | ||
1783 | }; | ||
1784 | |||
1785 | /****************************************************************************/ | ||
1786 | static void ip_conntrack_ras_expect(struct ip_conntrack *new, | ||
1787 | struct ip_conntrack_expect *this) | ||
1788 | { | ||
1789 | write_lock_bh(&ip_conntrack_lock); | ||
1790 | new->helper = &ip_conntrack_helper_ras; | ||
1791 | write_unlock_bh(&ip_conntrack_lock); | ||
1792 | } | ||
1793 | |||
1794 | /****************************************************************************/ | ||
1795 | /* Not __exit - called from init() */ | ||
1796 | static void fini(void) | ||
1797 | { | ||
1798 | ip_conntrack_helper_unregister(&ip_conntrack_helper_ras); | ||
1799 | ip_conntrack_helper_unregister(&ip_conntrack_helper_q931); | ||
1800 | kfree(h323_buffer); | ||
1801 | DEBUGP("ip_ct_h323: fini\n"); | ||
1802 | } | ||
1803 | |||
1804 | /****************************************************************************/ | ||
1805 | static int __init init(void) | ||
1806 | { | ||
1807 | int ret; | ||
1808 | |||
1809 | h323_buffer = kmalloc(65536, GFP_KERNEL); | ||
1810 | if (!h323_buffer) | ||
1811 | return -ENOMEM; | ||
1812 | if ((ret = ip_conntrack_helper_register(&ip_conntrack_helper_q931)) || | ||
1813 | (ret = ip_conntrack_helper_register(&ip_conntrack_helper_ras))) { | ||
1814 | fini(); | ||
1815 | return ret; | ||
1816 | } | ||
1817 | DEBUGP("ip_ct_h323: init success\n"); | ||
1818 | return 0; | ||
1819 | } | ||
1820 | |||
1821 | /****************************************************************************/ | ||
1822 | module_init(init); | ||
1823 | module_exit(fini); | ||
1824 | |||
1825 | EXPORT_SYMBOL_GPL(get_h225_addr); | ||
1826 | EXPORT_SYMBOL_GPL(ip_conntrack_h245_expect); | ||
1827 | EXPORT_SYMBOL_GPL(ip_conntrack_q931_expect); | ||
1828 | EXPORT_SYMBOL_GPL(set_h245_addr_hook); | ||
1829 | EXPORT_SYMBOL_GPL(set_h225_addr_hook); | ||
1830 | EXPORT_SYMBOL_GPL(set_sig_addr_hook); | ||
1831 | EXPORT_SYMBOL_GPL(set_ras_addr_hook); | ||
1832 | EXPORT_SYMBOL_GPL(nat_rtp_rtcp_hook); | ||
1833 | EXPORT_SYMBOL_GPL(nat_t120_hook); | ||
1834 | EXPORT_SYMBOL_GPL(nat_h245_hook); | ||
1835 | EXPORT_SYMBOL_GPL(nat_callforwarding_hook); | ||
1836 | EXPORT_SYMBOL_GPL(nat_q931_hook); | ||
1837 | |||
1838 | MODULE_AUTHOR("Jing Min Zhao <zhaojingmin@users.sourceforge.net>"); | ||
1839 | MODULE_DESCRIPTION("H.323 connection tracking helper"); | ||
1840 | MODULE_LICENSE("GPL"); | ||
diff --git a/net/ipv4/netfilter/ip_conntrack_helper_pptp.c b/net/ipv4/netfilter/ip_conntrack_helper_pptp.c deleted file mode 100644 index f5ab8e4b97cb..000000000000 --- a/net/ipv4/netfilter/ip_conntrack_helper_pptp.c +++ /dev/null | |||
@@ -1,684 +0,0 @@ | |||
1 | /* | ||
2 | * ip_conntrack_pptp.c - Version 3.0 | ||
3 | * | ||
4 | * Connection tracking support for PPTP (Point to Point Tunneling Protocol). | ||
5 | * PPTP is a a protocol for creating virtual private networks. | ||
6 | * It is a specification defined by Microsoft and some vendors | ||
7 | * working with Microsoft. PPTP is built on top of a modified | ||
8 | * version of the Internet Generic Routing Encapsulation Protocol. | ||
9 | * GRE is defined in RFC 1701 and RFC 1702. Documentation of | ||
10 | * PPTP can be found in RFC 2637 | ||
11 | * | ||
12 | * (C) 2000-2005 by Harald Welte <laforge@gnumonks.org> | ||
13 | * | ||
14 | * Development of this code funded by Astaro AG (http://www.astaro.com/) | ||
15 | * | ||
16 | * Limitations: | ||
17 | * - We blindly assume that control connections are always | ||
18 | * established in PNS->PAC direction. This is a violation | ||
19 | * of RFFC2673 | ||
20 | * - We can only support one single call within each session | ||
21 | * | ||
22 | * TODO: | ||
23 | * - testing of incoming PPTP calls | ||
24 | * | ||
25 | * Changes: | ||
26 | * 2002-02-05 - Version 1.3 | ||
27 | * - Call ip_conntrack_unexpect_related() from | ||
28 | * pptp_destroy_siblings() to destroy expectations in case | ||
29 | * CALL_DISCONNECT_NOTIFY or tcp fin packet was seen | ||
30 | * (Philip Craig <philipc@snapgear.com>) | ||
31 | * - Add Version information at module loadtime | ||
32 | * 2002-02-10 - Version 1.6 | ||
33 | * - move to C99 style initializers | ||
34 | * - remove second expectation if first arrives | ||
35 | * 2004-10-22 - Version 2.0 | ||
36 | * - merge Mandrake's 2.6.x port with recent 2.6.x API changes | ||
37 | * - fix lots of linear skb assumptions from Mandrake's port | ||
38 | * 2005-06-10 - Version 2.1 | ||
39 | * - use ip_conntrack_expect_free() instead of kfree() on the | ||
40 | * expect's (which are from the slab for quite some time) | ||
41 | * 2005-06-10 - Version 3.0 | ||
42 | * - port helper to post-2.6.11 API changes, | ||
43 | * funded by Oxcoda NetBox Blue (http://www.netboxblue.com/) | ||
44 | * 2005-07-30 - Version 3.1 | ||
45 | * - port helper to 2.6.13 API changes | ||
46 | * | ||
47 | */ | ||
48 | |||
49 | #include <linux/module.h> | ||
50 | #include <linux/netfilter.h> | ||
51 | #include <linux/ip.h> | ||
52 | #include <net/checksum.h> | ||
53 | #include <net/tcp.h> | ||
54 | |||
55 | #include <linux/netfilter_ipv4/ip_conntrack.h> | ||
56 | #include <linux/netfilter_ipv4/ip_conntrack_core.h> | ||
57 | #include <linux/netfilter_ipv4/ip_conntrack_helper.h> | ||
58 | #include <linux/netfilter_ipv4/ip_conntrack_proto_gre.h> | ||
59 | #include <linux/netfilter_ipv4/ip_conntrack_pptp.h> | ||
60 | |||
61 | #define IP_CT_PPTP_VERSION "3.1" | ||
62 | |||
63 | MODULE_LICENSE("GPL"); | ||
64 | MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>"); | ||
65 | MODULE_DESCRIPTION("Netfilter connection tracking helper module for PPTP"); | ||
66 | |||
67 | static DEFINE_SPINLOCK(ip_pptp_lock); | ||
68 | |||
69 | int | ||
70 | (*ip_nat_pptp_hook_outbound)(struct sk_buff **pskb, | ||
71 | struct ip_conntrack *ct, | ||
72 | enum ip_conntrack_info ctinfo, | ||
73 | struct PptpControlHeader *ctlh, | ||
74 | union pptp_ctrl_union *pptpReq); | ||
75 | |||
76 | int | ||
77 | (*ip_nat_pptp_hook_inbound)(struct sk_buff **pskb, | ||
78 | struct ip_conntrack *ct, | ||
79 | enum ip_conntrack_info ctinfo, | ||
80 | struct PptpControlHeader *ctlh, | ||
81 | union pptp_ctrl_union *pptpReq); | ||
82 | |||
83 | void | ||
84 | (*ip_nat_pptp_hook_exp_gre)(struct ip_conntrack_expect *expect_orig, | ||
85 | struct ip_conntrack_expect *expect_reply); | ||
86 | |||
87 | void | ||
88 | (*ip_nat_pptp_hook_expectfn)(struct ip_conntrack *ct, | ||
89 | struct ip_conntrack_expect *exp); | ||
90 | |||
91 | #if 0 | ||
92 | /* PptpControlMessageType names */ | ||
93 | const char *pptp_msg_name[] = { | ||
94 | "UNKNOWN_MESSAGE", | ||
95 | "START_SESSION_REQUEST", | ||
96 | "START_SESSION_REPLY", | ||
97 | "STOP_SESSION_REQUEST", | ||
98 | "STOP_SESSION_REPLY", | ||
99 | "ECHO_REQUEST", | ||
100 | "ECHO_REPLY", | ||
101 | "OUT_CALL_REQUEST", | ||
102 | "OUT_CALL_REPLY", | ||
103 | "IN_CALL_REQUEST", | ||
104 | "IN_CALL_REPLY", | ||
105 | "IN_CALL_CONNECT", | ||
106 | "CALL_CLEAR_REQUEST", | ||
107 | "CALL_DISCONNECT_NOTIFY", | ||
108 | "WAN_ERROR_NOTIFY", | ||
109 | "SET_LINK_INFO" | ||
110 | }; | ||
111 | EXPORT_SYMBOL(pptp_msg_name); | ||
112 | #define DEBUGP(format, args...) printk(KERN_DEBUG "%s:%s: " format, __FILE__, __FUNCTION__, ## args) | ||
113 | #else | ||
114 | #define DEBUGP(format, args...) | ||
115 | #endif | ||
116 | |||
117 | #define SECS *HZ | ||
118 | #define MINS * 60 SECS | ||
119 | #define HOURS * 60 MINS | ||
120 | |||
121 | #define PPTP_GRE_TIMEOUT (10 MINS) | ||
122 | #define PPTP_GRE_STREAM_TIMEOUT (5 HOURS) | ||
123 | |||
124 | static void pptp_expectfn(struct ip_conntrack *ct, | ||
125 | struct ip_conntrack_expect *exp) | ||
126 | { | ||
127 | typeof(ip_nat_pptp_hook_expectfn) ip_nat_pptp_expectfn; | ||
128 | |||
129 | DEBUGP("increasing timeouts\n"); | ||
130 | |||
131 | /* increase timeout of GRE data channel conntrack entry */ | ||
132 | ct->proto.gre.timeout = PPTP_GRE_TIMEOUT; | ||
133 | ct->proto.gre.stream_timeout = PPTP_GRE_STREAM_TIMEOUT; | ||
134 | |||
135 | /* Can you see how rusty this code is, compared with the pre-2.6.11 | ||
136 | * one? That's what happened to my shiny newnat of 2002 ;( -HW */ | ||
137 | |||
138 | rcu_read_lock(); | ||
139 | ip_nat_pptp_expectfn = rcu_dereference(ip_nat_pptp_hook_expectfn); | ||
140 | if (!ip_nat_pptp_expectfn) { | ||
141 | struct ip_conntrack_tuple inv_t; | ||
142 | struct ip_conntrack_expect *exp_other; | ||
143 | |||
144 | /* obviously this tuple inversion only works until you do NAT */ | ||
145 | invert_tuplepr(&inv_t, &exp->tuple); | ||
146 | DEBUGP("trying to unexpect other dir: "); | ||
147 | DUMP_TUPLE(&inv_t); | ||
148 | |||
149 | exp_other = ip_conntrack_expect_find_get(&inv_t); | ||
150 | if (exp_other) { | ||
151 | /* delete other expectation. */ | ||
152 | DEBUGP("found\n"); | ||
153 | ip_conntrack_unexpect_related(exp_other); | ||
154 | ip_conntrack_expect_put(exp_other); | ||
155 | } else { | ||
156 | DEBUGP("not found\n"); | ||
157 | } | ||
158 | } else { | ||
159 | /* we need more than simple inversion */ | ||
160 | ip_nat_pptp_expectfn(ct, exp); | ||
161 | } | ||
162 | rcu_read_unlock(); | ||
163 | } | ||
164 | |||
165 | static int destroy_sibling_or_exp(const struct ip_conntrack_tuple *t) | ||
166 | { | ||
167 | struct ip_conntrack_tuple_hash *h; | ||
168 | struct ip_conntrack_expect *exp; | ||
169 | |||
170 | DEBUGP("trying to timeout ct or exp for tuple "); | ||
171 | DUMP_TUPLE(t); | ||
172 | |||
173 | h = ip_conntrack_find_get(t, NULL); | ||
174 | if (h) { | ||
175 | struct ip_conntrack *sibling = tuplehash_to_ctrack(h); | ||
176 | DEBUGP("setting timeout of conntrack %p to 0\n", sibling); | ||
177 | sibling->proto.gre.timeout = 0; | ||
178 | sibling->proto.gre.stream_timeout = 0; | ||
179 | if (del_timer(&sibling->timeout)) | ||
180 | sibling->timeout.function((unsigned long)sibling); | ||
181 | ip_conntrack_put(sibling); | ||
182 | return 1; | ||
183 | } else { | ||
184 | exp = ip_conntrack_expect_find_get(t); | ||
185 | if (exp) { | ||
186 | DEBUGP("unexpect_related of expect %p\n", exp); | ||
187 | ip_conntrack_unexpect_related(exp); | ||
188 | ip_conntrack_expect_put(exp); | ||
189 | return 1; | ||
190 | } | ||
191 | } | ||
192 | |||
193 | return 0; | ||
194 | } | ||
195 | |||
196 | |||
197 | /* timeout GRE data connections */ | ||
198 | static void pptp_destroy_siblings(struct ip_conntrack *ct) | ||
199 | { | ||
200 | struct ip_conntrack_tuple t; | ||
201 | |||
202 | ip_ct_gre_keymap_destroy(ct); | ||
203 | /* Since ct->sibling_list has literally rusted away in 2.6.11, | ||
204 | * we now need another way to find out about our sibling | ||
205 | * contrack and expects... -HW */ | ||
206 | |||
207 | /* try original (pns->pac) tuple */ | ||
208 | memcpy(&t, &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple, sizeof(t)); | ||
209 | t.dst.protonum = IPPROTO_GRE; | ||
210 | t.src.u.gre.key = ct->help.ct_pptp_info.pns_call_id; | ||
211 | t.dst.u.gre.key = ct->help.ct_pptp_info.pac_call_id; | ||
212 | |||
213 | if (!destroy_sibling_or_exp(&t)) | ||
214 | DEBUGP("failed to timeout original pns->pac ct/exp\n"); | ||
215 | |||
216 | /* try reply (pac->pns) tuple */ | ||
217 | memcpy(&t, &ct->tuplehash[IP_CT_DIR_REPLY].tuple, sizeof(t)); | ||
218 | t.dst.protonum = IPPROTO_GRE; | ||
219 | t.src.u.gre.key = ct->help.ct_pptp_info.pac_call_id; | ||
220 | t.dst.u.gre.key = ct->help.ct_pptp_info.pns_call_id; | ||
221 | |||
222 | if (!destroy_sibling_or_exp(&t)) | ||
223 | DEBUGP("failed to timeout reply pac->pns ct/exp\n"); | ||
224 | } | ||
225 | |||
226 | /* expect GRE connections (PNS->PAC and PAC->PNS direction) */ | ||
227 | static inline int | ||
228 | exp_gre(struct ip_conntrack *ct, | ||
229 | __be16 callid, | ||
230 | __be16 peer_callid) | ||
231 | { | ||
232 | struct ip_conntrack_expect *exp_orig, *exp_reply; | ||
233 | int ret = 1; | ||
234 | typeof(ip_nat_pptp_hook_exp_gre) ip_nat_pptp_exp_gre; | ||
235 | |||
236 | exp_orig = ip_conntrack_expect_alloc(ct); | ||
237 | if (exp_orig == NULL) | ||
238 | goto out; | ||
239 | |||
240 | exp_reply = ip_conntrack_expect_alloc(ct); | ||
241 | if (exp_reply == NULL) | ||
242 | goto out_put_orig; | ||
243 | |||
244 | /* original direction, PNS->PAC */ | ||
245 | exp_orig->tuple.src.ip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip; | ||
246 | exp_orig->tuple.src.u.gre.key = peer_callid; | ||
247 | exp_orig->tuple.dst.ip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip; | ||
248 | exp_orig->tuple.dst.u.gre.key = callid; | ||
249 | exp_orig->tuple.dst.protonum = IPPROTO_GRE; | ||
250 | |||
251 | exp_orig->mask.src.ip = htonl(0xffffffff); | ||
252 | exp_orig->mask.src.u.all = 0; | ||
253 | exp_orig->mask.dst.u.gre.key = htons(0xffff); | ||
254 | exp_orig->mask.dst.ip = htonl(0xffffffff); | ||
255 | exp_orig->mask.dst.protonum = 0xff; | ||
256 | |||
257 | exp_orig->master = ct; | ||
258 | exp_orig->expectfn = pptp_expectfn; | ||
259 | exp_orig->flags = 0; | ||
260 | |||
261 | /* both expectations are identical apart from tuple */ | ||
262 | memcpy(exp_reply, exp_orig, sizeof(*exp_reply)); | ||
263 | |||
264 | /* reply direction, PAC->PNS */ | ||
265 | exp_reply->tuple.src.ip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip; | ||
266 | exp_reply->tuple.src.u.gre.key = callid; | ||
267 | exp_reply->tuple.dst.ip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip; | ||
268 | exp_reply->tuple.dst.u.gre.key = peer_callid; | ||
269 | exp_reply->tuple.dst.protonum = IPPROTO_GRE; | ||
270 | |||
271 | ip_nat_pptp_exp_gre = rcu_dereference(ip_nat_pptp_hook_exp_gre); | ||
272 | if (ip_nat_pptp_exp_gre) | ||
273 | ip_nat_pptp_exp_gre(exp_orig, exp_reply); | ||
274 | if (ip_conntrack_expect_related(exp_orig) != 0) | ||
275 | goto out_put_both; | ||
276 | if (ip_conntrack_expect_related(exp_reply) != 0) | ||
277 | goto out_unexpect_orig; | ||
278 | |||
279 | /* Add GRE keymap entries */ | ||
280 | if (ip_ct_gre_keymap_add(ct, &exp_orig->tuple, 0) != 0) | ||
281 | goto out_unexpect_both; | ||
282 | if (ip_ct_gre_keymap_add(ct, &exp_reply->tuple, 1) != 0) { | ||
283 | ip_ct_gre_keymap_destroy(ct); | ||
284 | goto out_unexpect_both; | ||
285 | } | ||
286 | ret = 0; | ||
287 | |||
288 | out_put_both: | ||
289 | ip_conntrack_expect_put(exp_reply); | ||
290 | out_put_orig: | ||
291 | ip_conntrack_expect_put(exp_orig); | ||
292 | out: | ||
293 | return ret; | ||
294 | |||
295 | out_unexpect_both: | ||
296 | ip_conntrack_unexpect_related(exp_reply); | ||
297 | out_unexpect_orig: | ||
298 | ip_conntrack_unexpect_related(exp_orig); | ||
299 | goto out_put_both; | ||
300 | } | ||
301 | |||
302 | static inline int | ||
303 | pptp_inbound_pkt(struct sk_buff **pskb, | ||
304 | struct PptpControlHeader *ctlh, | ||
305 | union pptp_ctrl_union *pptpReq, | ||
306 | unsigned int reqlen, | ||
307 | struct ip_conntrack *ct, | ||
308 | enum ip_conntrack_info ctinfo) | ||
309 | { | ||
310 | struct ip_ct_pptp_master *info = &ct->help.ct_pptp_info; | ||
311 | u_int16_t msg; | ||
312 | __be16 cid = 0, pcid = 0; | ||
313 | typeof(ip_nat_pptp_hook_inbound) ip_nat_pptp_inbound; | ||
314 | |||
315 | msg = ntohs(ctlh->messageType); | ||
316 | DEBUGP("inbound control message %s\n", pptp_msg_name[msg]); | ||
317 | |||
318 | switch (msg) { | ||
319 | case PPTP_START_SESSION_REPLY: | ||
320 | /* server confirms new control session */ | ||
321 | if (info->sstate < PPTP_SESSION_REQUESTED) | ||
322 | goto invalid; | ||
323 | if (pptpReq->srep.resultCode == PPTP_START_OK) | ||
324 | info->sstate = PPTP_SESSION_CONFIRMED; | ||
325 | else | ||
326 | info->sstate = PPTP_SESSION_ERROR; | ||
327 | break; | ||
328 | |||
329 | case PPTP_STOP_SESSION_REPLY: | ||
330 | /* server confirms end of control session */ | ||
331 | if (info->sstate > PPTP_SESSION_STOPREQ) | ||
332 | goto invalid; | ||
333 | if (pptpReq->strep.resultCode == PPTP_STOP_OK) | ||
334 | info->sstate = PPTP_SESSION_NONE; | ||
335 | else | ||
336 | info->sstate = PPTP_SESSION_ERROR; | ||
337 | break; | ||
338 | |||
339 | case PPTP_OUT_CALL_REPLY: | ||
340 | /* server accepted call, we now expect GRE frames */ | ||
341 | if (info->sstate != PPTP_SESSION_CONFIRMED) | ||
342 | goto invalid; | ||
343 | if (info->cstate != PPTP_CALL_OUT_REQ && | ||
344 | info->cstate != PPTP_CALL_OUT_CONF) | ||
345 | goto invalid; | ||
346 | |||
347 | cid = pptpReq->ocack.callID; | ||
348 | pcid = pptpReq->ocack.peersCallID; | ||
349 | if (info->pns_call_id != pcid) | ||
350 | goto invalid; | ||
351 | DEBUGP("%s, CID=%X, PCID=%X\n", pptp_msg_name[msg], | ||
352 | ntohs(cid), ntohs(pcid)); | ||
353 | |||
354 | if (pptpReq->ocack.resultCode == PPTP_OUTCALL_CONNECT) { | ||
355 | info->cstate = PPTP_CALL_OUT_CONF; | ||
356 | info->pac_call_id = cid; | ||
357 | exp_gre(ct, cid, pcid); | ||
358 | } else | ||
359 | info->cstate = PPTP_CALL_NONE; | ||
360 | break; | ||
361 | |||
362 | case PPTP_IN_CALL_REQUEST: | ||
363 | /* server tells us about incoming call request */ | ||
364 | if (info->sstate != PPTP_SESSION_CONFIRMED) | ||
365 | goto invalid; | ||
366 | |||
367 | cid = pptpReq->icreq.callID; | ||
368 | DEBUGP("%s, CID=%X\n", pptp_msg_name[msg], ntohs(cid)); | ||
369 | info->cstate = PPTP_CALL_IN_REQ; | ||
370 | info->pac_call_id = cid; | ||
371 | break; | ||
372 | |||
373 | case PPTP_IN_CALL_CONNECT: | ||
374 | /* server tells us about incoming call established */ | ||
375 | if (info->sstate != PPTP_SESSION_CONFIRMED) | ||
376 | goto invalid; | ||
377 | if (info->cstate != PPTP_CALL_IN_REP && | ||
378 | info->cstate != PPTP_CALL_IN_CONF) | ||
379 | goto invalid; | ||
380 | |||
381 | pcid = pptpReq->iccon.peersCallID; | ||
382 | cid = info->pac_call_id; | ||
383 | |||
384 | if (info->pns_call_id != pcid) | ||
385 | goto invalid; | ||
386 | |||
387 | DEBUGP("%s, PCID=%X\n", pptp_msg_name[msg], ntohs(pcid)); | ||
388 | info->cstate = PPTP_CALL_IN_CONF; | ||
389 | |||
390 | /* we expect a GRE connection from PAC to PNS */ | ||
391 | exp_gre(ct, cid, pcid); | ||
392 | break; | ||
393 | |||
394 | case PPTP_CALL_DISCONNECT_NOTIFY: | ||
395 | /* server confirms disconnect */ | ||
396 | cid = pptpReq->disc.callID; | ||
397 | DEBUGP("%s, CID=%X\n", pptp_msg_name[msg], ntohs(cid)); | ||
398 | info->cstate = PPTP_CALL_NONE; | ||
399 | |||
400 | /* untrack this call id, unexpect GRE packets */ | ||
401 | pptp_destroy_siblings(ct); | ||
402 | break; | ||
403 | |||
404 | case PPTP_WAN_ERROR_NOTIFY: | ||
405 | case PPTP_ECHO_REQUEST: | ||
406 | case PPTP_ECHO_REPLY: | ||
407 | /* I don't have to explain these ;) */ | ||
408 | break; | ||
409 | default: | ||
410 | goto invalid; | ||
411 | } | ||
412 | |||
413 | ip_nat_pptp_inbound = rcu_dereference(ip_nat_pptp_hook_inbound); | ||
414 | if (ip_nat_pptp_inbound) | ||
415 | return ip_nat_pptp_inbound(pskb, ct, ctinfo, ctlh, pptpReq); | ||
416 | return NF_ACCEPT; | ||
417 | |||
418 | invalid: | ||
419 | DEBUGP("invalid %s: type=%d cid=%u pcid=%u " | ||
420 | "cstate=%d sstate=%d pns_cid=%u pac_cid=%u\n", | ||
421 | msg <= PPTP_MSG_MAX ? pptp_msg_name[msg] : pptp_msg_name[0], | ||
422 | msg, ntohs(cid), ntohs(pcid), info->cstate, info->sstate, | ||
423 | ntohs(info->pns_call_id), ntohs(info->pac_call_id)); | ||
424 | return NF_ACCEPT; | ||
425 | } | ||
426 | |||
427 | static inline int | ||
428 | pptp_outbound_pkt(struct sk_buff **pskb, | ||
429 | struct PptpControlHeader *ctlh, | ||
430 | union pptp_ctrl_union *pptpReq, | ||
431 | unsigned int reqlen, | ||
432 | struct ip_conntrack *ct, | ||
433 | enum ip_conntrack_info ctinfo) | ||
434 | { | ||
435 | struct ip_ct_pptp_master *info = &ct->help.ct_pptp_info; | ||
436 | u_int16_t msg; | ||
437 | __be16 cid = 0, pcid = 0; | ||
438 | typeof(ip_nat_pptp_hook_outbound) ip_nat_pptp_outbound; | ||
439 | |||
440 | msg = ntohs(ctlh->messageType); | ||
441 | DEBUGP("outbound control message %s\n", pptp_msg_name[msg]); | ||
442 | |||
443 | switch (msg) { | ||
444 | case PPTP_START_SESSION_REQUEST: | ||
445 | /* client requests for new control session */ | ||
446 | if (info->sstate != PPTP_SESSION_NONE) | ||
447 | goto invalid; | ||
448 | info->sstate = PPTP_SESSION_REQUESTED; | ||
449 | break; | ||
450 | case PPTP_STOP_SESSION_REQUEST: | ||
451 | /* client requests end of control session */ | ||
452 | info->sstate = PPTP_SESSION_STOPREQ; | ||
453 | break; | ||
454 | |||
455 | case PPTP_OUT_CALL_REQUEST: | ||
456 | /* client initiating connection to server */ | ||
457 | if (info->sstate != PPTP_SESSION_CONFIRMED) | ||
458 | goto invalid; | ||
459 | info->cstate = PPTP_CALL_OUT_REQ; | ||
460 | /* track PNS call id */ | ||
461 | cid = pptpReq->ocreq.callID; | ||
462 | DEBUGP("%s, CID=%X\n", pptp_msg_name[msg], ntohs(cid)); | ||
463 | info->pns_call_id = cid; | ||
464 | break; | ||
465 | case PPTP_IN_CALL_REPLY: | ||
466 | /* client answers incoming call */ | ||
467 | if (info->cstate != PPTP_CALL_IN_REQ && | ||
468 | info->cstate != PPTP_CALL_IN_REP) | ||
469 | goto invalid; | ||
470 | |||
471 | cid = pptpReq->icack.callID; | ||
472 | pcid = pptpReq->icack.peersCallID; | ||
473 | if (info->pac_call_id != pcid) | ||
474 | goto invalid; | ||
475 | DEBUGP("%s, CID=%X PCID=%X\n", pptp_msg_name[msg], | ||
476 | ntohs(cid), ntohs(pcid)); | ||
477 | |||
478 | if (pptpReq->icack.resultCode == PPTP_INCALL_ACCEPT) { | ||
479 | /* part two of the three-way handshake */ | ||
480 | info->cstate = PPTP_CALL_IN_REP; | ||
481 | info->pns_call_id = cid; | ||
482 | } else | ||
483 | info->cstate = PPTP_CALL_NONE; | ||
484 | break; | ||
485 | |||
486 | case PPTP_CALL_CLEAR_REQUEST: | ||
487 | /* client requests hangup of call */ | ||
488 | if (info->sstate != PPTP_SESSION_CONFIRMED) | ||
489 | goto invalid; | ||
490 | /* FUTURE: iterate over all calls and check if | ||
491 | * call ID is valid. We don't do this without newnat, | ||
492 | * because we only know about last call */ | ||
493 | info->cstate = PPTP_CALL_CLEAR_REQ; | ||
494 | break; | ||
495 | case PPTP_SET_LINK_INFO: | ||
496 | case PPTP_ECHO_REQUEST: | ||
497 | case PPTP_ECHO_REPLY: | ||
498 | /* I don't have to explain these ;) */ | ||
499 | break; | ||
500 | default: | ||
501 | goto invalid; | ||
502 | } | ||
503 | |||
504 | ip_nat_pptp_outbound = rcu_dereference(ip_nat_pptp_hook_outbound); | ||
505 | if (ip_nat_pptp_outbound) | ||
506 | return ip_nat_pptp_outbound(pskb, ct, ctinfo, ctlh, pptpReq); | ||
507 | return NF_ACCEPT; | ||
508 | |||
509 | invalid: | ||
510 | DEBUGP("invalid %s: type=%d cid=%u pcid=%u " | ||
511 | "cstate=%d sstate=%d pns_cid=%u pac_cid=%u\n", | ||
512 | msg <= PPTP_MSG_MAX ? pptp_msg_name[msg] : pptp_msg_name[0], | ||
513 | msg, ntohs(cid), ntohs(pcid), info->cstate, info->sstate, | ||
514 | ntohs(info->pns_call_id), ntohs(info->pac_call_id)); | ||
515 | return NF_ACCEPT; | ||
516 | } | ||
517 | |||
518 | static const unsigned int pptp_msg_size[] = { | ||
519 | [PPTP_START_SESSION_REQUEST] = sizeof(struct PptpStartSessionRequest), | ||
520 | [PPTP_START_SESSION_REPLY] = sizeof(struct PptpStartSessionReply), | ||
521 | [PPTP_STOP_SESSION_REQUEST] = sizeof(struct PptpStopSessionRequest), | ||
522 | [PPTP_STOP_SESSION_REPLY] = sizeof(struct PptpStopSessionReply), | ||
523 | [PPTP_OUT_CALL_REQUEST] = sizeof(struct PptpOutCallRequest), | ||
524 | [PPTP_OUT_CALL_REPLY] = sizeof(struct PptpOutCallReply), | ||
525 | [PPTP_IN_CALL_REQUEST] = sizeof(struct PptpInCallRequest), | ||
526 | [PPTP_IN_CALL_REPLY] = sizeof(struct PptpInCallReply), | ||
527 | [PPTP_IN_CALL_CONNECT] = sizeof(struct PptpInCallConnected), | ||
528 | [PPTP_CALL_CLEAR_REQUEST] = sizeof(struct PptpClearCallRequest), | ||
529 | [PPTP_CALL_DISCONNECT_NOTIFY] = sizeof(struct PptpCallDisconnectNotify), | ||
530 | [PPTP_WAN_ERROR_NOTIFY] = sizeof(struct PptpWanErrorNotify), | ||
531 | [PPTP_SET_LINK_INFO] = sizeof(struct PptpSetLinkInfo), | ||
532 | }; | ||
533 | |||
534 | /* track caller id inside control connection, call expect_related */ | ||
535 | static int | ||
536 | conntrack_pptp_help(struct sk_buff **pskb, | ||
537 | struct ip_conntrack *ct, enum ip_conntrack_info ctinfo) | ||
538 | |||
539 | { | ||
540 | int dir = CTINFO2DIR(ctinfo); | ||
541 | struct ip_ct_pptp_master *info = &ct->help.ct_pptp_info; | ||
542 | struct tcphdr _tcph, *tcph; | ||
543 | struct pptp_pkt_hdr _pptph, *pptph; | ||
544 | struct PptpControlHeader _ctlh, *ctlh; | ||
545 | union pptp_ctrl_union _pptpReq, *pptpReq; | ||
546 | unsigned int tcplen = (*pskb)->len - ip_hdrlen(*pskb); | ||
547 | unsigned int datalen, reqlen, nexthdr_off; | ||
548 | int oldsstate, oldcstate; | ||
549 | int ret; | ||
550 | u_int16_t msg; | ||
551 | |||
552 | /* don't do any tracking before tcp handshake complete */ | ||
553 | if (ctinfo != IP_CT_ESTABLISHED | ||
554 | && ctinfo != IP_CT_ESTABLISHED+IP_CT_IS_REPLY) { | ||
555 | DEBUGP("ctinfo = %u, skipping\n", ctinfo); | ||
556 | return NF_ACCEPT; | ||
557 | } | ||
558 | |||
559 | nexthdr_off = ip_hdrlen(*pskb); | ||
560 | tcph = skb_header_pointer(*pskb, nexthdr_off, sizeof(_tcph), &_tcph); | ||
561 | BUG_ON(!tcph); | ||
562 | nexthdr_off += tcph->doff * 4; | ||
563 | datalen = tcplen - tcph->doff * 4; | ||
564 | |||
565 | pptph = skb_header_pointer(*pskb, nexthdr_off, sizeof(_pptph), &_pptph); | ||
566 | if (!pptph) { | ||
567 | DEBUGP("no full PPTP header, can't track\n"); | ||
568 | return NF_ACCEPT; | ||
569 | } | ||
570 | nexthdr_off += sizeof(_pptph); | ||
571 | datalen -= sizeof(_pptph); | ||
572 | |||
573 | /* if it's not a control message we can't do anything with it */ | ||
574 | if (ntohs(pptph->packetType) != PPTP_PACKET_CONTROL || | ||
575 | ntohl(pptph->magicCookie) != PPTP_MAGIC_COOKIE) { | ||
576 | DEBUGP("not a control packet\n"); | ||
577 | return NF_ACCEPT; | ||
578 | } | ||
579 | |||
580 | ctlh = skb_header_pointer(*pskb, nexthdr_off, sizeof(_ctlh), &_ctlh); | ||
581 | if (!ctlh) | ||
582 | return NF_ACCEPT; | ||
583 | nexthdr_off += sizeof(_ctlh); | ||
584 | datalen -= sizeof(_ctlh); | ||
585 | |||
586 | reqlen = datalen; | ||
587 | msg = ntohs(ctlh->messageType); | ||
588 | if (msg > 0 && msg <= PPTP_MSG_MAX && reqlen < pptp_msg_size[msg]) | ||
589 | return NF_ACCEPT; | ||
590 | if (reqlen > sizeof(*pptpReq)) | ||
591 | reqlen = sizeof(*pptpReq); | ||
592 | |||
593 | pptpReq = skb_header_pointer(*pskb, nexthdr_off, reqlen, &_pptpReq); | ||
594 | if (!pptpReq) | ||
595 | return NF_ACCEPT; | ||
596 | |||
597 | oldsstate = info->sstate; | ||
598 | oldcstate = info->cstate; | ||
599 | |||
600 | spin_lock_bh(&ip_pptp_lock); | ||
601 | |||
602 | /* FIXME: We just blindly assume that the control connection is always | ||
603 | * established from PNS->PAC. However, RFC makes no guarantee */ | ||
604 | if (dir == IP_CT_DIR_ORIGINAL) | ||
605 | /* client -> server (PNS -> PAC) */ | ||
606 | ret = pptp_outbound_pkt(pskb, ctlh, pptpReq, reqlen, ct, | ||
607 | ctinfo); | ||
608 | else | ||
609 | /* server -> client (PAC -> PNS) */ | ||
610 | ret = pptp_inbound_pkt(pskb, ctlh, pptpReq, reqlen, ct, | ||
611 | ctinfo); | ||
612 | DEBUGP("sstate: %d->%d, cstate: %d->%d\n", | ||
613 | oldsstate, info->sstate, oldcstate, info->cstate); | ||
614 | spin_unlock_bh(&ip_pptp_lock); | ||
615 | |||
616 | return ret; | ||
617 | } | ||
618 | |||
619 | /* control protocol helper */ | ||
620 | static struct ip_conntrack_helper pptp = { | ||
621 | .list = { NULL, NULL }, | ||
622 | .name = "pptp", | ||
623 | .me = THIS_MODULE, | ||
624 | .max_expected = 2, | ||
625 | .timeout = 5 * 60, | ||
626 | .tuple = { .src = { .ip = 0, | ||
627 | .u = { .tcp = { .port = | ||
628 | __constant_htons(PPTP_CONTROL_PORT) } } | ||
629 | }, | ||
630 | .dst = { .ip = 0, | ||
631 | .u = { .all = 0 }, | ||
632 | .protonum = IPPROTO_TCP | ||
633 | } | ||
634 | }, | ||
635 | .mask = { .src = { .ip = 0, | ||
636 | .u = { .tcp = { .port = __constant_htons(0xffff) } } | ||
637 | }, | ||
638 | .dst = { .ip = 0, | ||
639 | .u = { .all = 0 }, | ||
640 | .protonum = 0xff | ||
641 | } | ||
642 | }, | ||
643 | .help = conntrack_pptp_help, | ||
644 | .destroy = pptp_destroy_siblings, | ||
645 | }; | ||
646 | |||
647 | extern void ip_ct_proto_gre_fini(void); | ||
648 | extern int __init ip_ct_proto_gre_init(void); | ||
649 | |||
650 | /* ip_conntrack_pptp initialization */ | ||
651 | static int __init ip_conntrack_helper_pptp_init(void) | ||
652 | { | ||
653 | int retcode; | ||
654 | |||
655 | retcode = ip_ct_proto_gre_init(); | ||
656 | if (retcode < 0) | ||
657 | return retcode; | ||
658 | |||
659 | DEBUGP(" registering helper\n"); | ||
660 | if ((retcode = ip_conntrack_helper_register(&pptp))) { | ||
661 | printk(KERN_ERR "Unable to register conntrack application " | ||
662 | "helper for pptp: %d\n", retcode); | ||
663 | ip_ct_proto_gre_fini(); | ||
664 | return retcode; | ||
665 | } | ||
666 | |||
667 | printk("ip_conntrack_pptp version %s loaded\n", IP_CT_PPTP_VERSION); | ||
668 | return 0; | ||
669 | } | ||
670 | |||
671 | static void __exit ip_conntrack_helper_pptp_fini(void) | ||
672 | { | ||
673 | ip_conntrack_helper_unregister(&pptp); | ||
674 | ip_ct_proto_gre_fini(); | ||
675 | printk("ip_conntrack_pptp version %s unloaded\n", IP_CT_PPTP_VERSION); | ||
676 | } | ||
677 | |||
678 | module_init(ip_conntrack_helper_pptp_init); | ||
679 | module_exit(ip_conntrack_helper_pptp_fini); | ||
680 | |||
681 | EXPORT_SYMBOL(ip_nat_pptp_hook_outbound); | ||
682 | EXPORT_SYMBOL(ip_nat_pptp_hook_inbound); | ||
683 | EXPORT_SYMBOL(ip_nat_pptp_hook_exp_gre); | ||
684 | EXPORT_SYMBOL(ip_nat_pptp_hook_expectfn); | ||
diff --git a/net/ipv4/netfilter/ip_conntrack_irc.c b/net/ipv4/netfilter/ip_conntrack_irc.c deleted file mode 100644 index ee99abe482e3..000000000000 --- a/net/ipv4/netfilter/ip_conntrack_irc.c +++ /dev/null | |||
@@ -1,314 +0,0 @@ | |||
1 | /* IRC extension for IP connection tracking, Version 1.21 | ||
2 | * (C) 2000-2002 by Harald Welte <laforge@gnumonks.org> | ||
3 | * based on RR's ip_conntrack_ftp.c | ||
4 | * | ||
5 | * ip_conntrack_irc.c,v 1.21 2002/02/05 14:49:26 laforge Exp | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License | ||
9 | * as published by the Free Software Foundation; either version | ||
10 | * 2 of the License, or (at your option) any later version. | ||
11 | ** | ||
12 | * Module load syntax: | ||
13 | * insmod ip_conntrack_irc.o ports=port1,port2,...port<MAX_PORTS> | ||
14 | * max_dcc_channels=n dcc_timeout=secs | ||
15 | * | ||
16 | * please give the ports of all IRC servers You wish to connect to. | ||
17 | * If You don't specify ports, the default will be port 6667. | ||
18 | * With max_dcc_channels you can define the maximum number of not | ||
19 | * yet answered DCC channels per IRC session (default 8). | ||
20 | * With dcc_timeout you can specify how long the system waits for | ||
21 | * an expected DCC channel (default 300 seconds). | ||
22 | * | ||
23 | */ | ||
24 | |||
25 | #include <linux/module.h> | ||
26 | #include <linux/netfilter.h> | ||
27 | #include <linux/ip.h> | ||
28 | #include <net/checksum.h> | ||
29 | #include <net/tcp.h> | ||
30 | |||
31 | #include <linux/netfilter_ipv4/ip_conntrack_helper.h> | ||
32 | #include <linux/netfilter_ipv4/ip_conntrack_irc.h> | ||
33 | #include <linux/moduleparam.h> | ||
34 | |||
35 | #define MAX_PORTS 8 | ||
36 | static unsigned short ports[MAX_PORTS]; | ||
37 | static int ports_c; | ||
38 | static unsigned int max_dcc_channels = 8; | ||
39 | static unsigned int dcc_timeout = 300; | ||
40 | /* This is slow, but it's simple. --RR */ | ||
41 | static char *irc_buffer; | ||
42 | static DEFINE_SPINLOCK(irc_buffer_lock); | ||
43 | |||
44 | unsigned int (*ip_nat_irc_hook)(struct sk_buff **pskb, | ||
45 | enum ip_conntrack_info ctinfo, | ||
46 | unsigned int matchoff, | ||
47 | unsigned int matchlen, | ||
48 | struct ip_conntrack_expect *exp); | ||
49 | EXPORT_SYMBOL_GPL(ip_nat_irc_hook); | ||
50 | |||
51 | MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>"); | ||
52 | MODULE_DESCRIPTION("IRC (DCC) connection tracking helper"); | ||
53 | MODULE_LICENSE("GPL"); | ||
54 | module_param_array(ports, ushort, &ports_c, 0400); | ||
55 | MODULE_PARM_DESC(ports, "port numbers of IRC servers"); | ||
56 | module_param(max_dcc_channels, uint, 0400); | ||
57 | MODULE_PARM_DESC(max_dcc_channels, "max number of expected DCC channels per IRC session"); | ||
58 | module_param(dcc_timeout, uint, 0400); | ||
59 | MODULE_PARM_DESC(dcc_timeout, "timeout on for unestablished DCC channels"); | ||
60 | |||
61 | static const char *dccprotos[] = { "SEND ", "CHAT ", "MOVE ", "TSEND ", "SCHAT " }; | ||
62 | #define MINMATCHLEN 5 | ||
63 | |||
64 | #if 0 | ||
65 | #define DEBUGP(format, args...) printk(KERN_DEBUG "%s:%s:" format, \ | ||
66 | __FILE__, __FUNCTION__ , ## args) | ||
67 | #else | ||
68 | #define DEBUGP(format, args...) | ||
69 | #endif | ||
70 | |||
71 | static int parse_dcc(char *data, char *data_end, u_int32_t *ip, | ||
72 | u_int16_t *port, char **ad_beg_p, char **ad_end_p) | ||
73 | /* tries to get the ip_addr and port out of a dcc command | ||
74 | return value: -1 on failure, 0 on success | ||
75 | data pointer to first byte of DCC command data | ||
76 | data_end pointer to last byte of dcc command data | ||
77 | ip returns parsed ip of dcc command | ||
78 | port returns parsed port of dcc command | ||
79 | ad_beg_p returns pointer to first byte of addr data | ||
80 | ad_end_p returns pointer to last byte of addr data */ | ||
81 | { | ||
82 | |||
83 | /* at least 12: "AAAAAAAA P\1\n" */ | ||
84 | while (*data++ != ' ') | ||
85 | if (data > data_end - 12) | ||
86 | return -1; | ||
87 | |||
88 | *ad_beg_p = data; | ||
89 | *ip = simple_strtoul(data, &data, 10); | ||
90 | |||
91 | /* skip blanks between ip and port */ | ||
92 | while (*data == ' ') { | ||
93 | if (data >= data_end) | ||
94 | return -1; | ||
95 | data++; | ||
96 | } | ||
97 | |||
98 | *port = simple_strtoul(data, &data, 10); | ||
99 | *ad_end_p = data; | ||
100 | |||
101 | return 0; | ||
102 | } | ||
103 | |||
104 | static int help(struct sk_buff **pskb, | ||
105 | struct ip_conntrack *ct, enum ip_conntrack_info ctinfo) | ||
106 | { | ||
107 | unsigned int dataoff; | ||
108 | struct tcphdr _tcph, *th; | ||
109 | char *data, *data_limit, *ib_ptr; | ||
110 | int dir = CTINFO2DIR(ctinfo); | ||
111 | struct ip_conntrack_expect *exp; | ||
112 | u32 seq; | ||
113 | u_int32_t dcc_ip; | ||
114 | u_int16_t dcc_port; | ||
115 | int i, ret = NF_ACCEPT; | ||
116 | char *addr_beg_p, *addr_end_p; | ||
117 | typeof(ip_nat_irc_hook) ip_nat_irc; | ||
118 | |||
119 | DEBUGP("entered\n"); | ||
120 | |||
121 | /* If packet is coming from IRC server */ | ||
122 | if (dir == IP_CT_DIR_REPLY) | ||
123 | return NF_ACCEPT; | ||
124 | |||
125 | /* Until there's been traffic both ways, don't look in packets. */ | ||
126 | if (ctinfo != IP_CT_ESTABLISHED | ||
127 | && ctinfo != IP_CT_ESTABLISHED + IP_CT_IS_REPLY) { | ||
128 | DEBUGP("Conntrackinfo = %u\n", ctinfo); | ||
129 | return NF_ACCEPT; | ||
130 | } | ||
131 | |||
132 | /* Not a full tcp header? */ | ||
133 | th = skb_header_pointer(*pskb, ip_hdrlen(*pskb), | ||
134 | sizeof(_tcph), &_tcph); | ||
135 | if (th == NULL) | ||
136 | return NF_ACCEPT; | ||
137 | |||
138 | /* No data? */ | ||
139 | dataoff = ip_hdrlen(*pskb) + th->doff * 4; | ||
140 | if (dataoff >= (*pskb)->len) | ||
141 | return NF_ACCEPT; | ||
142 | |||
143 | spin_lock_bh(&irc_buffer_lock); | ||
144 | ib_ptr = skb_header_pointer(*pskb, dataoff, | ||
145 | (*pskb)->len - dataoff, irc_buffer); | ||
146 | BUG_ON(ib_ptr == NULL); | ||
147 | |||
148 | data = ib_ptr; | ||
149 | data_limit = ib_ptr + (*pskb)->len - dataoff; | ||
150 | |||
151 | /* strlen("\1DCC SENT t AAAAAAAA P\1\n")=24 | ||
152 | * 5+MINMATCHLEN+strlen("t AAAAAAAA P\1\n")=14 */ | ||
153 | while (data < (data_limit - (19 + MINMATCHLEN))) { | ||
154 | if (memcmp(data, "\1DCC ", 5)) { | ||
155 | data++; | ||
156 | continue; | ||
157 | } | ||
158 | |||
159 | data += 5; | ||
160 | /* we have at least (19+MINMATCHLEN)-5 bytes valid data left */ | ||
161 | |||
162 | DEBUGP("DCC found in master %u.%u.%u.%u:%u %u.%u.%u.%u:%u...\n", | ||
163 | NIPQUAD(iph->saddr), ntohs(th->source), | ||
164 | NIPQUAD(iph->daddr), ntohs(th->dest)); | ||
165 | |||
166 | for (i = 0; i < ARRAY_SIZE(dccprotos); i++) { | ||
167 | if (memcmp(data, dccprotos[i], strlen(dccprotos[i]))) { | ||
168 | /* no match */ | ||
169 | continue; | ||
170 | } | ||
171 | |||
172 | DEBUGP("DCC %s detected\n", dccprotos[i]); | ||
173 | data += strlen(dccprotos[i]); | ||
174 | /* we have at least | ||
175 | * (19+MINMATCHLEN)-5-dccprotos[i].matchlen bytes valid | ||
176 | * data left (== 14/13 bytes) */ | ||
177 | if (parse_dcc((char *)data, data_limit, &dcc_ip, | ||
178 | &dcc_port, &addr_beg_p, &addr_end_p)) { | ||
179 | /* unable to parse */ | ||
180 | DEBUGP("unable to parse dcc command\n"); | ||
181 | continue; | ||
182 | } | ||
183 | DEBUGP("DCC bound ip/port: %u.%u.%u.%u:%u\n", | ||
184 | HIPQUAD(dcc_ip), dcc_port); | ||
185 | |||
186 | /* dcc_ip can be the internal OR external (NAT'ed) IP | ||
187 | * Tiago Sousa <mirage@kaotik.org> */ | ||
188 | if (ct->tuplehash[dir].tuple.src.ip != htonl(dcc_ip) | ||
189 | && ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip != htonl(dcc_ip)) { | ||
190 | if (net_ratelimit()) | ||
191 | printk(KERN_WARNING | ||
192 | "Forged DCC command from " | ||
193 | "%u.%u.%u.%u: %u.%u.%u.%u:%u\n", | ||
194 | NIPQUAD(ct->tuplehash[dir].tuple.src.ip), | ||
195 | HIPQUAD(dcc_ip), dcc_port); | ||
196 | |||
197 | continue; | ||
198 | } | ||
199 | |||
200 | exp = ip_conntrack_expect_alloc(ct); | ||
201 | if (exp == NULL) { | ||
202 | ret = NF_DROP; | ||
203 | goto out; | ||
204 | } | ||
205 | |||
206 | /* save position of address in dcc string, | ||
207 | * necessary for NAT */ | ||
208 | DEBUGP("tcph->seq = %u\n", th->seq); | ||
209 | seq = ntohl(th->seq) + (addr_beg_p - ib_ptr); | ||
210 | |||
211 | /* We refer to the reverse direction ("!dir") | ||
212 | * tuples here, because we're expecting | ||
213 | * something in the other * direction. | ||
214 | * Doesn't matter unless NAT is happening. */ | ||
215 | exp->tuple = ((struct ip_conntrack_tuple) | ||
216 | { { 0, { 0 } }, | ||
217 | { ct->tuplehash[!dir].tuple.dst.ip, | ||
218 | { .tcp = { htons(dcc_port) } }, | ||
219 | IPPROTO_TCP }}); | ||
220 | exp->mask = ((struct ip_conntrack_tuple) | ||
221 | { { 0, { 0 } }, | ||
222 | { htonl(0xFFFFFFFF), | ||
223 | { .tcp = { htons(0xFFFF) } }, 0xFF }}); | ||
224 | exp->expectfn = NULL; | ||
225 | exp->flags = 0; | ||
226 | ip_nat_irc = rcu_dereference(ip_nat_irc_hook); | ||
227 | if (ip_nat_irc) | ||
228 | ret = ip_nat_irc(pskb, ctinfo, | ||
229 | addr_beg_p - ib_ptr, | ||
230 | addr_end_p - addr_beg_p, | ||
231 | exp); | ||
232 | else if (ip_conntrack_expect_related(exp) != 0) | ||
233 | ret = NF_DROP; | ||
234 | ip_conntrack_expect_put(exp); | ||
235 | goto out; | ||
236 | } /* for .. NUM_DCCPROTO */ | ||
237 | } /* while data < ... */ | ||
238 | |||
239 | out: | ||
240 | spin_unlock_bh(&irc_buffer_lock); | ||
241 | return ret; | ||
242 | } | ||
243 | |||
244 | static struct ip_conntrack_helper irc_helpers[MAX_PORTS]; | ||
245 | static char irc_names[MAX_PORTS][sizeof("irc-65535")]; | ||
246 | |||
247 | static void ip_conntrack_irc_fini(void); | ||
248 | |||
249 | static int __init ip_conntrack_irc_init(void) | ||
250 | { | ||
251 | int i, ret; | ||
252 | struct ip_conntrack_helper *hlpr; | ||
253 | char *tmpname; | ||
254 | |||
255 | if (max_dcc_channels < 1) { | ||
256 | printk("ip_conntrack_irc: max_dcc_channels must be a positive integer\n"); | ||
257 | return -EBUSY; | ||
258 | } | ||
259 | |||
260 | irc_buffer = kmalloc(65536, GFP_KERNEL); | ||
261 | if (!irc_buffer) | ||
262 | return -ENOMEM; | ||
263 | |||
264 | /* If no port given, default to standard irc port */ | ||
265 | if (ports_c == 0) | ||
266 | ports[ports_c++] = IRC_PORT; | ||
267 | |||
268 | for (i = 0; i < ports_c; i++) { | ||
269 | hlpr = &irc_helpers[i]; | ||
270 | hlpr->tuple.src.u.tcp.port = htons(ports[i]); | ||
271 | hlpr->tuple.dst.protonum = IPPROTO_TCP; | ||
272 | hlpr->mask.src.u.tcp.port = htons(0xFFFF); | ||
273 | hlpr->mask.dst.protonum = 0xFF; | ||
274 | hlpr->max_expected = max_dcc_channels; | ||
275 | hlpr->timeout = dcc_timeout; | ||
276 | hlpr->me = THIS_MODULE; | ||
277 | hlpr->help = help; | ||
278 | |||
279 | tmpname = &irc_names[i][0]; | ||
280 | if (ports[i] == IRC_PORT) | ||
281 | sprintf(tmpname, "irc"); | ||
282 | else | ||
283 | sprintf(tmpname, "irc-%d", i); | ||
284 | hlpr->name = tmpname; | ||
285 | |||
286 | DEBUGP("port #%d: %d\n", i, ports[i]); | ||
287 | |||
288 | ret = ip_conntrack_helper_register(hlpr); | ||
289 | |||
290 | if (ret) { | ||
291 | printk("ip_conntrack_irc: ERROR registering port %d\n", | ||
292 | ports[i]); | ||
293 | ip_conntrack_irc_fini(); | ||
294 | return -EBUSY; | ||
295 | } | ||
296 | } | ||
297 | return 0; | ||
298 | } | ||
299 | |||
300 | /* This function is intentionally _NOT_ defined as __exit, because | ||
301 | * it is needed by the init function */ | ||
302 | static void ip_conntrack_irc_fini(void) | ||
303 | { | ||
304 | int i; | ||
305 | for (i = 0; i < ports_c; i++) { | ||
306 | DEBUGP("unregistering port %d\n", | ||
307 | ports[i]); | ||
308 | ip_conntrack_helper_unregister(&irc_helpers[i]); | ||
309 | } | ||
310 | kfree(irc_buffer); | ||
311 | } | ||
312 | |||
313 | module_init(ip_conntrack_irc_init); | ||
314 | module_exit(ip_conntrack_irc_fini); | ||
diff --git a/net/ipv4/netfilter/ip_conntrack_netbios_ns.c b/net/ipv4/netfilter/ip_conntrack_netbios_ns.c deleted file mode 100644 index df07c5f1d874..000000000000 --- a/net/ipv4/netfilter/ip_conntrack_netbios_ns.c +++ /dev/null | |||
@@ -1,143 +0,0 @@ | |||
1 | /* | ||
2 | * NetBIOS name service broadcast connection tracking helper | ||
3 | * | ||
4 | * (c) 2005 Patrick McHardy <kaber@trash.net> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License | ||
8 | * as published by the Free Software Foundation; either version | ||
9 | * 2 of the License, or (at your option) any later version. | ||
10 | */ | ||
11 | /* | ||
12 | * This helper tracks locally originating NetBIOS name service | ||
13 | * requests by issuing permanent expectations (valid until | ||
14 | * timing out) matching all reply connections from the | ||
15 | * destination network. The only NetBIOS specific thing is | ||
16 | * actually the port number. | ||
17 | */ | ||
18 | #include <linux/kernel.h> | ||
19 | #include <linux/module.h> | ||
20 | #include <linux/init.h> | ||
21 | #include <linux/skbuff.h> | ||
22 | #include <linux/netdevice.h> | ||
23 | #include <linux/inetdevice.h> | ||
24 | #include <linux/if_addr.h> | ||
25 | #include <linux/in.h> | ||
26 | #include <linux/ip.h> | ||
27 | #include <net/route.h> | ||
28 | |||
29 | #include <linux/netfilter.h> | ||
30 | #include <linux/netfilter_ipv4.h> | ||
31 | #include <linux/netfilter_ipv4/ip_conntrack.h> | ||
32 | #include <linux/netfilter_ipv4/ip_conntrack_helper.h> | ||
33 | |||
34 | #define NMBD_PORT 137 | ||
35 | |||
36 | MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>"); | ||
37 | MODULE_DESCRIPTION("NetBIOS name service broadcast connection tracking helper"); | ||
38 | MODULE_LICENSE("GPL"); | ||
39 | |||
40 | static unsigned int timeout = 3; | ||
41 | module_param(timeout, uint, 0400); | ||
42 | MODULE_PARM_DESC(timeout, "timeout for master connection/replies in seconds"); | ||
43 | |||
44 | static int help(struct sk_buff **pskb, | ||
45 | struct ip_conntrack *ct, enum ip_conntrack_info ctinfo) | ||
46 | { | ||
47 | struct ip_conntrack_expect *exp; | ||
48 | struct iphdr *iph = ip_hdr(*pskb); | ||
49 | struct rtable *rt = (struct rtable *)(*pskb)->dst; | ||
50 | struct in_device *in_dev; | ||
51 | __be32 mask = 0; | ||
52 | |||
53 | /* we're only interested in locally generated packets */ | ||
54 | if ((*pskb)->sk == NULL) | ||
55 | goto out; | ||
56 | if (rt == NULL || !(rt->rt_flags & RTCF_BROADCAST)) | ||
57 | goto out; | ||
58 | if (CTINFO2DIR(ctinfo) != IP_CT_DIR_ORIGINAL) | ||
59 | goto out; | ||
60 | |||
61 | rcu_read_lock(); | ||
62 | in_dev = __in_dev_get_rcu(rt->u.dst.dev); | ||
63 | if (in_dev != NULL) { | ||
64 | for_primary_ifa(in_dev) { | ||
65 | if (ifa->ifa_broadcast == iph->daddr) { | ||
66 | mask = ifa->ifa_mask; | ||
67 | break; | ||
68 | } | ||
69 | } endfor_ifa(in_dev); | ||
70 | } | ||
71 | rcu_read_unlock(); | ||
72 | |||
73 | if (mask == 0) | ||
74 | goto out; | ||
75 | |||
76 | exp = ip_conntrack_expect_alloc(ct); | ||
77 | if (exp == NULL) | ||
78 | goto out; | ||
79 | |||
80 | exp->tuple = ct->tuplehash[IP_CT_DIR_REPLY].tuple; | ||
81 | exp->tuple.src.u.udp.port = htons(NMBD_PORT); | ||
82 | |||
83 | exp->mask.src.ip = mask; | ||
84 | exp->mask.src.u.udp.port = htons(0xFFFF); | ||
85 | exp->mask.dst.ip = htonl(0xFFFFFFFF); | ||
86 | exp->mask.dst.u.udp.port = htons(0xFFFF); | ||
87 | exp->mask.dst.protonum = 0xFF; | ||
88 | |||
89 | exp->expectfn = NULL; | ||
90 | exp->flags = IP_CT_EXPECT_PERMANENT; | ||
91 | |||
92 | ip_conntrack_expect_related(exp); | ||
93 | ip_conntrack_expect_put(exp); | ||
94 | |||
95 | ip_ct_refresh(ct, *pskb, timeout * HZ); | ||
96 | out: | ||
97 | return NF_ACCEPT; | ||
98 | } | ||
99 | |||
100 | static struct ip_conntrack_helper helper = { | ||
101 | .name = "netbios-ns", | ||
102 | .tuple = { | ||
103 | .src = { | ||
104 | .u = { | ||
105 | .udp = { | ||
106 | .port = __constant_htons(NMBD_PORT), | ||
107 | } | ||
108 | } | ||
109 | }, | ||
110 | .dst = { | ||
111 | .protonum = IPPROTO_UDP, | ||
112 | }, | ||
113 | }, | ||
114 | .mask = { | ||
115 | .src = { | ||
116 | .u = { | ||
117 | .udp = { | ||
118 | .port = __constant_htons(0xFFFF), | ||
119 | } | ||
120 | } | ||
121 | }, | ||
122 | .dst = { | ||
123 | .protonum = 0xFF, | ||
124 | }, | ||
125 | }, | ||
126 | .max_expected = 1, | ||
127 | .me = THIS_MODULE, | ||
128 | .help = help, | ||
129 | }; | ||
130 | |||
131 | static int __init ip_conntrack_netbios_ns_init(void) | ||
132 | { | ||
133 | helper.timeout = timeout; | ||
134 | return ip_conntrack_helper_register(&helper); | ||
135 | } | ||
136 | |||
137 | static void __exit ip_conntrack_netbios_ns_fini(void) | ||
138 | { | ||
139 | ip_conntrack_helper_unregister(&helper); | ||
140 | } | ||
141 | |||
142 | module_init(ip_conntrack_netbios_ns_init); | ||
143 | module_exit(ip_conntrack_netbios_ns_fini); | ||
diff --git a/net/ipv4/netfilter/ip_conntrack_netlink.c b/net/ipv4/netfilter/ip_conntrack_netlink.c deleted file mode 100644 index 9228b76ccd9a..000000000000 --- a/net/ipv4/netfilter/ip_conntrack_netlink.c +++ /dev/null | |||
@@ -1,1577 +0,0 @@ | |||
1 | /* Connection tracking via netlink socket. Allows for user space | ||
2 | * protocol helpers and general trouble making from userspace. | ||
3 | * | ||
4 | * (C) 2001 by Jay Schulist <jschlst@samba.org> | ||
5 | * (C) 2002-2005 by Harald Welte <laforge@gnumonks.org> | ||
6 | * (C) 2003 by Patrick Mchardy <kaber@trash.net> | ||
7 | * (C) 2005-2006 by Pablo Neira Ayuso <pablo@eurodev.net> | ||
8 | * | ||
9 | * I've reworked this stuff to use attributes instead of conntrack | ||
10 | * structures. 5.44 am. I need more tea. --pablo 05/07/11. | ||
11 | * | ||
12 | * Initial connection tracking via netlink development funded and | ||
13 | * generally made possible by Network Robots, Inc. (www.networkrobots.com) | ||
14 | * | ||
15 | * Further development of this code funded by Astaro AG (http://www.astaro.com) | ||
16 | * | ||
17 | * This software may be used and distributed according to the terms | ||
18 | * of the GNU General Public License, incorporated herein by reference. | ||
19 | */ | ||
20 | |||
21 | #include <linux/init.h> | ||
22 | #include <linux/module.h> | ||
23 | #include <linux/kernel.h> | ||
24 | #include <linux/types.h> | ||
25 | #include <linux/timer.h> | ||
26 | #include <linux/skbuff.h> | ||
27 | #include <linux/errno.h> | ||
28 | #include <linux/netlink.h> | ||
29 | #include <linux/spinlock.h> | ||
30 | #include <linux/interrupt.h> | ||
31 | #include <linux/notifier.h> | ||
32 | |||
33 | #include <linux/netfilter.h> | ||
34 | #include <linux/netfilter_ipv4/ip_conntrack.h> | ||
35 | #include <linux/netfilter_ipv4/ip_conntrack_core.h> | ||
36 | #include <linux/netfilter_ipv4/ip_conntrack_helper.h> | ||
37 | #include <linux/netfilter_ipv4/ip_conntrack_protocol.h> | ||
38 | #include <linux/netfilter_ipv4/ip_nat_protocol.h> | ||
39 | |||
40 | #include <linux/netfilter/nfnetlink.h> | ||
41 | #include <linux/netfilter/nfnetlink_conntrack.h> | ||
42 | |||
43 | MODULE_LICENSE("GPL"); | ||
44 | |||
45 | static char __initdata version[] = "0.90"; | ||
46 | |||
47 | static inline int | ||
48 | ctnetlink_dump_tuples_proto(struct sk_buff *skb, | ||
49 | const struct ip_conntrack_tuple *tuple, | ||
50 | struct ip_conntrack_protocol *proto) | ||
51 | { | ||
52 | int ret = 0; | ||
53 | struct nfattr *nest_parms = NFA_NEST(skb, CTA_TUPLE_PROTO); | ||
54 | |||
55 | NFA_PUT(skb, CTA_PROTO_NUM, sizeof(u_int8_t), &tuple->dst.protonum); | ||
56 | |||
57 | if (likely(proto->tuple_to_nfattr)) | ||
58 | ret = proto->tuple_to_nfattr(skb, tuple); | ||
59 | |||
60 | NFA_NEST_END(skb, nest_parms); | ||
61 | |||
62 | return ret; | ||
63 | |||
64 | nfattr_failure: | ||
65 | return -1; | ||
66 | } | ||
67 | |||
68 | static inline int | ||
69 | ctnetlink_dump_tuples_ip(struct sk_buff *skb, | ||
70 | const struct ip_conntrack_tuple *tuple) | ||
71 | { | ||
72 | struct nfattr *nest_parms = NFA_NEST(skb, CTA_TUPLE_IP); | ||
73 | |||
74 | NFA_PUT(skb, CTA_IP_V4_SRC, sizeof(__be32), &tuple->src.ip); | ||
75 | NFA_PUT(skb, CTA_IP_V4_DST, sizeof(__be32), &tuple->dst.ip); | ||
76 | |||
77 | NFA_NEST_END(skb, nest_parms); | ||
78 | |||
79 | return 0; | ||
80 | |||
81 | nfattr_failure: | ||
82 | return -1; | ||
83 | } | ||
84 | |||
85 | static inline int | ||
86 | ctnetlink_dump_tuples(struct sk_buff *skb, | ||
87 | const struct ip_conntrack_tuple *tuple) | ||
88 | { | ||
89 | int ret; | ||
90 | struct ip_conntrack_protocol *proto; | ||
91 | |||
92 | ret = ctnetlink_dump_tuples_ip(skb, tuple); | ||
93 | if (unlikely(ret < 0)) | ||
94 | return ret; | ||
95 | |||
96 | proto = ip_conntrack_proto_find_get(tuple->dst.protonum); | ||
97 | ret = ctnetlink_dump_tuples_proto(skb, tuple, proto); | ||
98 | ip_conntrack_proto_put(proto); | ||
99 | |||
100 | return ret; | ||
101 | } | ||
102 | |||
103 | static inline int | ||
104 | ctnetlink_dump_status(struct sk_buff *skb, const struct ip_conntrack *ct) | ||
105 | { | ||
106 | __be32 status = htonl((u_int32_t) ct->status); | ||
107 | NFA_PUT(skb, CTA_STATUS, sizeof(status), &status); | ||
108 | return 0; | ||
109 | |||
110 | nfattr_failure: | ||
111 | return -1; | ||
112 | } | ||
113 | |||
114 | static inline int | ||
115 | ctnetlink_dump_timeout(struct sk_buff *skb, const struct ip_conntrack *ct) | ||
116 | { | ||
117 | long timeout_l = ct->timeout.expires - jiffies; | ||
118 | __be32 timeout; | ||
119 | |||
120 | if (timeout_l < 0) | ||
121 | timeout = 0; | ||
122 | else | ||
123 | timeout = htonl(timeout_l / HZ); | ||
124 | |||
125 | NFA_PUT(skb, CTA_TIMEOUT, sizeof(timeout), &timeout); | ||
126 | return 0; | ||
127 | |||
128 | nfattr_failure: | ||
129 | return -1; | ||
130 | } | ||
131 | |||
132 | static inline int | ||
133 | ctnetlink_dump_protoinfo(struct sk_buff *skb, const struct ip_conntrack *ct) | ||
134 | { | ||
135 | struct ip_conntrack_protocol *proto = ip_conntrack_proto_find_get(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum); | ||
136 | |||
137 | struct nfattr *nest_proto; | ||
138 | int ret; | ||
139 | |||
140 | if (!proto->to_nfattr) { | ||
141 | ip_conntrack_proto_put(proto); | ||
142 | return 0; | ||
143 | } | ||
144 | |||
145 | nest_proto = NFA_NEST(skb, CTA_PROTOINFO); | ||
146 | |||
147 | ret = proto->to_nfattr(skb, nest_proto, ct); | ||
148 | |||
149 | ip_conntrack_proto_put(proto); | ||
150 | |||
151 | NFA_NEST_END(skb, nest_proto); | ||
152 | |||
153 | return ret; | ||
154 | |||
155 | nfattr_failure: | ||
156 | ip_conntrack_proto_put(proto); | ||
157 | return -1; | ||
158 | } | ||
159 | |||
160 | static inline int | ||
161 | ctnetlink_dump_helpinfo(struct sk_buff *skb, const struct ip_conntrack *ct) | ||
162 | { | ||
163 | struct nfattr *nest_helper; | ||
164 | |||
165 | if (!ct->helper) | ||
166 | return 0; | ||
167 | |||
168 | nest_helper = NFA_NEST(skb, CTA_HELP); | ||
169 | NFA_PUT(skb, CTA_HELP_NAME, strlen(ct->helper->name), ct->helper->name); | ||
170 | |||
171 | if (ct->helper->to_nfattr) | ||
172 | ct->helper->to_nfattr(skb, ct); | ||
173 | |||
174 | NFA_NEST_END(skb, nest_helper); | ||
175 | |||
176 | return 0; | ||
177 | |||
178 | nfattr_failure: | ||
179 | return -1; | ||
180 | } | ||
181 | |||
182 | #ifdef CONFIG_IP_NF_CT_ACCT | ||
183 | static inline int | ||
184 | ctnetlink_dump_counters(struct sk_buff *skb, const struct ip_conntrack *ct, | ||
185 | enum ip_conntrack_dir dir) | ||
186 | { | ||
187 | enum ctattr_type type = dir ? CTA_COUNTERS_REPLY: CTA_COUNTERS_ORIG; | ||
188 | struct nfattr *nest_count = NFA_NEST(skb, type); | ||
189 | __be32 tmp; | ||
190 | |||
191 | tmp = htonl(ct->counters[dir].packets); | ||
192 | NFA_PUT(skb, CTA_COUNTERS32_PACKETS, sizeof(__be32), &tmp); | ||
193 | |||
194 | tmp = htonl(ct->counters[dir].bytes); | ||
195 | NFA_PUT(skb, CTA_COUNTERS32_BYTES, sizeof(__be32), &tmp); | ||
196 | |||
197 | NFA_NEST_END(skb, nest_count); | ||
198 | |||
199 | return 0; | ||
200 | |||
201 | nfattr_failure: | ||
202 | return -1; | ||
203 | } | ||
204 | #else | ||
205 | #define ctnetlink_dump_counters(a, b, c) (0) | ||
206 | #endif | ||
207 | |||
208 | #ifdef CONFIG_IP_NF_CONNTRACK_MARK | ||
209 | static inline int | ||
210 | ctnetlink_dump_mark(struct sk_buff *skb, const struct ip_conntrack *ct) | ||
211 | { | ||
212 | __be32 mark = htonl(ct->mark); | ||
213 | |||
214 | NFA_PUT(skb, CTA_MARK, sizeof(__be32), &mark); | ||
215 | return 0; | ||
216 | |||
217 | nfattr_failure: | ||
218 | return -1; | ||
219 | } | ||
220 | #else | ||
221 | #define ctnetlink_dump_mark(a, b) (0) | ||
222 | #endif | ||
223 | |||
224 | static inline int | ||
225 | ctnetlink_dump_id(struct sk_buff *skb, const struct ip_conntrack *ct) | ||
226 | { | ||
227 | __be32 id = htonl(ct->id); | ||
228 | NFA_PUT(skb, CTA_ID, sizeof(__be32), &id); | ||
229 | return 0; | ||
230 | |||
231 | nfattr_failure: | ||
232 | return -1; | ||
233 | } | ||
234 | |||
235 | static inline int | ||
236 | ctnetlink_dump_use(struct sk_buff *skb, const struct ip_conntrack *ct) | ||
237 | { | ||
238 | __be32 use = htonl(atomic_read(&ct->ct_general.use)); | ||
239 | |||
240 | NFA_PUT(skb, CTA_USE, sizeof(__be32), &use); | ||
241 | return 0; | ||
242 | |||
243 | nfattr_failure: | ||
244 | return -1; | ||
245 | } | ||
246 | |||
247 | #define tuple(ct, dir) (&(ct)->tuplehash[dir].tuple) | ||
248 | |||
249 | static int | ||
250 | ctnetlink_fill_info(struct sk_buff *skb, u32 pid, u32 seq, | ||
251 | int event, int nowait, | ||
252 | const struct ip_conntrack *ct) | ||
253 | { | ||
254 | struct nlmsghdr *nlh; | ||
255 | struct nfgenmsg *nfmsg; | ||
256 | struct nfattr *nest_parms; | ||
257 | unsigned char *b; | ||
258 | |||
259 | b = skb->tail; | ||
260 | |||
261 | event |= NFNL_SUBSYS_CTNETLINK << 8; | ||
262 | nlh = NLMSG_PUT(skb, pid, seq, event, sizeof(struct nfgenmsg)); | ||
263 | nfmsg = NLMSG_DATA(nlh); | ||
264 | |||
265 | nlh->nlmsg_flags = (nowait && pid) ? NLM_F_MULTI : 0; | ||
266 | nfmsg->nfgen_family = AF_INET; | ||
267 | nfmsg->version = NFNETLINK_V0; | ||
268 | nfmsg->res_id = 0; | ||
269 | |||
270 | nest_parms = NFA_NEST(skb, CTA_TUPLE_ORIG); | ||
271 | if (ctnetlink_dump_tuples(skb, tuple(ct, IP_CT_DIR_ORIGINAL)) < 0) | ||
272 | goto nfattr_failure; | ||
273 | NFA_NEST_END(skb, nest_parms); | ||
274 | |||
275 | nest_parms = NFA_NEST(skb, CTA_TUPLE_REPLY); | ||
276 | if (ctnetlink_dump_tuples(skb, tuple(ct, IP_CT_DIR_REPLY)) < 0) | ||
277 | goto nfattr_failure; | ||
278 | NFA_NEST_END(skb, nest_parms); | ||
279 | |||
280 | if (ctnetlink_dump_status(skb, ct) < 0 || | ||
281 | ctnetlink_dump_timeout(skb, ct) < 0 || | ||
282 | ctnetlink_dump_counters(skb, ct, IP_CT_DIR_ORIGINAL) < 0 || | ||
283 | ctnetlink_dump_counters(skb, ct, IP_CT_DIR_REPLY) < 0 || | ||
284 | ctnetlink_dump_protoinfo(skb, ct) < 0 || | ||
285 | ctnetlink_dump_helpinfo(skb, ct) < 0 || | ||
286 | ctnetlink_dump_mark(skb, ct) < 0 || | ||
287 | ctnetlink_dump_id(skb, ct) < 0 || | ||
288 | ctnetlink_dump_use(skb, ct) < 0) | ||
289 | goto nfattr_failure; | ||
290 | |||
291 | nlh->nlmsg_len = skb->tail - b; | ||
292 | return skb->len; | ||
293 | |||
294 | nlmsg_failure: | ||
295 | nfattr_failure: | ||
296 | skb_trim(skb, b - skb->data); | ||
297 | return -1; | ||
298 | } | ||
299 | |||
300 | #ifdef CONFIG_IP_NF_CONNTRACK_EVENTS | ||
301 | static int ctnetlink_conntrack_event(struct notifier_block *this, | ||
302 | unsigned long events, void *ptr) | ||
303 | { | ||
304 | struct nlmsghdr *nlh; | ||
305 | struct nfgenmsg *nfmsg; | ||
306 | struct nfattr *nest_parms; | ||
307 | struct ip_conntrack *ct = (struct ip_conntrack *)ptr; | ||
308 | struct sk_buff *skb; | ||
309 | unsigned int type; | ||
310 | unsigned char *b; | ||
311 | unsigned int flags = 0, group; | ||
312 | |||
313 | /* ignore our fake conntrack entry */ | ||
314 | if (ct == &ip_conntrack_untracked) | ||
315 | return NOTIFY_DONE; | ||
316 | |||
317 | if (events & IPCT_DESTROY) { | ||
318 | type = IPCTNL_MSG_CT_DELETE; | ||
319 | group = NFNLGRP_CONNTRACK_DESTROY; | ||
320 | } else if (events & (IPCT_NEW | IPCT_RELATED)) { | ||
321 | type = IPCTNL_MSG_CT_NEW; | ||
322 | flags = NLM_F_CREATE|NLM_F_EXCL; | ||
323 | group = NFNLGRP_CONNTRACK_NEW; | ||
324 | } else if (events & (IPCT_STATUS | IPCT_PROTOINFO)) { | ||
325 | type = IPCTNL_MSG_CT_NEW; | ||
326 | group = NFNLGRP_CONNTRACK_UPDATE; | ||
327 | } else | ||
328 | return NOTIFY_DONE; | ||
329 | |||
330 | if (!nfnetlink_has_listeners(group)) | ||
331 | return NOTIFY_DONE; | ||
332 | |||
333 | skb = alloc_skb(NLMSG_GOODSIZE, GFP_ATOMIC); | ||
334 | if (!skb) | ||
335 | return NOTIFY_DONE; | ||
336 | |||
337 | b = skb->tail; | ||
338 | |||
339 | type |= NFNL_SUBSYS_CTNETLINK << 8; | ||
340 | nlh = NLMSG_PUT(skb, 0, 0, type, sizeof(struct nfgenmsg)); | ||
341 | nfmsg = NLMSG_DATA(nlh); | ||
342 | |||
343 | nlh->nlmsg_flags = flags; | ||
344 | nfmsg->nfgen_family = AF_INET; | ||
345 | nfmsg->version = NFNETLINK_V0; | ||
346 | nfmsg->res_id = 0; | ||
347 | |||
348 | nest_parms = NFA_NEST(skb, CTA_TUPLE_ORIG); | ||
349 | if (ctnetlink_dump_tuples(skb, tuple(ct, IP_CT_DIR_ORIGINAL)) < 0) | ||
350 | goto nfattr_failure; | ||
351 | NFA_NEST_END(skb, nest_parms); | ||
352 | |||
353 | nest_parms = NFA_NEST(skb, CTA_TUPLE_REPLY); | ||
354 | if (ctnetlink_dump_tuples(skb, tuple(ct, IP_CT_DIR_REPLY)) < 0) | ||
355 | goto nfattr_failure; | ||
356 | NFA_NEST_END(skb, nest_parms); | ||
357 | |||
358 | if (events & IPCT_DESTROY) { | ||
359 | if (ctnetlink_dump_counters(skb, ct, IP_CT_DIR_ORIGINAL) < 0 || | ||
360 | ctnetlink_dump_counters(skb, ct, IP_CT_DIR_REPLY) < 0) | ||
361 | goto nfattr_failure; | ||
362 | } else { | ||
363 | if (ctnetlink_dump_status(skb, ct) < 0) | ||
364 | goto nfattr_failure; | ||
365 | |||
366 | if (ctnetlink_dump_timeout(skb, ct) < 0) | ||
367 | goto nfattr_failure; | ||
368 | |||
369 | if (events & IPCT_PROTOINFO | ||
370 | && ctnetlink_dump_protoinfo(skb, ct) < 0) | ||
371 | goto nfattr_failure; | ||
372 | |||
373 | if ((events & IPCT_HELPER || ct->helper) | ||
374 | && ctnetlink_dump_helpinfo(skb, ct) < 0) | ||
375 | goto nfattr_failure; | ||
376 | |||
377 | #ifdef CONFIG_IP_NF_CONNTRACK_MARK | ||
378 | if ((events & IPCT_MARK || ct->mark) | ||
379 | && ctnetlink_dump_mark(skb, ct) < 0) | ||
380 | goto nfattr_failure; | ||
381 | #endif | ||
382 | |||
383 | if (events & IPCT_COUNTER_FILLING && | ||
384 | (ctnetlink_dump_counters(skb, ct, IP_CT_DIR_ORIGINAL) < 0 || | ||
385 | ctnetlink_dump_counters(skb, ct, IP_CT_DIR_REPLY) < 0)) | ||
386 | goto nfattr_failure; | ||
387 | } | ||
388 | |||
389 | nlh->nlmsg_len = skb->tail - b; | ||
390 | nfnetlink_send(skb, 0, group, 0); | ||
391 | return NOTIFY_DONE; | ||
392 | |||
393 | nlmsg_failure: | ||
394 | nfattr_failure: | ||
395 | kfree_skb(skb); | ||
396 | return NOTIFY_DONE; | ||
397 | } | ||
398 | #endif /* CONFIG_IP_NF_CONNTRACK_EVENTS */ | ||
399 | |||
400 | static int ctnetlink_done(struct netlink_callback *cb) | ||
401 | { | ||
402 | if (cb->args[1]) | ||
403 | ip_conntrack_put((struct ip_conntrack *)cb->args[1]); | ||
404 | return 0; | ||
405 | } | ||
406 | |||
407 | static int | ||
408 | ctnetlink_dump_table(struct sk_buff *skb, struct netlink_callback *cb) | ||
409 | { | ||
410 | struct ip_conntrack *ct, *last; | ||
411 | struct ip_conntrack_tuple_hash *h; | ||
412 | struct list_head *i; | ||
413 | |||
414 | read_lock_bh(&ip_conntrack_lock); | ||
415 | last = (struct ip_conntrack *)cb->args[1]; | ||
416 | for (; cb->args[0] < ip_conntrack_htable_size; cb->args[0]++) { | ||
417 | restart: | ||
418 | list_for_each_prev(i, &ip_conntrack_hash[cb->args[0]]) { | ||
419 | h = (struct ip_conntrack_tuple_hash *) i; | ||
420 | if (DIRECTION(h) != IP_CT_DIR_ORIGINAL) | ||
421 | continue; | ||
422 | ct = tuplehash_to_ctrack(h); | ||
423 | if (cb->args[1]) { | ||
424 | if (ct != last) | ||
425 | continue; | ||
426 | cb->args[1] = 0; | ||
427 | } | ||
428 | if (ctnetlink_fill_info(skb, NETLINK_CB(cb->skb).pid, | ||
429 | cb->nlh->nlmsg_seq, | ||
430 | IPCTNL_MSG_CT_NEW, | ||
431 | 1, ct) < 0) { | ||
432 | nf_conntrack_get(&ct->ct_general); | ||
433 | cb->args[1] = (unsigned long)ct; | ||
434 | goto out; | ||
435 | } | ||
436 | #ifdef CONFIG_NF_CT_ACCT | ||
437 | if (NFNL_MSG_TYPE(cb->nlh->nlmsg_type) == | ||
438 | IPCTNL_MSG_CT_GET_CTRZERO) | ||
439 | memset(&ct->counters, 0, sizeof(ct->counters)); | ||
440 | #endif | ||
441 | } | ||
442 | if (cb->args[1]) { | ||
443 | cb->args[1] = 0; | ||
444 | goto restart; | ||
445 | } | ||
446 | } | ||
447 | out: | ||
448 | read_unlock_bh(&ip_conntrack_lock); | ||
449 | if (last) | ||
450 | ip_conntrack_put(last); | ||
451 | |||
452 | return skb->len; | ||
453 | } | ||
454 | |||
455 | static const size_t cta_min_ip[CTA_IP_MAX] = { | ||
456 | [CTA_IP_V4_SRC-1] = sizeof(__be32), | ||
457 | [CTA_IP_V4_DST-1] = sizeof(__be32), | ||
458 | }; | ||
459 | |||
460 | static inline int | ||
461 | ctnetlink_parse_tuple_ip(struct nfattr *attr, struct ip_conntrack_tuple *tuple) | ||
462 | { | ||
463 | struct nfattr *tb[CTA_IP_MAX]; | ||
464 | |||
465 | nfattr_parse_nested(tb, CTA_IP_MAX, attr); | ||
466 | |||
467 | if (nfattr_bad_size(tb, CTA_IP_MAX, cta_min_ip)) | ||
468 | return -EINVAL; | ||
469 | |||
470 | if (!tb[CTA_IP_V4_SRC-1]) | ||
471 | return -EINVAL; | ||
472 | tuple->src.ip = *(__be32 *)NFA_DATA(tb[CTA_IP_V4_SRC-1]); | ||
473 | |||
474 | if (!tb[CTA_IP_V4_DST-1]) | ||
475 | return -EINVAL; | ||
476 | tuple->dst.ip = *(__be32 *)NFA_DATA(tb[CTA_IP_V4_DST-1]); | ||
477 | |||
478 | return 0; | ||
479 | } | ||
480 | |||
481 | static const size_t cta_min_proto[CTA_PROTO_MAX] = { | ||
482 | [CTA_PROTO_NUM-1] = sizeof(u_int8_t), | ||
483 | [CTA_PROTO_SRC_PORT-1] = sizeof(u_int16_t), | ||
484 | [CTA_PROTO_DST_PORT-1] = sizeof(u_int16_t), | ||
485 | [CTA_PROTO_ICMP_TYPE-1] = sizeof(u_int8_t), | ||
486 | [CTA_PROTO_ICMP_CODE-1] = sizeof(u_int8_t), | ||
487 | [CTA_PROTO_ICMP_ID-1] = sizeof(u_int16_t), | ||
488 | }; | ||
489 | |||
490 | static inline int | ||
491 | ctnetlink_parse_tuple_proto(struct nfattr *attr, | ||
492 | struct ip_conntrack_tuple *tuple) | ||
493 | { | ||
494 | struct nfattr *tb[CTA_PROTO_MAX]; | ||
495 | struct ip_conntrack_protocol *proto; | ||
496 | int ret = 0; | ||
497 | |||
498 | nfattr_parse_nested(tb, CTA_PROTO_MAX, attr); | ||
499 | |||
500 | if (nfattr_bad_size(tb, CTA_PROTO_MAX, cta_min_proto)) | ||
501 | return -EINVAL; | ||
502 | |||
503 | if (!tb[CTA_PROTO_NUM-1]) | ||
504 | return -EINVAL; | ||
505 | tuple->dst.protonum = *(u_int8_t *)NFA_DATA(tb[CTA_PROTO_NUM-1]); | ||
506 | |||
507 | proto = ip_conntrack_proto_find_get(tuple->dst.protonum); | ||
508 | |||
509 | if (likely(proto->nfattr_to_tuple)) | ||
510 | ret = proto->nfattr_to_tuple(tb, tuple); | ||
511 | |||
512 | ip_conntrack_proto_put(proto); | ||
513 | |||
514 | return ret; | ||
515 | } | ||
516 | |||
517 | static inline int | ||
518 | ctnetlink_parse_tuple(struct nfattr *cda[], struct ip_conntrack_tuple *tuple, | ||
519 | enum ctattr_tuple type) | ||
520 | { | ||
521 | struct nfattr *tb[CTA_TUPLE_MAX]; | ||
522 | int err; | ||
523 | |||
524 | memset(tuple, 0, sizeof(*tuple)); | ||
525 | |||
526 | nfattr_parse_nested(tb, CTA_TUPLE_MAX, cda[type-1]); | ||
527 | |||
528 | if (!tb[CTA_TUPLE_IP-1]) | ||
529 | return -EINVAL; | ||
530 | |||
531 | err = ctnetlink_parse_tuple_ip(tb[CTA_TUPLE_IP-1], tuple); | ||
532 | if (err < 0) | ||
533 | return err; | ||
534 | |||
535 | if (!tb[CTA_TUPLE_PROTO-1]) | ||
536 | return -EINVAL; | ||
537 | |||
538 | err = ctnetlink_parse_tuple_proto(tb[CTA_TUPLE_PROTO-1], tuple); | ||
539 | if (err < 0) | ||
540 | return err; | ||
541 | |||
542 | /* orig and expect tuples get DIR_ORIGINAL */ | ||
543 | if (type == CTA_TUPLE_REPLY) | ||
544 | tuple->dst.dir = IP_CT_DIR_REPLY; | ||
545 | else | ||
546 | tuple->dst.dir = IP_CT_DIR_ORIGINAL; | ||
547 | |||
548 | return 0; | ||
549 | } | ||
550 | |||
551 | #ifdef CONFIG_IP_NF_NAT_NEEDED | ||
552 | static const size_t cta_min_protonat[CTA_PROTONAT_MAX] = { | ||
553 | [CTA_PROTONAT_PORT_MIN-1] = sizeof(u_int16_t), | ||
554 | [CTA_PROTONAT_PORT_MAX-1] = sizeof(u_int16_t), | ||
555 | }; | ||
556 | |||
557 | static int ctnetlink_parse_nat_proto(struct nfattr *attr, | ||
558 | const struct ip_conntrack *ct, | ||
559 | struct ip_nat_range *range) | ||
560 | { | ||
561 | struct nfattr *tb[CTA_PROTONAT_MAX]; | ||
562 | struct ip_nat_protocol *npt; | ||
563 | |||
564 | nfattr_parse_nested(tb, CTA_PROTONAT_MAX, attr); | ||
565 | |||
566 | if (nfattr_bad_size(tb, CTA_PROTONAT_MAX, cta_min_protonat)) | ||
567 | return -EINVAL; | ||
568 | |||
569 | npt = ip_nat_proto_find_get(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum); | ||
570 | |||
571 | if (!npt->nfattr_to_range) { | ||
572 | ip_nat_proto_put(npt); | ||
573 | return 0; | ||
574 | } | ||
575 | |||
576 | /* nfattr_to_range returns 1 if it parsed, 0 if not, neg. on error */ | ||
577 | if (npt->nfattr_to_range(tb, range) > 0) | ||
578 | range->flags |= IP_NAT_RANGE_PROTO_SPECIFIED; | ||
579 | |||
580 | ip_nat_proto_put(npt); | ||
581 | |||
582 | return 0; | ||
583 | } | ||
584 | |||
585 | static const size_t cta_min_nat[CTA_NAT_MAX] = { | ||
586 | [CTA_NAT_MINIP-1] = sizeof(__be32), | ||
587 | [CTA_NAT_MAXIP-1] = sizeof(__be32), | ||
588 | }; | ||
589 | |||
590 | static inline int | ||
591 | ctnetlink_parse_nat(struct nfattr *nat, | ||
592 | const struct ip_conntrack *ct, struct ip_nat_range *range) | ||
593 | { | ||
594 | struct nfattr *tb[CTA_NAT_MAX]; | ||
595 | int err; | ||
596 | |||
597 | memset(range, 0, sizeof(*range)); | ||
598 | |||
599 | nfattr_parse_nested(tb, CTA_NAT_MAX, nat); | ||
600 | |||
601 | if (nfattr_bad_size(tb, CTA_NAT_MAX, cta_min_nat)) | ||
602 | return -EINVAL; | ||
603 | |||
604 | if (tb[CTA_NAT_MINIP-1]) | ||
605 | range->min_ip = *(__be32 *)NFA_DATA(tb[CTA_NAT_MINIP-1]); | ||
606 | |||
607 | if (!tb[CTA_NAT_MAXIP-1]) | ||
608 | range->max_ip = range->min_ip; | ||
609 | else | ||
610 | range->max_ip = *(__be32 *)NFA_DATA(tb[CTA_NAT_MAXIP-1]); | ||
611 | |||
612 | if (range->min_ip) | ||
613 | range->flags |= IP_NAT_RANGE_MAP_IPS; | ||
614 | |||
615 | if (!tb[CTA_NAT_PROTO-1]) | ||
616 | return 0; | ||
617 | |||
618 | err = ctnetlink_parse_nat_proto(tb[CTA_NAT_PROTO-1], ct, range); | ||
619 | if (err < 0) | ||
620 | return err; | ||
621 | |||
622 | return 0; | ||
623 | } | ||
624 | #endif | ||
625 | |||
626 | static inline int | ||
627 | ctnetlink_parse_help(struct nfattr *attr, char **helper_name) | ||
628 | { | ||
629 | struct nfattr *tb[CTA_HELP_MAX]; | ||
630 | |||
631 | nfattr_parse_nested(tb, CTA_HELP_MAX, attr); | ||
632 | |||
633 | if (!tb[CTA_HELP_NAME-1]) | ||
634 | return -EINVAL; | ||
635 | |||
636 | *helper_name = NFA_DATA(tb[CTA_HELP_NAME-1]); | ||
637 | |||
638 | return 0; | ||
639 | } | ||
640 | |||
641 | static const size_t cta_min[CTA_MAX] = { | ||
642 | [CTA_STATUS-1] = sizeof(__be32), | ||
643 | [CTA_TIMEOUT-1] = sizeof(__be32), | ||
644 | [CTA_MARK-1] = sizeof(__be32), | ||
645 | [CTA_USE-1] = sizeof(__be32), | ||
646 | [CTA_ID-1] = sizeof(__be32) | ||
647 | }; | ||
648 | |||
649 | static int | ||
650 | ctnetlink_del_conntrack(struct sock *ctnl, struct sk_buff *skb, | ||
651 | struct nlmsghdr *nlh, struct nfattr *cda[], int *errp) | ||
652 | { | ||
653 | struct ip_conntrack_tuple_hash *h; | ||
654 | struct ip_conntrack_tuple tuple; | ||
655 | struct ip_conntrack *ct; | ||
656 | int err = 0; | ||
657 | |||
658 | if (nfattr_bad_size(cda, CTA_MAX, cta_min)) | ||
659 | return -EINVAL; | ||
660 | |||
661 | if (cda[CTA_TUPLE_ORIG-1]) | ||
662 | err = ctnetlink_parse_tuple(cda, &tuple, CTA_TUPLE_ORIG); | ||
663 | else if (cda[CTA_TUPLE_REPLY-1]) | ||
664 | err = ctnetlink_parse_tuple(cda, &tuple, CTA_TUPLE_REPLY); | ||
665 | else { | ||
666 | /* Flush the whole table */ | ||
667 | ip_conntrack_flush(); | ||
668 | return 0; | ||
669 | } | ||
670 | |||
671 | if (err < 0) | ||
672 | return err; | ||
673 | |||
674 | h = ip_conntrack_find_get(&tuple, NULL); | ||
675 | if (!h) | ||
676 | return -ENOENT; | ||
677 | |||
678 | ct = tuplehash_to_ctrack(h); | ||
679 | |||
680 | if (cda[CTA_ID-1]) { | ||
681 | u_int32_t id = ntohl(*(__be32 *)NFA_DATA(cda[CTA_ID-1])); | ||
682 | if (ct->id != id) { | ||
683 | ip_conntrack_put(ct); | ||
684 | return -ENOENT; | ||
685 | } | ||
686 | } | ||
687 | if (del_timer(&ct->timeout)) | ||
688 | ct->timeout.function((unsigned long)ct); | ||
689 | |||
690 | ip_conntrack_put(ct); | ||
691 | |||
692 | return 0; | ||
693 | } | ||
694 | |||
695 | static int | ||
696 | ctnetlink_get_conntrack(struct sock *ctnl, struct sk_buff *skb, | ||
697 | struct nlmsghdr *nlh, struct nfattr *cda[], int *errp) | ||
698 | { | ||
699 | struct ip_conntrack_tuple_hash *h; | ||
700 | struct ip_conntrack_tuple tuple; | ||
701 | struct ip_conntrack *ct; | ||
702 | struct sk_buff *skb2 = NULL; | ||
703 | int err = 0; | ||
704 | |||
705 | if (nlh->nlmsg_flags & NLM_F_DUMP) { | ||
706 | struct nfgenmsg *msg = NLMSG_DATA(nlh); | ||
707 | u32 rlen; | ||
708 | |||
709 | if (msg->nfgen_family != AF_INET) | ||
710 | return -EAFNOSUPPORT; | ||
711 | |||
712 | #ifndef CONFIG_IP_NF_CT_ACCT | ||
713 | if (NFNL_MSG_TYPE(nlh->nlmsg_type) == IPCTNL_MSG_CT_GET_CTRZERO) | ||
714 | return -ENOTSUPP; | ||
715 | #endif | ||
716 | if ((*errp = netlink_dump_start(ctnl, skb, nlh, | ||
717 | ctnetlink_dump_table, | ||
718 | ctnetlink_done)) != 0) | ||
719 | return -EINVAL; | ||
720 | |||
721 | rlen = NLMSG_ALIGN(nlh->nlmsg_len); | ||
722 | if (rlen > skb->len) | ||
723 | rlen = skb->len; | ||
724 | skb_pull(skb, rlen); | ||
725 | return 0; | ||
726 | } | ||
727 | |||
728 | if (nfattr_bad_size(cda, CTA_MAX, cta_min)) | ||
729 | return -EINVAL; | ||
730 | |||
731 | if (cda[CTA_TUPLE_ORIG-1]) | ||
732 | err = ctnetlink_parse_tuple(cda, &tuple, CTA_TUPLE_ORIG); | ||
733 | else if (cda[CTA_TUPLE_REPLY-1]) | ||
734 | err = ctnetlink_parse_tuple(cda, &tuple, CTA_TUPLE_REPLY); | ||
735 | else | ||
736 | return -EINVAL; | ||
737 | |||
738 | if (err < 0) | ||
739 | return err; | ||
740 | |||
741 | h = ip_conntrack_find_get(&tuple, NULL); | ||
742 | if (!h) | ||
743 | return -ENOENT; | ||
744 | |||
745 | ct = tuplehash_to_ctrack(h); | ||
746 | |||
747 | err = -ENOMEM; | ||
748 | skb2 = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); | ||
749 | if (!skb2) { | ||
750 | ip_conntrack_put(ct); | ||
751 | return -ENOMEM; | ||
752 | } | ||
753 | |||
754 | err = ctnetlink_fill_info(skb2, NETLINK_CB(skb).pid, nlh->nlmsg_seq, | ||
755 | IPCTNL_MSG_CT_NEW, 1, ct); | ||
756 | ip_conntrack_put(ct); | ||
757 | if (err <= 0) | ||
758 | goto free; | ||
759 | |||
760 | err = netlink_unicast(ctnl, skb2, NETLINK_CB(skb).pid, MSG_DONTWAIT); | ||
761 | if (err < 0) | ||
762 | goto out; | ||
763 | |||
764 | return 0; | ||
765 | |||
766 | free: | ||
767 | kfree_skb(skb2); | ||
768 | out: | ||
769 | return err; | ||
770 | } | ||
771 | |||
772 | static inline int | ||
773 | ctnetlink_change_status(struct ip_conntrack *ct, struct nfattr *cda[]) | ||
774 | { | ||
775 | unsigned long d; | ||
776 | unsigned status = ntohl(*(__be32 *)NFA_DATA(cda[CTA_STATUS-1])); | ||
777 | d = ct->status ^ status; | ||
778 | |||
779 | if (d & (IPS_EXPECTED|IPS_CONFIRMED|IPS_DYING)) | ||
780 | /* unchangeable */ | ||
781 | return -EINVAL; | ||
782 | |||
783 | if (d & IPS_SEEN_REPLY && !(status & IPS_SEEN_REPLY)) | ||
784 | /* SEEN_REPLY bit can only be set */ | ||
785 | return -EINVAL; | ||
786 | |||
787 | |||
788 | if (d & IPS_ASSURED && !(status & IPS_ASSURED)) | ||
789 | /* ASSURED bit can only be set */ | ||
790 | return -EINVAL; | ||
791 | |||
792 | if (cda[CTA_NAT_SRC-1] || cda[CTA_NAT_DST-1]) { | ||
793 | #ifndef CONFIG_IP_NF_NAT_NEEDED | ||
794 | return -EINVAL; | ||
795 | #else | ||
796 | struct ip_nat_range range; | ||
797 | |||
798 | if (cda[CTA_NAT_DST-1]) { | ||
799 | if (ctnetlink_parse_nat(cda[CTA_NAT_DST-1], ct, | ||
800 | &range) < 0) | ||
801 | return -EINVAL; | ||
802 | if (ip_nat_initialized(ct, | ||
803 | HOOK2MANIP(NF_IP_PRE_ROUTING))) | ||
804 | return -EEXIST; | ||
805 | ip_nat_setup_info(ct, &range, NF_IP_PRE_ROUTING); | ||
806 | } | ||
807 | if (cda[CTA_NAT_SRC-1]) { | ||
808 | if (ctnetlink_parse_nat(cda[CTA_NAT_SRC-1], ct, | ||
809 | &range) < 0) | ||
810 | return -EINVAL; | ||
811 | if (ip_nat_initialized(ct, | ||
812 | HOOK2MANIP(NF_IP_POST_ROUTING))) | ||
813 | return -EEXIST; | ||
814 | ip_nat_setup_info(ct, &range, NF_IP_POST_ROUTING); | ||
815 | } | ||
816 | #endif | ||
817 | } | ||
818 | |||
819 | /* Be careful here, modifying NAT bits can screw up things, | ||
820 | * so don't let users modify them directly if they don't pass | ||
821 | * ip_nat_range. */ | ||
822 | ct->status |= status & ~(IPS_NAT_DONE_MASK | IPS_NAT_MASK); | ||
823 | return 0; | ||
824 | } | ||
825 | |||
826 | |||
827 | static inline int | ||
828 | ctnetlink_change_helper(struct ip_conntrack *ct, struct nfattr *cda[]) | ||
829 | { | ||
830 | struct ip_conntrack_helper *helper; | ||
831 | char *helpname; | ||
832 | int err; | ||
833 | |||
834 | /* don't change helper of sibling connections */ | ||
835 | if (ct->master) | ||
836 | return -EINVAL; | ||
837 | |||
838 | err = ctnetlink_parse_help(cda[CTA_HELP-1], &helpname); | ||
839 | if (err < 0) | ||
840 | return err; | ||
841 | |||
842 | helper = __ip_conntrack_helper_find_byname(helpname); | ||
843 | if (!helper) { | ||
844 | if (!strcmp(helpname, "")) | ||
845 | helper = NULL; | ||
846 | else | ||
847 | return -EINVAL; | ||
848 | } | ||
849 | |||
850 | if (ct->helper) { | ||
851 | if (!helper) { | ||
852 | /* we had a helper before ... */ | ||
853 | ip_ct_remove_expectations(ct); | ||
854 | ct->helper = NULL; | ||
855 | } else { | ||
856 | /* need to zero data of old helper */ | ||
857 | memset(&ct->help, 0, sizeof(ct->help)); | ||
858 | } | ||
859 | } | ||
860 | |||
861 | ct->helper = helper; | ||
862 | |||
863 | return 0; | ||
864 | } | ||
865 | |||
866 | static inline int | ||
867 | ctnetlink_change_timeout(struct ip_conntrack *ct, struct nfattr *cda[]) | ||
868 | { | ||
869 | u_int32_t timeout = ntohl(*(__be32 *)NFA_DATA(cda[CTA_TIMEOUT-1])); | ||
870 | |||
871 | if (!del_timer(&ct->timeout)) | ||
872 | return -ETIME; | ||
873 | |||
874 | ct->timeout.expires = jiffies + timeout * HZ; | ||
875 | add_timer(&ct->timeout); | ||
876 | |||
877 | return 0; | ||
878 | } | ||
879 | |||
880 | static inline int | ||
881 | ctnetlink_change_protoinfo(struct ip_conntrack *ct, struct nfattr *cda[]) | ||
882 | { | ||
883 | struct nfattr *tb[CTA_PROTOINFO_MAX], *attr = cda[CTA_PROTOINFO-1]; | ||
884 | struct ip_conntrack_protocol *proto; | ||
885 | u_int16_t npt = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum; | ||
886 | int err = 0; | ||
887 | |||
888 | nfattr_parse_nested(tb, CTA_PROTOINFO_MAX, attr); | ||
889 | |||
890 | proto = ip_conntrack_proto_find_get(npt); | ||
891 | |||
892 | if (proto->from_nfattr) | ||
893 | err = proto->from_nfattr(tb, ct); | ||
894 | ip_conntrack_proto_put(proto); | ||
895 | |||
896 | return err; | ||
897 | } | ||
898 | |||
899 | static int | ||
900 | ctnetlink_change_conntrack(struct ip_conntrack *ct, struct nfattr *cda[]) | ||
901 | { | ||
902 | int err; | ||
903 | |||
904 | if (cda[CTA_HELP-1]) { | ||
905 | err = ctnetlink_change_helper(ct, cda); | ||
906 | if (err < 0) | ||
907 | return err; | ||
908 | } | ||
909 | |||
910 | if (cda[CTA_TIMEOUT-1]) { | ||
911 | err = ctnetlink_change_timeout(ct, cda); | ||
912 | if (err < 0) | ||
913 | return err; | ||
914 | } | ||
915 | |||
916 | if (cda[CTA_STATUS-1]) { | ||
917 | err = ctnetlink_change_status(ct, cda); | ||
918 | if (err < 0) | ||
919 | return err; | ||
920 | } | ||
921 | |||
922 | if (cda[CTA_PROTOINFO-1]) { | ||
923 | err = ctnetlink_change_protoinfo(ct, cda); | ||
924 | if (err < 0) | ||
925 | return err; | ||
926 | } | ||
927 | |||
928 | #if defined(CONFIG_IP_NF_CONNTRACK_MARK) | ||
929 | if (cda[CTA_MARK-1]) | ||
930 | ct->mark = ntohl(*(__be32 *)NFA_DATA(cda[CTA_MARK-1])); | ||
931 | #endif | ||
932 | |||
933 | return 0; | ||
934 | } | ||
935 | |||
936 | static int | ||
937 | ctnetlink_create_conntrack(struct nfattr *cda[], | ||
938 | struct ip_conntrack_tuple *otuple, | ||
939 | struct ip_conntrack_tuple *rtuple) | ||
940 | { | ||
941 | struct ip_conntrack *ct; | ||
942 | int err = -EINVAL; | ||
943 | |||
944 | ct = ip_conntrack_alloc(otuple, rtuple); | ||
945 | if (ct == NULL || IS_ERR(ct)) | ||
946 | return -ENOMEM; | ||
947 | |||
948 | if (!cda[CTA_TIMEOUT-1]) | ||
949 | goto err; | ||
950 | ct->timeout.expires = ntohl(*(__be32 *)NFA_DATA(cda[CTA_TIMEOUT-1])); | ||
951 | |||
952 | ct->timeout.expires = jiffies + ct->timeout.expires * HZ; | ||
953 | ct->status |= IPS_CONFIRMED; | ||
954 | |||
955 | if (cda[CTA_STATUS-1]) { | ||
956 | err = ctnetlink_change_status(ct, cda); | ||
957 | if (err < 0) | ||
958 | goto err; | ||
959 | } | ||
960 | |||
961 | if (cda[CTA_PROTOINFO-1]) { | ||
962 | err = ctnetlink_change_protoinfo(ct, cda); | ||
963 | if (err < 0) | ||
964 | goto err; | ||
965 | } | ||
966 | |||
967 | #if defined(CONFIG_IP_NF_CONNTRACK_MARK) | ||
968 | if (cda[CTA_MARK-1]) | ||
969 | ct->mark = ntohl(*(__be32 *)NFA_DATA(cda[CTA_MARK-1])); | ||
970 | #endif | ||
971 | |||
972 | ct->helper = ip_conntrack_helper_find_get(rtuple); | ||
973 | |||
974 | add_timer(&ct->timeout); | ||
975 | ip_conntrack_hash_insert(ct); | ||
976 | |||
977 | if (ct->helper) | ||
978 | ip_conntrack_helper_put(ct->helper); | ||
979 | |||
980 | return 0; | ||
981 | |||
982 | err: | ||
983 | ip_conntrack_free(ct); | ||
984 | return err; | ||
985 | } | ||
986 | |||
987 | static int | ||
988 | ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb, | ||
989 | struct nlmsghdr *nlh, struct nfattr *cda[], int *errp) | ||
990 | { | ||
991 | struct ip_conntrack_tuple otuple, rtuple; | ||
992 | struct ip_conntrack_tuple_hash *h = NULL; | ||
993 | int err = 0; | ||
994 | |||
995 | if (nfattr_bad_size(cda, CTA_MAX, cta_min)) | ||
996 | return -EINVAL; | ||
997 | |||
998 | if (cda[CTA_TUPLE_ORIG-1]) { | ||
999 | err = ctnetlink_parse_tuple(cda, &otuple, CTA_TUPLE_ORIG); | ||
1000 | if (err < 0) | ||
1001 | return err; | ||
1002 | } | ||
1003 | |||
1004 | if (cda[CTA_TUPLE_REPLY-1]) { | ||
1005 | err = ctnetlink_parse_tuple(cda, &rtuple, CTA_TUPLE_REPLY); | ||
1006 | if (err < 0) | ||
1007 | return err; | ||
1008 | } | ||
1009 | |||
1010 | write_lock_bh(&ip_conntrack_lock); | ||
1011 | if (cda[CTA_TUPLE_ORIG-1]) | ||
1012 | h = __ip_conntrack_find(&otuple, NULL); | ||
1013 | else if (cda[CTA_TUPLE_REPLY-1]) | ||
1014 | h = __ip_conntrack_find(&rtuple, NULL); | ||
1015 | |||
1016 | if (h == NULL) { | ||
1017 | write_unlock_bh(&ip_conntrack_lock); | ||
1018 | err = -ENOENT; | ||
1019 | if (nlh->nlmsg_flags & NLM_F_CREATE) | ||
1020 | err = ctnetlink_create_conntrack(cda, &otuple, &rtuple); | ||
1021 | return err; | ||
1022 | } | ||
1023 | /* implicit 'else' */ | ||
1024 | |||
1025 | /* we only allow nat config for new conntracks */ | ||
1026 | if (cda[CTA_NAT_SRC-1] || cda[CTA_NAT_DST-1]) { | ||
1027 | err = -EINVAL; | ||
1028 | goto out_unlock; | ||
1029 | } | ||
1030 | |||
1031 | /* We manipulate the conntrack inside the global conntrack table lock, | ||
1032 | * so there's no need to increase the refcount */ | ||
1033 | err = -EEXIST; | ||
1034 | if (!(nlh->nlmsg_flags & NLM_F_EXCL)) | ||
1035 | err = ctnetlink_change_conntrack(tuplehash_to_ctrack(h), cda); | ||
1036 | |||
1037 | out_unlock: | ||
1038 | write_unlock_bh(&ip_conntrack_lock); | ||
1039 | return err; | ||
1040 | } | ||
1041 | |||
1042 | /*********************************************************************** | ||
1043 | * EXPECT | ||
1044 | ***********************************************************************/ | ||
1045 | |||
1046 | static inline int | ||
1047 | ctnetlink_exp_dump_tuple(struct sk_buff *skb, | ||
1048 | const struct ip_conntrack_tuple *tuple, | ||
1049 | enum ctattr_expect type) | ||
1050 | { | ||
1051 | struct nfattr *nest_parms = NFA_NEST(skb, type); | ||
1052 | |||
1053 | if (ctnetlink_dump_tuples(skb, tuple) < 0) | ||
1054 | goto nfattr_failure; | ||
1055 | |||
1056 | NFA_NEST_END(skb, nest_parms); | ||
1057 | |||
1058 | return 0; | ||
1059 | |||
1060 | nfattr_failure: | ||
1061 | return -1; | ||
1062 | } | ||
1063 | |||
1064 | static inline int | ||
1065 | ctnetlink_exp_dump_mask(struct sk_buff *skb, | ||
1066 | const struct ip_conntrack_tuple *tuple, | ||
1067 | const struct ip_conntrack_tuple *mask) | ||
1068 | { | ||
1069 | int ret; | ||
1070 | struct ip_conntrack_protocol *proto; | ||
1071 | struct nfattr *nest_parms = NFA_NEST(skb, CTA_EXPECT_MASK); | ||
1072 | |||
1073 | ret = ctnetlink_dump_tuples_ip(skb, mask); | ||
1074 | if (unlikely(ret < 0)) | ||
1075 | goto nfattr_failure; | ||
1076 | |||
1077 | proto = ip_conntrack_proto_find_get(tuple->dst.protonum); | ||
1078 | ret = ctnetlink_dump_tuples_proto(skb, mask, proto); | ||
1079 | ip_conntrack_proto_put(proto); | ||
1080 | if (unlikely(ret < 0)) | ||
1081 | goto nfattr_failure; | ||
1082 | |||
1083 | NFA_NEST_END(skb, nest_parms); | ||
1084 | |||
1085 | return 0; | ||
1086 | |||
1087 | nfattr_failure: | ||
1088 | return -1; | ||
1089 | } | ||
1090 | |||
1091 | static inline int | ||
1092 | ctnetlink_exp_dump_expect(struct sk_buff *skb, | ||
1093 | const struct ip_conntrack_expect *exp) | ||
1094 | { | ||
1095 | struct ip_conntrack *master = exp->master; | ||
1096 | __be32 timeout = htonl((exp->timeout.expires - jiffies) / HZ); | ||
1097 | __be32 id = htonl(exp->id); | ||
1098 | |||
1099 | if (ctnetlink_exp_dump_tuple(skb, &exp->tuple, CTA_EXPECT_TUPLE) < 0) | ||
1100 | goto nfattr_failure; | ||
1101 | if (ctnetlink_exp_dump_mask(skb, &exp->tuple, &exp->mask) < 0) | ||
1102 | goto nfattr_failure; | ||
1103 | if (ctnetlink_exp_dump_tuple(skb, | ||
1104 | &master->tuplehash[IP_CT_DIR_ORIGINAL].tuple, | ||
1105 | CTA_EXPECT_MASTER) < 0) | ||
1106 | goto nfattr_failure; | ||
1107 | |||
1108 | NFA_PUT(skb, CTA_EXPECT_TIMEOUT, sizeof(__be32), &timeout); | ||
1109 | NFA_PUT(skb, CTA_EXPECT_ID, sizeof(__be32), &id); | ||
1110 | |||
1111 | return 0; | ||
1112 | |||
1113 | nfattr_failure: | ||
1114 | return -1; | ||
1115 | } | ||
1116 | |||
1117 | static int | ||
1118 | ctnetlink_exp_fill_info(struct sk_buff *skb, u32 pid, u32 seq, | ||
1119 | int event, | ||
1120 | int nowait, | ||
1121 | const struct ip_conntrack_expect *exp) | ||
1122 | { | ||
1123 | struct nlmsghdr *nlh; | ||
1124 | struct nfgenmsg *nfmsg; | ||
1125 | unsigned char *b; | ||
1126 | |||
1127 | b = skb->tail; | ||
1128 | |||
1129 | event |= NFNL_SUBSYS_CTNETLINK_EXP << 8; | ||
1130 | nlh = NLMSG_PUT(skb, pid, seq, event, sizeof(struct nfgenmsg)); | ||
1131 | nfmsg = NLMSG_DATA(nlh); | ||
1132 | |||
1133 | nlh->nlmsg_flags = (nowait && pid) ? NLM_F_MULTI : 0; | ||
1134 | nfmsg->nfgen_family = AF_INET; | ||
1135 | nfmsg->version = NFNETLINK_V0; | ||
1136 | nfmsg->res_id = 0; | ||
1137 | |||
1138 | if (ctnetlink_exp_dump_expect(skb, exp) < 0) | ||
1139 | goto nfattr_failure; | ||
1140 | |||
1141 | nlh->nlmsg_len = skb->tail - b; | ||
1142 | return skb->len; | ||
1143 | |||
1144 | nlmsg_failure: | ||
1145 | nfattr_failure: | ||
1146 | skb_trim(skb, b - skb->data); | ||
1147 | return -1; | ||
1148 | } | ||
1149 | |||
1150 | #ifdef CONFIG_IP_NF_CONNTRACK_EVENTS | ||
1151 | static int ctnetlink_expect_event(struct notifier_block *this, | ||
1152 | unsigned long events, void *ptr) | ||
1153 | { | ||
1154 | struct nlmsghdr *nlh; | ||
1155 | struct nfgenmsg *nfmsg; | ||
1156 | struct ip_conntrack_expect *exp = (struct ip_conntrack_expect *)ptr; | ||
1157 | struct sk_buff *skb; | ||
1158 | unsigned int type; | ||
1159 | unsigned char *b; | ||
1160 | int flags = 0; | ||
1161 | |||
1162 | if (events & IPEXP_NEW) { | ||
1163 | type = IPCTNL_MSG_EXP_NEW; | ||
1164 | flags = NLM_F_CREATE|NLM_F_EXCL; | ||
1165 | } else | ||
1166 | return NOTIFY_DONE; | ||
1167 | |||
1168 | if (!nfnetlink_has_listeners(NFNLGRP_CONNTRACK_EXP_NEW)) | ||
1169 | return NOTIFY_DONE; | ||
1170 | |||
1171 | skb = alloc_skb(NLMSG_GOODSIZE, GFP_ATOMIC); | ||
1172 | if (!skb) | ||
1173 | return NOTIFY_DONE; | ||
1174 | |||
1175 | b = skb->tail; | ||
1176 | |||
1177 | type |= NFNL_SUBSYS_CTNETLINK_EXP << 8; | ||
1178 | nlh = NLMSG_PUT(skb, 0, 0, type, sizeof(struct nfgenmsg)); | ||
1179 | nfmsg = NLMSG_DATA(nlh); | ||
1180 | |||
1181 | nlh->nlmsg_flags = flags; | ||
1182 | nfmsg->nfgen_family = AF_INET; | ||
1183 | nfmsg->version = NFNETLINK_V0; | ||
1184 | nfmsg->res_id = 0; | ||
1185 | |||
1186 | if (ctnetlink_exp_dump_expect(skb, exp) < 0) | ||
1187 | goto nfattr_failure; | ||
1188 | |||
1189 | nlh->nlmsg_len = skb->tail - b; | ||
1190 | nfnetlink_send(skb, 0, NFNLGRP_CONNTRACK_EXP_NEW, 0); | ||
1191 | return NOTIFY_DONE; | ||
1192 | |||
1193 | nlmsg_failure: | ||
1194 | nfattr_failure: | ||
1195 | kfree_skb(skb); | ||
1196 | return NOTIFY_DONE; | ||
1197 | } | ||
1198 | #endif | ||
1199 | |||
1200 | static int | ||
1201 | ctnetlink_exp_dump_table(struct sk_buff *skb, struct netlink_callback *cb) | ||
1202 | { | ||
1203 | struct ip_conntrack_expect *exp = NULL; | ||
1204 | struct list_head *i; | ||
1205 | u_int32_t *id = (u_int32_t *) &cb->args[0]; | ||
1206 | |||
1207 | read_lock_bh(&ip_conntrack_lock); | ||
1208 | list_for_each_prev(i, &ip_conntrack_expect_list) { | ||
1209 | exp = (struct ip_conntrack_expect *) i; | ||
1210 | if (exp->id <= *id) | ||
1211 | continue; | ||
1212 | if (ctnetlink_exp_fill_info(skb, NETLINK_CB(cb->skb).pid, | ||
1213 | cb->nlh->nlmsg_seq, | ||
1214 | IPCTNL_MSG_EXP_NEW, | ||
1215 | 1, exp) < 0) | ||
1216 | goto out; | ||
1217 | *id = exp->id; | ||
1218 | } | ||
1219 | out: | ||
1220 | read_unlock_bh(&ip_conntrack_lock); | ||
1221 | |||
1222 | return skb->len; | ||
1223 | } | ||
1224 | |||
1225 | static const size_t cta_min_exp[CTA_EXPECT_MAX] = { | ||
1226 | [CTA_EXPECT_TIMEOUT-1] = sizeof(__be32), | ||
1227 | [CTA_EXPECT_ID-1] = sizeof(__be32) | ||
1228 | }; | ||
1229 | |||
1230 | static int | ||
1231 | ctnetlink_get_expect(struct sock *ctnl, struct sk_buff *skb, | ||
1232 | struct nlmsghdr *nlh, struct nfattr *cda[], int *errp) | ||
1233 | { | ||
1234 | struct ip_conntrack_tuple tuple; | ||
1235 | struct ip_conntrack_expect *exp; | ||
1236 | struct sk_buff *skb2; | ||
1237 | int err = 0; | ||
1238 | |||
1239 | if (nfattr_bad_size(cda, CTA_EXPECT_MAX, cta_min_exp)) | ||
1240 | return -EINVAL; | ||
1241 | |||
1242 | if (nlh->nlmsg_flags & NLM_F_DUMP) { | ||
1243 | struct nfgenmsg *msg = NLMSG_DATA(nlh); | ||
1244 | u32 rlen; | ||
1245 | |||
1246 | if (msg->nfgen_family != AF_INET) | ||
1247 | return -EAFNOSUPPORT; | ||
1248 | |||
1249 | if ((*errp = netlink_dump_start(ctnl, skb, nlh, | ||
1250 | ctnetlink_exp_dump_table, | ||
1251 | ctnetlink_done)) != 0) | ||
1252 | return -EINVAL; | ||
1253 | rlen = NLMSG_ALIGN(nlh->nlmsg_len); | ||
1254 | if (rlen > skb->len) | ||
1255 | rlen = skb->len; | ||
1256 | skb_pull(skb, rlen); | ||
1257 | return 0; | ||
1258 | } | ||
1259 | |||
1260 | if (cda[CTA_EXPECT_MASTER-1]) | ||
1261 | err = ctnetlink_parse_tuple(cda, &tuple, CTA_EXPECT_MASTER); | ||
1262 | else | ||
1263 | return -EINVAL; | ||
1264 | |||
1265 | if (err < 0) | ||
1266 | return err; | ||
1267 | |||
1268 | exp = ip_conntrack_expect_find_get(&tuple); | ||
1269 | if (!exp) | ||
1270 | return -ENOENT; | ||
1271 | |||
1272 | if (cda[CTA_EXPECT_ID-1]) { | ||
1273 | __be32 id = *(__be32 *)NFA_DATA(cda[CTA_EXPECT_ID-1]); | ||
1274 | if (exp->id != ntohl(id)) { | ||
1275 | ip_conntrack_expect_put(exp); | ||
1276 | return -ENOENT; | ||
1277 | } | ||
1278 | } | ||
1279 | |||
1280 | err = -ENOMEM; | ||
1281 | skb2 = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); | ||
1282 | if (!skb2) | ||
1283 | goto out; | ||
1284 | |||
1285 | err = ctnetlink_exp_fill_info(skb2, NETLINK_CB(skb).pid, | ||
1286 | nlh->nlmsg_seq, IPCTNL_MSG_EXP_NEW, | ||
1287 | 1, exp); | ||
1288 | if (err <= 0) | ||
1289 | goto free; | ||
1290 | |||
1291 | ip_conntrack_expect_put(exp); | ||
1292 | |||
1293 | return netlink_unicast(ctnl, skb2, NETLINK_CB(skb).pid, MSG_DONTWAIT); | ||
1294 | |||
1295 | free: | ||
1296 | kfree_skb(skb2); | ||
1297 | out: | ||
1298 | ip_conntrack_expect_put(exp); | ||
1299 | return err; | ||
1300 | } | ||
1301 | |||
1302 | static int | ||
1303 | ctnetlink_del_expect(struct sock *ctnl, struct sk_buff *skb, | ||
1304 | struct nlmsghdr *nlh, struct nfattr *cda[], int *errp) | ||
1305 | { | ||
1306 | struct ip_conntrack_expect *exp, *tmp; | ||
1307 | struct ip_conntrack_tuple tuple; | ||
1308 | struct ip_conntrack_helper *h; | ||
1309 | int err; | ||
1310 | |||
1311 | if (nfattr_bad_size(cda, CTA_EXPECT_MAX, cta_min_exp)) | ||
1312 | return -EINVAL; | ||
1313 | |||
1314 | if (cda[CTA_EXPECT_TUPLE-1]) { | ||
1315 | /* delete a single expect by tuple */ | ||
1316 | err = ctnetlink_parse_tuple(cda, &tuple, CTA_EXPECT_TUPLE); | ||
1317 | if (err < 0) | ||
1318 | return err; | ||
1319 | |||
1320 | /* bump usage count to 2 */ | ||
1321 | exp = ip_conntrack_expect_find_get(&tuple); | ||
1322 | if (!exp) | ||
1323 | return -ENOENT; | ||
1324 | |||
1325 | if (cda[CTA_EXPECT_ID-1]) { | ||
1326 | __be32 id = | ||
1327 | *(__be32 *)NFA_DATA(cda[CTA_EXPECT_ID-1]); | ||
1328 | if (exp->id != ntohl(id)) { | ||
1329 | ip_conntrack_expect_put(exp); | ||
1330 | return -ENOENT; | ||
1331 | } | ||
1332 | } | ||
1333 | |||
1334 | /* after list removal, usage count == 1 */ | ||
1335 | ip_conntrack_unexpect_related(exp); | ||
1336 | /* have to put what we 'get' above. | ||
1337 | * after this line usage count == 0 */ | ||
1338 | ip_conntrack_expect_put(exp); | ||
1339 | } else if (cda[CTA_EXPECT_HELP_NAME-1]) { | ||
1340 | char *name = NFA_DATA(cda[CTA_EXPECT_HELP_NAME-1]); | ||
1341 | |||
1342 | /* delete all expectations for this helper */ | ||
1343 | write_lock_bh(&ip_conntrack_lock); | ||
1344 | h = __ip_conntrack_helper_find_byname(name); | ||
1345 | if (!h) { | ||
1346 | write_unlock_bh(&ip_conntrack_lock); | ||
1347 | return -EINVAL; | ||
1348 | } | ||
1349 | list_for_each_entry_safe(exp, tmp, &ip_conntrack_expect_list, | ||
1350 | list) { | ||
1351 | if (exp->master->helper == h | ||
1352 | && del_timer(&exp->timeout)) { | ||
1353 | ip_ct_unlink_expect(exp); | ||
1354 | ip_conntrack_expect_put(exp); | ||
1355 | } | ||
1356 | } | ||
1357 | write_unlock_bh(&ip_conntrack_lock); | ||
1358 | } else { | ||
1359 | /* This basically means we have to flush everything*/ | ||
1360 | write_lock_bh(&ip_conntrack_lock); | ||
1361 | list_for_each_entry_safe(exp, tmp, &ip_conntrack_expect_list, | ||
1362 | list) { | ||
1363 | if (del_timer(&exp->timeout)) { | ||
1364 | ip_ct_unlink_expect(exp); | ||
1365 | ip_conntrack_expect_put(exp); | ||
1366 | } | ||
1367 | } | ||
1368 | write_unlock_bh(&ip_conntrack_lock); | ||
1369 | } | ||
1370 | |||
1371 | return 0; | ||
1372 | } | ||
1373 | static int | ||
1374 | ctnetlink_change_expect(struct ip_conntrack_expect *x, struct nfattr *cda[]) | ||
1375 | { | ||
1376 | return -EOPNOTSUPP; | ||
1377 | } | ||
1378 | |||
1379 | static int | ||
1380 | ctnetlink_create_expect(struct nfattr *cda[]) | ||
1381 | { | ||
1382 | struct ip_conntrack_tuple tuple, mask, master_tuple; | ||
1383 | struct ip_conntrack_tuple_hash *h = NULL; | ||
1384 | struct ip_conntrack_expect *exp; | ||
1385 | struct ip_conntrack *ct; | ||
1386 | int err = 0; | ||
1387 | |||
1388 | /* caller guarantees that those three CTA_EXPECT_* exist */ | ||
1389 | err = ctnetlink_parse_tuple(cda, &tuple, CTA_EXPECT_TUPLE); | ||
1390 | if (err < 0) | ||
1391 | return err; | ||
1392 | err = ctnetlink_parse_tuple(cda, &mask, CTA_EXPECT_MASK); | ||
1393 | if (err < 0) | ||
1394 | return err; | ||
1395 | err = ctnetlink_parse_tuple(cda, &master_tuple, CTA_EXPECT_MASTER); | ||
1396 | if (err < 0) | ||
1397 | return err; | ||
1398 | |||
1399 | /* Look for master conntrack of this expectation */ | ||
1400 | h = ip_conntrack_find_get(&master_tuple, NULL); | ||
1401 | if (!h) | ||
1402 | return -ENOENT; | ||
1403 | ct = tuplehash_to_ctrack(h); | ||
1404 | |||
1405 | if (!ct->helper) { | ||
1406 | /* such conntrack hasn't got any helper, abort */ | ||
1407 | err = -EINVAL; | ||
1408 | goto out; | ||
1409 | } | ||
1410 | |||
1411 | exp = ip_conntrack_expect_alloc(ct); | ||
1412 | if (!exp) { | ||
1413 | err = -ENOMEM; | ||
1414 | goto out; | ||
1415 | } | ||
1416 | |||
1417 | exp->expectfn = NULL; | ||
1418 | exp->flags = 0; | ||
1419 | exp->master = ct; | ||
1420 | memcpy(&exp->tuple, &tuple, sizeof(struct ip_conntrack_tuple)); | ||
1421 | memcpy(&exp->mask, &mask, sizeof(struct ip_conntrack_tuple)); | ||
1422 | |||
1423 | err = ip_conntrack_expect_related(exp); | ||
1424 | ip_conntrack_expect_put(exp); | ||
1425 | |||
1426 | out: | ||
1427 | ip_conntrack_put(tuplehash_to_ctrack(h)); | ||
1428 | return err; | ||
1429 | } | ||
1430 | |||
1431 | static int | ||
1432 | ctnetlink_new_expect(struct sock *ctnl, struct sk_buff *skb, | ||
1433 | struct nlmsghdr *nlh, struct nfattr *cda[], int *errp) | ||
1434 | { | ||
1435 | struct ip_conntrack_tuple tuple; | ||
1436 | struct ip_conntrack_expect *exp; | ||
1437 | int err = 0; | ||
1438 | |||
1439 | if (nfattr_bad_size(cda, CTA_EXPECT_MAX, cta_min_exp)) | ||
1440 | return -EINVAL; | ||
1441 | |||
1442 | if (!cda[CTA_EXPECT_TUPLE-1] | ||
1443 | || !cda[CTA_EXPECT_MASK-1] | ||
1444 | || !cda[CTA_EXPECT_MASTER-1]) | ||
1445 | return -EINVAL; | ||
1446 | |||
1447 | err = ctnetlink_parse_tuple(cda, &tuple, CTA_EXPECT_TUPLE); | ||
1448 | if (err < 0) | ||
1449 | return err; | ||
1450 | |||
1451 | write_lock_bh(&ip_conntrack_lock); | ||
1452 | exp = __ip_conntrack_expect_find(&tuple); | ||
1453 | |||
1454 | if (!exp) { | ||
1455 | write_unlock_bh(&ip_conntrack_lock); | ||
1456 | err = -ENOENT; | ||
1457 | if (nlh->nlmsg_flags & NLM_F_CREATE) | ||
1458 | err = ctnetlink_create_expect(cda); | ||
1459 | return err; | ||
1460 | } | ||
1461 | |||
1462 | err = -EEXIST; | ||
1463 | if (!(nlh->nlmsg_flags & NLM_F_EXCL)) | ||
1464 | err = ctnetlink_change_expect(exp, cda); | ||
1465 | write_unlock_bh(&ip_conntrack_lock); | ||
1466 | |||
1467 | return err; | ||
1468 | } | ||
1469 | |||
1470 | #ifdef CONFIG_IP_NF_CONNTRACK_EVENTS | ||
1471 | static struct notifier_block ctnl_notifier = { | ||
1472 | .notifier_call = ctnetlink_conntrack_event, | ||
1473 | }; | ||
1474 | |||
1475 | static struct notifier_block ctnl_notifier_exp = { | ||
1476 | .notifier_call = ctnetlink_expect_event, | ||
1477 | }; | ||
1478 | #endif | ||
1479 | |||
1480 | static struct nfnl_callback ctnl_cb[IPCTNL_MSG_MAX] = { | ||
1481 | [IPCTNL_MSG_CT_NEW] = { .call = ctnetlink_new_conntrack, | ||
1482 | .attr_count = CTA_MAX, }, | ||
1483 | [IPCTNL_MSG_CT_GET] = { .call = ctnetlink_get_conntrack, | ||
1484 | .attr_count = CTA_MAX, }, | ||
1485 | [IPCTNL_MSG_CT_DELETE] = { .call = ctnetlink_del_conntrack, | ||
1486 | .attr_count = CTA_MAX, }, | ||
1487 | [IPCTNL_MSG_CT_GET_CTRZERO] = { .call = ctnetlink_get_conntrack, | ||
1488 | .attr_count = CTA_MAX, }, | ||
1489 | }; | ||
1490 | |||
1491 | static struct nfnl_callback ctnl_exp_cb[IPCTNL_MSG_EXP_MAX] = { | ||
1492 | [IPCTNL_MSG_EXP_GET] = { .call = ctnetlink_get_expect, | ||
1493 | .attr_count = CTA_EXPECT_MAX, }, | ||
1494 | [IPCTNL_MSG_EXP_NEW] = { .call = ctnetlink_new_expect, | ||
1495 | .attr_count = CTA_EXPECT_MAX, }, | ||
1496 | [IPCTNL_MSG_EXP_DELETE] = { .call = ctnetlink_del_expect, | ||
1497 | .attr_count = CTA_EXPECT_MAX, }, | ||
1498 | }; | ||
1499 | |||
1500 | static struct nfnetlink_subsystem ctnl_subsys = { | ||
1501 | .name = "conntrack", | ||
1502 | .subsys_id = NFNL_SUBSYS_CTNETLINK, | ||
1503 | .cb_count = IPCTNL_MSG_MAX, | ||
1504 | .cb = ctnl_cb, | ||
1505 | }; | ||
1506 | |||
1507 | static struct nfnetlink_subsystem ctnl_exp_subsys = { | ||
1508 | .name = "conntrack_expect", | ||
1509 | .subsys_id = NFNL_SUBSYS_CTNETLINK_EXP, | ||
1510 | .cb_count = IPCTNL_MSG_EXP_MAX, | ||
1511 | .cb = ctnl_exp_cb, | ||
1512 | }; | ||
1513 | |||
1514 | MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_CTNETLINK); | ||
1515 | MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_CTNETLINK_EXP); | ||
1516 | |||
1517 | static int __init ctnetlink_init(void) | ||
1518 | { | ||
1519 | int ret; | ||
1520 | |||
1521 | printk("ctnetlink v%s: registering with nfnetlink.\n", version); | ||
1522 | ret = nfnetlink_subsys_register(&ctnl_subsys); | ||
1523 | if (ret < 0) { | ||
1524 | printk("ctnetlink_init: cannot register with nfnetlink.\n"); | ||
1525 | goto err_out; | ||
1526 | } | ||
1527 | |||
1528 | ret = nfnetlink_subsys_register(&ctnl_exp_subsys); | ||
1529 | if (ret < 0) { | ||
1530 | printk("ctnetlink_init: cannot register exp with nfnetlink.\n"); | ||
1531 | goto err_unreg_subsys; | ||
1532 | } | ||
1533 | |||
1534 | #ifdef CONFIG_IP_NF_CONNTRACK_EVENTS | ||
1535 | ret = ip_conntrack_register_notifier(&ctnl_notifier); | ||
1536 | if (ret < 0) { | ||
1537 | printk("ctnetlink_init: cannot register notifier.\n"); | ||
1538 | goto err_unreg_exp_subsys; | ||
1539 | } | ||
1540 | |||
1541 | ret = ip_conntrack_expect_register_notifier(&ctnl_notifier_exp); | ||
1542 | if (ret < 0) { | ||
1543 | printk("ctnetlink_init: cannot expect register notifier.\n"); | ||
1544 | goto err_unreg_notifier; | ||
1545 | } | ||
1546 | #endif | ||
1547 | |||
1548 | return 0; | ||
1549 | |||
1550 | #ifdef CONFIG_IP_NF_CONNTRACK_EVENTS | ||
1551 | err_unreg_notifier: | ||
1552 | ip_conntrack_unregister_notifier(&ctnl_notifier); | ||
1553 | err_unreg_exp_subsys: | ||
1554 | nfnetlink_subsys_unregister(&ctnl_exp_subsys); | ||
1555 | #endif | ||
1556 | err_unreg_subsys: | ||
1557 | nfnetlink_subsys_unregister(&ctnl_subsys); | ||
1558 | err_out: | ||
1559 | return ret; | ||
1560 | } | ||
1561 | |||
1562 | static void __exit ctnetlink_exit(void) | ||
1563 | { | ||
1564 | printk("ctnetlink: unregistering from nfnetlink.\n"); | ||
1565 | |||
1566 | #ifdef CONFIG_IP_NF_CONNTRACK_EVENTS | ||
1567 | ip_conntrack_expect_unregister_notifier(&ctnl_notifier_exp); | ||
1568 | ip_conntrack_unregister_notifier(&ctnl_notifier); | ||
1569 | #endif | ||
1570 | |||
1571 | nfnetlink_subsys_unregister(&ctnl_exp_subsys); | ||
1572 | nfnetlink_subsys_unregister(&ctnl_subsys); | ||
1573 | return; | ||
1574 | } | ||
1575 | |||
1576 | module_init(ctnetlink_init); | ||
1577 | module_exit(ctnetlink_exit); | ||
diff --git a/net/ipv4/netfilter/ip_conntrack_proto_generic.c b/net/ipv4/netfilter/ip_conntrack_proto_generic.c deleted file mode 100644 index 88af82e98658..000000000000 --- a/net/ipv4/netfilter/ip_conntrack_proto_generic.c +++ /dev/null | |||
@@ -1,74 +0,0 @@ | |||
1 | /* (C) 1999-2001 Paul `Rusty' Russell | ||
2 | * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | */ | ||
8 | |||
9 | #include <linux/types.h> | ||
10 | #include <linux/timer.h> | ||
11 | #include <linux/netfilter.h> | ||
12 | #include <linux/netfilter_ipv4/ip_conntrack_protocol.h> | ||
13 | |||
14 | unsigned int ip_ct_generic_timeout __read_mostly = 600*HZ; | ||
15 | |||
16 | static int generic_pkt_to_tuple(const struct sk_buff *skb, | ||
17 | unsigned int dataoff, | ||
18 | struct ip_conntrack_tuple *tuple) | ||
19 | { | ||
20 | tuple->src.u.all = 0; | ||
21 | tuple->dst.u.all = 0; | ||
22 | |||
23 | return 1; | ||
24 | } | ||
25 | |||
26 | static int generic_invert_tuple(struct ip_conntrack_tuple *tuple, | ||
27 | const struct ip_conntrack_tuple *orig) | ||
28 | { | ||
29 | tuple->src.u.all = 0; | ||
30 | tuple->dst.u.all = 0; | ||
31 | |||
32 | return 1; | ||
33 | } | ||
34 | |||
35 | /* Print out the per-protocol part of the tuple. */ | ||
36 | static int generic_print_tuple(struct seq_file *s, | ||
37 | const struct ip_conntrack_tuple *tuple) | ||
38 | { | ||
39 | return 0; | ||
40 | } | ||
41 | |||
42 | /* Print out the private part of the conntrack. */ | ||
43 | static int generic_print_conntrack(struct seq_file *s, | ||
44 | const struct ip_conntrack *state) | ||
45 | { | ||
46 | return 0; | ||
47 | } | ||
48 | |||
49 | /* Returns verdict for packet, or -1 for invalid. */ | ||
50 | static int packet(struct ip_conntrack *conntrack, | ||
51 | const struct sk_buff *skb, | ||
52 | enum ip_conntrack_info ctinfo) | ||
53 | { | ||
54 | ip_ct_refresh_acct(conntrack, ctinfo, skb, ip_ct_generic_timeout); | ||
55 | return NF_ACCEPT; | ||
56 | } | ||
57 | |||
58 | /* Called when a new connection for this protocol found. */ | ||
59 | static int new(struct ip_conntrack *conntrack, const struct sk_buff *skb) | ||
60 | { | ||
61 | return 1; | ||
62 | } | ||
63 | |||
64 | struct ip_conntrack_protocol ip_conntrack_generic_protocol = | ||
65 | { | ||
66 | .proto = 0, | ||
67 | .name = "unknown", | ||
68 | .pkt_to_tuple = generic_pkt_to_tuple, | ||
69 | .invert_tuple = generic_invert_tuple, | ||
70 | .print_tuple = generic_print_tuple, | ||
71 | .print_conntrack = generic_print_conntrack, | ||
72 | .packet = packet, | ||
73 | .new = new, | ||
74 | }; | ||
diff --git a/net/ipv4/netfilter/ip_conntrack_proto_gre.c b/net/ipv4/netfilter/ip_conntrack_proto_gre.c deleted file mode 100644 index ac1c49ef36a9..000000000000 --- a/net/ipv4/netfilter/ip_conntrack_proto_gre.c +++ /dev/null | |||
@@ -1,328 +0,0 @@ | |||
1 | /* | ||
2 | * ip_conntrack_proto_gre.c - Version 3.0 | ||
3 | * | ||
4 | * Connection tracking protocol helper module for GRE. | ||
5 | * | ||
6 | * GRE is a generic encapsulation protocol, which is generally not very | ||
7 | * suited for NAT, as it has no protocol-specific part as port numbers. | ||
8 | * | ||
9 | * It has an optional key field, which may help us distinguishing two | ||
10 | * connections between the same two hosts. | ||
11 | * | ||
12 | * GRE is defined in RFC 1701 and RFC 1702, as well as RFC 2784 | ||
13 | * | ||
14 | * PPTP is built on top of a modified version of GRE, and has a mandatory | ||
15 | * field called "CallID", which serves us for the same purpose as the key | ||
16 | * field in plain GRE. | ||
17 | * | ||
18 | * Documentation about PPTP can be found in RFC 2637 | ||
19 | * | ||
20 | * (C) 2000-2005 by Harald Welte <laforge@gnumonks.org> | ||
21 | * | ||
22 | * Development of this code funded by Astaro AG (http://www.astaro.com/) | ||
23 | * | ||
24 | */ | ||
25 | |||
26 | #include <linux/module.h> | ||
27 | #include <linux/types.h> | ||
28 | #include <linux/timer.h> | ||
29 | #include <linux/netfilter.h> | ||
30 | #include <linux/ip.h> | ||
31 | #include <linux/in.h> | ||
32 | #include <linux/list.h> | ||
33 | #include <linux/seq_file.h> | ||
34 | #include <linux/interrupt.h> | ||
35 | |||
36 | static DEFINE_RWLOCK(ip_ct_gre_lock); | ||
37 | |||
38 | #include <linux/netfilter_ipv4/ip_conntrack_protocol.h> | ||
39 | #include <linux/netfilter_ipv4/ip_conntrack_helper.h> | ||
40 | #include <linux/netfilter_ipv4/ip_conntrack_core.h> | ||
41 | |||
42 | #include <linux/netfilter_ipv4/ip_conntrack_proto_gre.h> | ||
43 | #include <linux/netfilter_ipv4/ip_conntrack_pptp.h> | ||
44 | |||
45 | MODULE_LICENSE("GPL"); | ||
46 | MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>"); | ||
47 | MODULE_DESCRIPTION("netfilter connection tracking protocol helper for GRE"); | ||
48 | |||
49 | /* shamelessly stolen from ip_conntrack_proto_udp.c */ | ||
50 | #define GRE_TIMEOUT (30*HZ) | ||
51 | #define GRE_STREAM_TIMEOUT (180*HZ) | ||
52 | |||
53 | #if 0 | ||
54 | #define DEBUGP(format, args...) printk(KERN_DEBUG "%s:%s: " format, __FILE__, __FUNCTION__, ## args) | ||
55 | #define DUMP_TUPLE_GRE(x) printk("%u.%u.%u.%u:0x%x -> %u.%u.%u.%u:0x%x\n", \ | ||
56 | NIPQUAD((x)->src.ip), ntohs((x)->src.u.gre.key), \ | ||
57 | NIPQUAD((x)->dst.ip), ntohs((x)->dst.u.gre.key)) | ||
58 | #else | ||
59 | #define DEBUGP(x, args...) | ||
60 | #define DUMP_TUPLE_GRE(x) | ||
61 | #endif | ||
62 | |||
63 | /* GRE KEYMAP HANDLING FUNCTIONS */ | ||
64 | static LIST_HEAD(gre_keymap_list); | ||
65 | |||
66 | static inline int gre_key_cmpfn(const struct ip_ct_gre_keymap *km, | ||
67 | const struct ip_conntrack_tuple *t) | ||
68 | { | ||
69 | return ((km->tuple.src.ip == t->src.ip) && | ||
70 | (km->tuple.dst.ip == t->dst.ip) && | ||
71 | (km->tuple.dst.protonum == t->dst.protonum) && | ||
72 | (km->tuple.dst.u.all == t->dst.u.all)); | ||
73 | } | ||
74 | |||
75 | /* look up the source key for a given tuple */ | ||
76 | static __be16 gre_keymap_lookup(struct ip_conntrack_tuple *t) | ||
77 | { | ||
78 | struct ip_ct_gre_keymap *km; | ||
79 | __be16 key = 0; | ||
80 | |||
81 | read_lock_bh(&ip_ct_gre_lock); | ||
82 | list_for_each_entry(km, &gre_keymap_list, list) { | ||
83 | if (gre_key_cmpfn(km, t)) { | ||
84 | key = km->tuple.src.u.gre.key; | ||
85 | break; | ||
86 | } | ||
87 | } | ||
88 | read_unlock_bh(&ip_ct_gre_lock); | ||
89 | |||
90 | DEBUGP("lookup src key 0x%x up key for ", key); | ||
91 | DUMP_TUPLE_GRE(t); | ||
92 | |||
93 | return key; | ||
94 | } | ||
95 | |||
96 | /* add a single keymap entry, associate with specified master ct */ | ||
97 | int | ||
98 | ip_ct_gre_keymap_add(struct ip_conntrack *ct, | ||
99 | struct ip_conntrack_tuple *t, int reply) | ||
100 | { | ||
101 | struct ip_ct_gre_keymap **exist_km, *km; | ||
102 | |||
103 | if (!ct->helper || strcmp(ct->helper->name, "pptp")) { | ||
104 | DEBUGP("refusing to add GRE keymap to non-pptp session\n"); | ||
105 | return -1; | ||
106 | } | ||
107 | |||
108 | if (!reply) | ||
109 | exist_km = &ct->help.ct_pptp_info.keymap_orig; | ||
110 | else | ||
111 | exist_km = &ct->help.ct_pptp_info.keymap_reply; | ||
112 | |||
113 | if (*exist_km) { | ||
114 | /* check whether it's a retransmission */ | ||
115 | list_for_each_entry(km, &gre_keymap_list, list) { | ||
116 | if (gre_key_cmpfn(km, t) && km == *exist_km) | ||
117 | return 0; | ||
118 | } | ||
119 | DEBUGP("trying to override keymap_%s for ct %p\n", | ||
120 | reply? "reply":"orig", ct); | ||
121 | return -EEXIST; | ||
122 | } | ||
123 | |||
124 | km = kmalloc(sizeof(*km), GFP_ATOMIC); | ||
125 | if (!km) | ||
126 | return -ENOMEM; | ||
127 | |||
128 | memcpy(&km->tuple, t, sizeof(*t)); | ||
129 | *exist_km = km; | ||
130 | |||
131 | DEBUGP("adding new entry %p: ", km); | ||
132 | DUMP_TUPLE_GRE(&km->tuple); | ||
133 | |||
134 | write_lock_bh(&ip_ct_gre_lock); | ||
135 | list_add_tail(&km->list, &gre_keymap_list); | ||
136 | write_unlock_bh(&ip_ct_gre_lock); | ||
137 | |||
138 | return 0; | ||
139 | } | ||
140 | |||
141 | /* destroy the keymap entries associated with specified master ct */ | ||
142 | void ip_ct_gre_keymap_destroy(struct ip_conntrack *ct) | ||
143 | { | ||
144 | DEBUGP("entering for ct %p\n", ct); | ||
145 | |||
146 | if (!ct->helper || strcmp(ct->helper->name, "pptp")) { | ||
147 | DEBUGP("refusing to destroy GRE keymap to non-pptp session\n"); | ||
148 | return; | ||
149 | } | ||
150 | |||
151 | write_lock_bh(&ip_ct_gre_lock); | ||
152 | if (ct->help.ct_pptp_info.keymap_orig) { | ||
153 | DEBUGP("removing %p from list\n", | ||
154 | ct->help.ct_pptp_info.keymap_orig); | ||
155 | list_del(&ct->help.ct_pptp_info.keymap_orig->list); | ||
156 | kfree(ct->help.ct_pptp_info.keymap_orig); | ||
157 | ct->help.ct_pptp_info.keymap_orig = NULL; | ||
158 | } | ||
159 | if (ct->help.ct_pptp_info.keymap_reply) { | ||
160 | DEBUGP("removing %p from list\n", | ||
161 | ct->help.ct_pptp_info.keymap_reply); | ||
162 | list_del(&ct->help.ct_pptp_info.keymap_reply->list); | ||
163 | kfree(ct->help.ct_pptp_info.keymap_reply); | ||
164 | ct->help.ct_pptp_info.keymap_reply = NULL; | ||
165 | } | ||
166 | write_unlock_bh(&ip_ct_gre_lock); | ||
167 | } | ||
168 | |||
169 | |||
170 | /* PUBLIC CONNTRACK PROTO HELPER FUNCTIONS */ | ||
171 | |||
172 | /* invert gre part of tuple */ | ||
173 | static int gre_invert_tuple(struct ip_conntrack_tuple *tuple, | ||
174 | const struct ip_conntrack_tuple *orig) | ||
175 | { | ||
176 | tuple->dst.u.gre.key = orig->src.u.gre.key; | ||
177 | tuple->src.u.gre.key = orig->dst.u.gre.key; | ||
178 | |||
179 | return 1; | ||
180 | } | ||
181 | |||
182 | /* gre hdr info to tuple */ | ||
183 | static int gre_pkt_to_tuple(const struct sk_buff *skb, | ||
184 | unsigned int dataoff, | ||
185 | struct ip_conntrack_tuple *tuple) | ||
186 | { | ||
187 | struct gre_hdr_pptp _pgrehdr, *pgrehdr; | ||
188 | __be16 srckey; | ||
189 | struct gre_hdr _grehdr, *grehdr; | ||
190 | |||
191 | /* first only delinearize old RFC1701 GRE header */ | ||
192 | grehdr = skb_header_pointer(skb, dataoff, sizeof(_grehdr), &_grehdr); | ||
193 | if (!grehdr || grehdr->version != GRE_VERSION_PPTP) { | ||
194 | /* try to behave like "ip_conntrack_proto_generic" */ | ||
195 | tuple->src.u.all = 0; | ||
196 | tuple->dst.u.all = 0; | ||
197 | return 1; | ||
198 | } | ||
199 | |||
200 | /* PPTP header is variable length, only need up to the call_id field */ | ||
201 | pgrehdr = skb_header_pointer(skb, dataoff, 8, &_pgrehdr); | ||
202 | if (!pgrehdr) | ||
203 | return 1; | ||
204 | |||
205 | if (ntohs(grehdr->protocol) != GRE_PROTOCOL_PPTP) { | ||
206 | DEBUGP("GRE_VERSION_PPTP but unknown proto\n"); | ||
207 | return 0; | ||
208 | } | ||
209 | |||
210 | tuple->dst.u.gre.key = pgrehdr->call_id; | ||
211 | srckey = gre_keymap_lookup(tuple); | ||
212 | tuple->src.u.gre.key = srckey; | ||
213 | |||
214 | return 1; | ||
215 | } | ||
216 | |||
217 | /* print gre part of tuple */ | ||
218 | static int gre_print_tuple(struct seq_file *s, | ||
219 | const struct ip_conntrack_tuple *tuple) | ||
220 | { | ||
221 | return seq_printf(s, "srckey=0x%x dstkey=0x%x ", | ||
222 | ntohs(tuple->src.u.gre.key), | ||
223 | ntohs(tuple->dst.u.gre.key)); | ||
224 | } | ||
225 | |||
226 | /* print private data for conntrack */ | ||
227 | static int gre_print_conntrack(struct seq_file *s, | ||
228 | const struct ip_conntrack *ct) | ||
229 | { | ||
230 | return seq_printf(s, "timeout=%u, stream_timeout=%u ", | ||
231 | (ct->proto.gre.timeout / HZ), | ||
232 | (ct->proto.gre.stream_timeout / HZ)); | ||
233 | } | ||
234 | |||
235 | /* Returns verdict for packet, and may modify conntrack */ | ||
236 | static int gre_packet(struct ip_conntrack *ct, | ||
237 | const struct sk_buff *skb, | ||
238 | enum ip_conntrack_info conntrackinfo) | ||
239 | { | ||
240 | /* If we've seen traffic both ways, this is a GRE connection. | ||
241 | * Extend timeout. */ | ||
242 | if (ct->status & IPS_SEEN_REPLY) { | ||
243 | ip_ct_refresh_acct(ct, conntrackinfo, skb, | ||
244 | ct->proto.gre.stream_timeout); | ||
245 | /* Also, more likely to be important, and not a probe. */ | ||
246 | set_bit(IPS_ASSURED_BIT, &ct->status); | ||
247 | ip_conntrack_event_cache(IPCT_STATUS, skb); | ||
248 | } else | ||
249 | ip_ct_refresh_acct(ct, conntrackinfo, skb, | ||
250 | ct->proto.gre.timeout); | ||
251 | |||
252 | return NF_ACCEPT; | ||
253 | } | ||
254 | |||
255 | /* Called when a new connection for this protocol found. */ | ||
256 | static int gre_new(struct ip_conntrack *ct, | ||
257 | const struct sk_buff *skb) | ||
258 | { | ||
259 | DEBUGP(": "); | ||
260 | DUMP_TUPLE_GRE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); | ||
261 | |||
262 | /* initialize to sane value. Ideally a conntrack helper | ||
263 | * (e.g. in case of pptp) is increasing them */ | ||
264 | ct->proto.gre.stream_timeout = GRE_STREAM_TIMEOUT; | ||
265 | ct->proto.gre.timeout = GRE_TIMEOUT; | ||
266 | |||
267 | return 1; | ||
268 | } | ||
269 | |||
270 | /* Called when a conntrack entry has already been removed from the hashes | ||
271 | * and is about to be deleted from memory */ | ||
272 | static void gre_destroy(struct ip_conntrack *ct) | ||
273 | { | ||
274 | struct ip_conntrack *master = ct->master; | ||
275 | DEBUGP(" entering\n"); | ||
276 | |||
277 | if (!master) | ||
278 | DEBUGP("no master !?!\n"); | ||
279 | else | ||
280 | ip_ct_gre_keymap_destroy(master); | ||
281 | } | ||
282 | |||
283 | /* protocol helper struct */ | ||
284 | static struct ip_conntrack_protocol gre = { | ||
285 | .proto = IPPROTO_GRE, | ||
286 | .name = "gre", | ||
287 | .pkt_to_tuple = gre_pkt_to_tuple, | ||
288 | .invert_tuple = gre_invert_tuple, | ||
289 | .print_tuple = gre_print_tuple, | ||
290 | .print_conntrack = gre_print_conntrack, | ||
291 | .packet = gre_packet, | ||
292 | .new = gre_new, | ||
293 | .destroy = gre_destroy, | ||
294 | .me = THIS_MODULE, | ||
295 | #if defined(CONFIG_IP_NF_CONNTRACK_NETLINK) || \ | ||
296 | defined(CONFIG_IP_NF_CONNTRACK_NETLINK_MODULE) | ||
297 | .tuple_to_nfattr = ip_ct_port_tuple_to_nfattr, | ||
298 | .nfattr_to_tuple = ip_ct_port_nfattr_to_tuple, | ||
299 | #endif | ||
300 | }; | ||
301 | |||
302 | /* ip_conntrack_proto_gre initialization */ | ||
303 | int __init ip_ct_proto_gre_init(void) | ||
304 | { | ||
305 | return ip_conntrack_protocol_register(&gre); | ||
306 | } | ||
307 | |||
308 | /* This cannot be __exit, as it is invoked from ip_conntrack_helper_pptp.c's | ||
309 | * init() code on errors. | ||
310 | */ | ||
311 | void ip_ct_proto_gre_fini(void) | ||
312 | { | ||
313 | struct list_head *pos, *n; | ||
314 | |||
315 | /* delete all keymap entries */ | ||
316 | write_lock_bh(&ip_ct_gre_lock); | ||
317 | list_for_each_safe(pos, n, &gre_keymap_list) { | ||
318 | DEBUGP("deleting keymap %p at module unload time\n", pos); | ||
319 | list_del(pos); | ||
320 | kfree(pos); | ||
321 | } | ||
322 | write_unlock_bh(&ip_ct_gre_lock); | ||
323 | |||
324 | ip_conntrack_protocol_unregister(&gre); | ||
325 | } | ||
326 | |||
327 | EXPORT_SYMBOL(ip_ct_gre_keymap_add); | ||
328 | EXPORT_SYMBOL(ip_ct_gre_keymap_destroy); | ||
diff --git a/net/ipv4/netfilter/ip_conntrack_proto_icmp.c b/net/ipv4/netfilter/ip_conntrack_proto_icmp.c deleted file mode 100644 index e253f3ee52d0..000000000000 --- a/net/ipv4/netfilter/ip_conntrack_proto_icmp.c +++ /dev/null | |||
@@ -1,315 +0,0 @@ | |||
1 | /* (C) 1999-2001 Paul `Rusty' Russell | ||
2 | * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | */ | ||
8 | |||
9 | #include <linux/types.h> | ||
10 | #include <linux/timer.h> | ||
11 | #include <linux/netfilter.h> | ||
12 | #include <linux/in.h> | ||
13 | #include <linux/icmp.h> | ||
14 | #include <linux/seq_file.h> | ||
15 | #include <linux/skbuff.h> | ||
16 | #include <net/ip.h> | ||
17 | #include <net/checksum.h> | ||
18 | #include <linux/netfilter_ipv4.h> | ||
19 | #include <linux/netfilter_ipv4/ip_conntrack.h> | ||
20 | #include <linux/netfilter_ipv4/ip_conntrack_core.h> | ||
21 | #include <linux/netfilter_ipv4/ip_conntrack_protocol.h> | ||
22 | |||
23 | unsigned int ip_ct_icmp_timeout __read_mostly = 30*HZ; | ||
24 | |||
25 | #if 0 | ||
26 | #define DEBUGP printk | ||
27 | #else | ||
28 | #define DEBUGP(format, args...) | ||
29 | #endif | ||
30 | |||
31 | static int icmp_pkt_to_tuple(const struct sk_buff *skb, | ||
32 | unsigned int dataoff, | ||
33 | struct ip_conntrack_tuple *tuple) | ||
34 | { | ||
35 | struct icmphdr _hdr, *hp; | ||
36 | |||
37 | hp = skb_header_pointer(skb, dataoff, sizeof(_hdr), &_hdr); | ||
38 | if (hp == NULL) | ||
39 | return 0; | ||
40 | |||
41 | tuple->dst.u.icmp.type = hp->type; | ||
42 | tuple->src.u.icmp.id = hp->un.echo.id; | ||
43 | tuple->dst.u.icmp.code = hp->code; | ||
44 | |||
45 | return 1; | ||
46 | } | ||
47 | |||
48 | /* Add 1; spaces filled with 0. */ | ||
49 | static const u_int8_t invmap[] = { | ||
50 | [ICMP_ECHO] = ICMP_ECHOREPLY + 1, | ||
51 | [ICMP_ECHOREPLY] = ICMP_ECHO + 1, | ||
52 | [ICMP_TIMESTAMP] = ICMP_TIMESTAMPREPLY + 1, | ||
53 | [ICMP_TIMESTAMPREPLY] = ICMP_TIMESTAMP + 1, | ||
54 | [ICMP_INFO_REQUEST] = ICMP_INFO_REPLY + 1, | ||
55 | [ICMP_INFO_REPLY] = ICMP_INFO_REQUEST + 1, | ||
56 | [ICMP_ADDRESS] = ICMP_ADDRESSREPLY + 1, | ||
57 | [ICMP_ADDRESSREPLY] = ICMP_ADDRESS + 1 | ||
58 | }; | ||
59 | |||
60 | static int icmp_invert_tuple(struct ip_conntrack_tuple *tuple, | ||
61 | const struct ip_conntrack_tuple *orig) | ||
62 | { | ||
63 | if (orig->dst.u.icmp.type >= sizeof(invmap) | ||
64 | || !invmap[orig->dst.u.icmp.type]) | ||
65 | return 0; | ||
66 | |||
67 | tuple->src.u.icmp.id = orig->src.u.icmp.id; | ||
68 | tuple->dst.u.icmp.type = invmap[orig->dst.u.icmp.type] - 1; | ||
69 | tuple->dst.u.icmp.code = orig->dst.u.icmp.code; | ||
70 | return 1; | ||
71 | } | ||
72 | |||
73 | /* Print out the per-protocol part of the tuple. */ | ||
74 | static int icmp_print_tuple(struct seq_file *s, | ||
75 | const struct ip_conntrack_tuple *tuple) | ||
76 | { | ||
77 | return seq_printf(s, "type=%u code=%u id=%u ", | ||
78 | tuple->dst.u.icmp.type, | ||
79 | tuple->dst.u.icmp.code, | ||
80 | ntohs(tuple->src.u.icmp.id)); | ||
81 | } | ||
82 | |||
83 | /* Print out the private part of the conntrack. */ | ||
84 | static int icmp_print_conntrack(struct seq_file *s, | ||
85 | const struct ip_conntrack *conntrack) | ||
86 | { | ||
87 | return 0; | ||
88 | } | ||
89 | |||
90 | /* Returns verdict for packet, or -1 for invalid. */ | ||
91 | static int icmp_packet(struct ip_conntrack *ct, | ||
92 | const struct sk_buff *skb, | ||
93 | enum ip_conntrack_info ctinfo) | ||
94 | { | ||
95 | /* Try to delete connection immediately after all replies: | ||
96 | won't actually vanish as we still have skb, and del_timer | ||
97 | means this will only run once even if count hits zero twice | ||
98 | (theoretically possible with SMP) */ | ||
99 | if (CTINFO2DIR(ctinfo) == IP_CT_DIR_REPLY) { | ||
100 | if (atomic_dec_and_test(&ct->proto.icmp.count) | ||
101 | && del_timer(&ct->timeout)) | ||
102 | ct->timeout.function((unsigned long)ct); | ||
103 | } else { | ||
104 | atomic_inc(&ct->proto.icmp.count); | ||
105 | ip_conntrack_event_cache(IPCT_PROTOINFO_VOLATILE, skb); | ||
106 | ip_ct_refresh_acct(ct, ctinfo, skb, ip_ct_icmp_timeout); | ||
107 | } | ||
108 | |||
109 | return NF_ACCEPT; | ||
110 | } | ||
111 | |||
112 | /* Called when a new connection for this protocol found. */ | ||
113 | static int icmp_new(struct ip_conntrack *conntrack, | ||
114 | const struct sk_buff *skb) | ||
115 | { | ||
116 | static const u_int8_t valid_new[] = { | ||
117 | [ICMP_ECHO] = 1, | ||
118 | [ICMP_TIMESTAMP] = 1, | ||
119 | [ICMP_INFO_REQUEST] = 1, | ||
120 | [ICMP_ADDRESS] = 1 | ||
121 | }; | ||
122 | |||
123 | if (conntrack->tuplehash[0].tuple.dst.u.icmp.type >= sizeof(valid_new) | ||
124 | || !valid_new[conntrack->tuplehash[0].tuple.dst.u.icmp.type]) { | ||
125 | /* Can't create a new ICMP `conn' with this. */ | ||
126 | DEBUGP("icmp: can't create new conn with type %u\n", | ||
127 | conntrack->tuplehash[0].tuple.dst.u.icmp.type); | ||
128 | DUMP_TUPLE(&conntrack->tuplehash[0].tuple); | ||
129 | return 0; | ||
130 | } | ||
131 | atomic_set(&conntrack->proto.icmp.count, 0); | ||
132 | return 1; | ||
133 | } | ||
134 | |||
135 | static int | ||
136 | icmp_error_message(struct sk_buff *skb, | ||
137 | enum ip_conntrack_info *ctinfo, | ||
138 | unsigned int hooknum) | ||
139 | { | ||
140 | struct ip_conntrack_tuple innertuple, origtuple; | ||
141 | struct { | ||
142 | struct icmphdr icmp; | ||
143 | struct iphdr ip; | ||
144 | } _in, *inside; | ||
145 | struct ip_conntrack_protocol *innerproto; | ||
146 | struct ip_conntrack_tuple_hash *h; | ||
147 | int dataoff; | ||
148 | |||
149 | IP_NF_ASSERT(skb->nfct == NULL); | ||
150 | |||
151 | /* Not enough header? */ | ||
152 | inside = skb_header_pointer(skb, ip_hdrlen(skb), sizeof(_in), &_in); | ||
153 | if (inside == NULL) | ||
154 | return -NF_ACCEPT; | ||
155 | |||
156 | /* Ignore ICMP's containing fragments (shouldn't happen) */ | ||
157 | if (inside->ip.frag_off & htons(IP_OFFSET)) { | ||
158 | DEBUGP("icmp_error_track: fragment of proto %u\n", | ||
159 | inside->ip.protocol); | ||
160 | return -NF_ACCEPT; | ||
161 | } | ||
162 | |||
163 | innerproto = ip_conntrack_proto_find_get(inside->ip.protocol); | ||
164 | dataoff = ip_hdrlen(skb) + sizeof(inside->icmp) + inside->ip.ihl * 4; | ||
165 | /* Are they talking about one of our connections? */ | ||
166 | if (!ip_ct_get_tuple(&inside->ip, skb, dataoff, &origtuple, innerproto)) { | ||
167 | DEBUGP("icmp_error: ! get_tuple p=%u", inside->ip.protocol); | ||
168 | ip_conntrack_proto_put(innerproto); | ||
169 | return -NF_ACCEPT; | ||
170 | } | ||
171 | |||
172 | /* Ordinarily, we'd expect the inverted tupleproto, but it's | ||
173 | been preserved inside the ICMP. */ | ||
174 | if (!ip_ct_invert_tuple(&innertuple, &origtuple, innerproto)) { | ||
175 | DEBUGP("icmp_error_track: Can't invert tuple\n"); | ||
176 | ip_conntrack_proto_put(innerproto); | ||
177 | return -NF_ACCEPT; | ||
178 | } | ||
179 | ip_conntrack_proto_put(innerproto); | ||
180 | |||
181 | *ctinfo = IP_CT_RELATED; | ||
182 | |||
183 | h = ip_conntrack_find_get(&innertuple, NULL); | ||
184 | if (!h) { | ||
185 | /* Locally generated ICMPs will match inverted if they | ||
186 | haven't been SNAT'ed yet */ | ||
187 | /* FIXME: NAT code has to handle half-done double NAT --RR */ | ||
188 | if (hooknum == NF_IP_LOCAL_OUT) | ||
189 | h = ip_conntrack_find_get(&origtuple, NULL); | ||
190 | |||
191 | if (!h) { | ||
192 | DEBUGP("icmp_error_track: no match\n"); | ||
193 | return -NF_ACCEPT; | ||
194 | } | ||
195 | /* Reverse direction from that found */ | ||
196 | if (DIRECTION(h) != IP_CT_DIR_REPLY) | ||
197 | *ctinfo += IP_CT_IS_REPLY; | ||
198 | } else { | ||
199 | if (DIRECTION(h) == IP_CT_DIR_REPLY) | ||
200 | *ctinfo += IP_CT_IS_REPLY; | ||
201 | } | ||
202 | |||
203 | /* Update skb to refer to this connection */ | ||
204 | skb->nfct = &tuplehash_to_ctrack(h)->ct_general; | ||
205 | skb->nfctinfo = *ctinfo; | ||
206 | return -NF_ACCEPT; | ||
207 | } | ||
208 | |||
209 | /* Small and modified version of icmp_rcv */ | ||
210 | static int | ||
211 | icmp_error(struct sk_buff *skb, enum ip_conntrack_info *ctinfo, | ||
212 | unsigned int hooknum) | ||
213 | { | ||
214 | struct icmphdr _ih, *icmph; | ||
215 | |||
216 | /* Not enough header? */ | ||
217 | icmph = skb_header_pointer(skb, ip_hdrlen(skb), sizeof(_ih), &_ih); | ||
218 | if (icmph == NULL) { | ||
219 | if (LOG_INVALID(IPPROTO_ICMP)) | ||
220 | nf_log_packet(PF_INET, 0, skb, NULL, NULL, NULL, | ||
221 | "ip_ct_icmp: short packet "); | ||
222 | return -NF_ACCEPT; | ||
223 | } | ||
224 | |||
225 | /* See ip_conntrack_proto_tcp.c */ | ||
226 | if (ip_conntrack_checksum && hooknum == NF_IP_PRE_ROUTING && | ||
227 | nf_ip_checksum(skb, hooknum, ip_hdrlen(skb), 0)) { | ||
228 | if (LOG_INVALID(IPPROTO_ICMP)) | ||
229 | nf_log_packet(PF_INET, 0, skb, NULL, NULL, NULL, | ||
230 | "ip_ct_icmp: bad ICMP checksum "); | ||
231 | return -NF_ACCEPT; | ||
232 | } | ||
233 | |||
234 | /* | ||
235 | * 18 is the highest 'known' ICMP type. Anything else is a mystery | ||
236 | * | ||
237 | * RFC 1122: 3.2.2 Unknown ICMP messages types MUST be silently | ||
238 | * discarded. | ||
239 | */ | ||
240 | if (icmph->type > NR_ICMP_TYPES) { | ||
241 | if (LOG_INVALID(IPPROTO_ICMP)) | ||
242 | nf_log_packet(PF_INET, 0, skb, NULL, NULL, NULL, | ||
243 | "ip_ct_icmp: invalid ICMP type "); | ||
244 | return -NF_ACCEPT; | ||
245 | } | ||
246 | |||
247 | /* Need to track icmp error message? */ | ||
248 | if (icmph->type != ICMP_DEST_UNREACH | ||
249 | && icmph->type != ICMP_SOURCE_QUENCH | ||
250 | && icmph->type != ICMP_TIME_EXCEEDED | ||
251 | && icmph->type != ICMP_PARAMETERPROB | ||
252 | && icmph->type != ICMP_REDIRECT) | ||
253 | return NF_ACCEPT; | ||
254 | |||
255 | return icmp_error_message(skb, ctinfo, hooknum); | ||
256 | } | ||
257 | |||
258 | #if defined(CONFIG_IP_NF_CONNTRACK_NETLINK) || \ | ||
259 | defined(CONFIG_IP_NF_CONNTRACK_NETLINK_MODULE) | ||
260 | static int icmp_tuple_to_nfattr(struct sk_buff *skb, | ||
261 | const struct ip_conntrack_tuple *t) | ||
262 | { | ||
263 | NFA_PUT(skb, CTA_PROTO_ICMP_ID, sizeof(__be16), | ||
264 | &t->src.u.icmp.id); | ||
265 | NFA_PUT(skb, CTA_PROTO_ICMP_TYPE, sizeof(u_int8_t), | ||
266 | &t->dst.u.icmp.type); | ||
267 | NFA_PUT(skb, CTA_PROTO_ICMP_CODE, sizeof(u_int8_t), | ||
268 | &t->dst.u.icmp.code); | ||
269 | |||
270 | return 0; | ||
271 | |||
272 | nfattr_failure: | ||
273 | return -1; | ||
274 | } | ||
275 | |||
276 | static int icmp_nfattr_to_tuple(struct nfattr *tb[], | ||
277 | struct ip_conntrack_tuple *tuple) | ||
278 | { | ||
279 | if (!tb[CTA_PROTO_ICMP_TYPE-1] | ||
280 | || !tb[CTA_PROTO_ICMP_CODE-1] | ||
281 | || !tb[CTA_PROTO_ICMP_ID-1]) | ||
282 | return -EINVAL; | ||
283 | |||
284 | tuple->dst.u.icmp.type = | ||
285 | *(u_int8_t *)NFA_DATA(tb[CTA_PROTO_ICMP_TYPE-1]); | ||
286 | tuple->dst.u.icmp.code = | ||
287 | *(u_int8_t *)NFA_DATA(tb[CTA_PROTO_ICMP_CODE-1]); | ||
288 | tuple->src.u.icmp.id = | ||
289 | *(__be16 *)NFA_DATA(tb[CTA_PROTO_ICMP_ID-1]); | ||
290 | |||
291 | if (tuple->dst.u.icmp.type >= sizeof(invmap) | ||
292 | || !invmap[tuple->dst.u.icmp.type]) | ||
293 | return -EINVAL; | ||
294 | |||
295 | return 0; | ||
296 | } | ||
297 | #endif | ||
298 | |||
299 | struct ip_conntrack_protocol ip_conntrack_protocol_icmp = | ||
300 | { | ||
301 | .proto = IPPROTO_ICMP, | ||
302 | .name = "icmp", | ||
303 | .pkt_to_tuple = icmp_pkt_to_tuple, | ||
304 | .invert_tuple = icmp_invert_tuple, | ||
305 | .print_tuple = icmp_print_tuple, | ||
306 | .print_conntrack = icmp_print_conntrack, | ||
307 | .packet = icmp_packet, | ||
308 | .new = icmp_new, | ||
309 | .error = icmp_error, | ||
310 | #if defined(CONFIG_IP_NF_CONNTRACK_NETLINK) || \ | ||
311 | defined(CONFIG_IP_NF_CONNTRACK_NETLINK_MODULE) | ||
312 | .tuple_to_nfattr = icmp_tuple_to_nfattr, | ||
313 | .nfattr_to_tuple = icmp_nfattr_to_tuple, | ||
314 | #endif | ||
315 | }; | ||
diff --git a/net/ipv4/netfilter/ip_conntrack_proto_sctp.c b/net/ipv4/netfilter/ip_conntrack_proto_sctp.c deleted file mode 100644 index 91d0c05c8e86..000000000000 --- a/net/ipv4/netfilter/ip_conntrack_proto_sctp.c +++ /dev/null | |||
@@ -1,659 +0,0 @@ | |||
1 | /* | ||
2 | * Connection tracking protocol helper module for SCTP. | ||
3 | * | ||
4 | * SCTP is defined in RFC 2960. References to various sections in this code | ||
5 | * are to this RFC. | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | */ | ||
11 | |||
12 | /* | ||
13 | * Added support for proc manipulation of timeouts. | ||
14 | */ | ||
15 | |||
16 | #include <linux/types.h> | ||
17 | #include <linux/timer.h> | ||
18 | #include <linux/interrupt.h> | ||
19 | #include <linux/netfilter.h> | ||
20 | #include <linux/module.h> | ||
21 | #include <linux/in.h> | ||
22 | #include <linux/ip.h> | ||
23 | #include <linux/sctp.h> | ||
24 | #include <linux/string.h> | ||
25 | #include <linux/seq_file.h> | ||
26 | |||
27 | #include <linux/netfilter_ipv4/ip_conntrack.h> | ||
28 | #include <linux/netfilter_ipv4/ip_conntrack_protocol.h> | ||
29 | |||
30 | #if 0 | ||
31 | #define DEBUGP(format, ...) printk(format, ## __VA_ARGS__) | ||
32 | #else | ||
33 | #define DEBUGP(format, args...) | ||
34 | #endif | ||
35 | |||
36 | /* Protects conntrack->proto.sctp */ | ||
37 | static DEFINE_RWLOCK(sctp_lock); | ||
38 | |||
39 | /* FIXME: Examine ipfilter's timeouts and conntrack transitions more | ||
40 | closely. They're more complex. --RR | ||
41 | |||
42 | And so for me for SCTP :D -Kiran */ | ||
43 | |||
44 | static const char *sctp_conntrack_names[] = { | ||
45 | "NONE", | ||
46 | "CLOSED", | ||
47 | "COOKIE_WAIT", | ||
48 | "COOKIE_ECHOED", | ||
49 | "ESTABLISHED", | ||
50 | "SHUTDOWN_SENT", | ||
51 | "SHUTDOWN_RECD", | ||
52 | "SHUTDOWN_ACK_SENT", | ||
53 | }; | ||
54 | |||
55 | #define SECS * HZ | ||
56 | #define MINS * 60 SECS | ||
57 | #define HOURS * 60 MINS | ||
58 | #define DAYS * 24 HOURS | ||
59 | |||
60 | static unsigned int ip_ct_sctp_timeout_closed __read_mostly = 10 SECS; | ||
61 | static unsigned int ip_ct_sctp_timeout_cookie_wait __read_mostly = 3 SECS; | ||
62 | static unsigned int ip_ct_sctp_timeout_cookie_echoed __read_mostly = 3 SECS; | ||
63 | static unsigned int ip_ct_sctp_timeout_established __read_mostly = 5 DAYS; | ||
64 | static unsigned int ip_ct_sctp_timeout_shutdown_sent __read_mostly = 300 SECS / 1000; | ||
65 | static unsigned int ip_ct_sctp_timeout_shutdown_recd __read_mostly = 300 SECS / 1000; | ||
66 | static unsigned int ip_ct_sctp_timeout_shutdown_ack_sent __read_mostly = 3 SECS; | ||
67 | |||
68 | static const unsigned int * sctp_timeouts[] | ||
69 | = { NULL, /* SCTP_CONNTRACK_NONE */ | ||
70 | &ip_ct_sctp_timeout_closed, /* SCTP_CONNTRACK_CLOSED */ | ||
71 | &ip_ct_sctp_timeout_cookie_wait, /* SCTP_CONNTRACK_COOKIE_WAIT */ | ||
72 | &ip_ct_sctp_timeout_cookie_echoed, /* SCTP_CONNTRACK_COOKIE_ECHOED */ | ||
73 | &ip_ct_sctp_timeout_established, /* SCTP_CONNTRACK_ESTABLISHED */ | ||
74 | &ip_ct_sctp_timeout_shutdown_sent, /* SCTP_CONNTRACK_SHUTDOWN_SENT */ | ||
75 | &ip_ct_sctp_timeout_shutdown_recd, /* SCTP_CONNTRACK_SHUTDOWN_RECD */ | ||
76 | &ip_ct_sctp_timeout_shutdown_ack_sent /* SCTP_CONNTRACK_SHUTDOWN_ACK_SENT */ | ||
77 | }; | ||
78 | |||
79 | #define sNO SCTP_CONNTRACK_NONE | ||
80 | #define sCL SCTP_CONNTRACK_CLOSED | ||
81 | #define sCW SCTP_CONNTRACK_COOKIE_WAIT | ||
82 | #define sCE SCTP_CONNTRACK_COOKIE_ECHOED | ||
83 | #define sES SCTP_CONNTRACK_ESTABLISHED | ||
84 | #define sSS SCTP_CONNTRACK_SHUTDOWN_SENT | ||
85 | #define sSR SCTP_CONNTRACK_SHUTDOWN_RECD | ||
86 | #define sSA SCTP_CONNTRACK_SHUTDOWN_ACK_SENT | ||
87 | #define sIV SCTP_CONNTRACK_MAX | ||
88 | |||
89 | /* | ||
90 | These are the descriptions of the states: | ||
91 | |||
92 | NOTE: These state names are tantalizingly similar to the states of an | ||
93 | SCTP endpoint. But the interpretation of the states is a little different, | ||
94 | considering that these are the states of the connection and not of an end | ||
95 | point. Please note the subtleties. -Kiran | ||
96 | |||
97 | NONE - Nothing so far. | ||
98 | COOKIE WAIT - We have seen an INIT chunk in the original direction, or also | ||
99 | an INIT_ACK chunk in the reply direction. | ||
100 | COOKIE ECHOED - We have seen a COOKIE_ECHO chunk in the original direction. | ||
101 | ESTABLISHED - We have seen a COOKIE_ACK in the reply direction. | ||
102 | SHUTDOWN_SENT - We have seen a SHUTDOWN chunk in the original direction. | ||
103 | SHUTDOWN_RECD - We have seen a SHUTDOWN chunk in the reply directoin. | ||
104 | SHUTDOWN_ACK_SENT - We have seen a SHUTDOWN_ACK chunk in the direction opposite | ||
105 | to that of the SHUTDOWN chunk. | ||
106 | CLOSED - We have seen a SHUTDOWN_COMPLETE chunk in the direction of | ||
107 | the SHUTDOWN chunk. Connection is closed. | ||
108 | */ | ||
109 | |||
110 | /* TODO | ||
111 | - I have assumed that the first INIT is in the original direction. | ||
112 | This messes things when an INIT comes in the reply direction in CLOSED | ||
113 | state. | ||
114 | - Check the error type in the reply dir before transitioning from | ||
115 | cookie echoed to closed. | ||
116 | - Sec 5.2.4 of RFC 2960 | ||
117 | - Multi Homing support. | ||
118 | */ | ||
119 | |||
120 | /* SCTP conntrack state transitions */ | ||
121 | static const enum sctp_conntrack sctp_conntracks[2][9][SCTP_CONNTRACK_MAX] = { | ||
122 | { | ||
123 | /* ORIGINAL */ | ||
124 | /* sNO, sCL, sCW, sCE, sES, sSS, sSR, sSA */ | ||
125 | /* init */ {sCW, sCW, sCW, sCE, sES, sSS, sSR, sSA}, | ||
126 | /* init_ack */ {sCL, sCL, sCW, sCE, sES, sSS, sSR, sSA}, | ||
127 | /* abort */ {sCL, sCL, sCL, sCL, sCL, sCL, sCL, sCL}, | ||
128 | /* shutdown */ {sCL, sCL, sCW, sCE, sSS, sSS, sSR, sSA}, | ||
129 | /* shutdown_ack */ {sSA, sCL, sCW, sCE, sES, sSA, sSA, sSA}, | ||
130 | /* error */ {sCL, sCL, sCW, sCE, sES, sSS, sSR, sSA},/* Cant have Stale cookie*/ | ||
131 | /* cookie_echo */ {sCL, sCL, sCE, sCE, sES, sSS, sSR, sSA},/* 5.2.4 - Big TODO */ | ||
132 | /* cookie_ack */ {sCL, sCL, sCW, sCE, sES, sSS, sSR, sSA},/* Cant come in orig dir */ | ||
133 | /* shutdown_comp*/ {sCL, sCL, sCW, sCE, sES, sSS, sSR, sCL} | ||
134 | }, | ||
135 | { | ||
136 | /* REPLY */ | ||
137 | /* sNO, sCL, sCW, sCE, sES, sSS, sSR, sSA */ | ||
138 | /* init */ {sIV, sCL, sCW, sCE, sES, sSS, sSR, sSA},/* INIT in sCL Big TODO */ | ||
139 | /* init_ack */ {sIV, sCL, sCW, sCE, sES, sSS, sSR, sSA}, | ||
140 | /* abort */ {sIV, sCL, sCL, sCL, sCL, sCL, sCL, sCL}, | ||
141 | /* shutdown */ {sIV, sCL, sCW, sCE, sSR, sSS, sSR, sSA}, | ||
142 | /* shutdown_ack */ {sIV, sCL, sCW, sCE, sES, sSA, sSA, sSA}, | ||
143 | /* error */ {sIV, sCL, sCW, sCL, sES, sSS, sSR, sSA}, | ||
144 | /* cookie_echo */ {sIV, sCL, sCW, sCE, sES, sSS, sSR, sSA},/* Cant come in reply dir */ | ||
145 | /* cookie_ack */ {sIV, sCL, sCW, sES, sES, sSS, sSR, sSA}, | ||
146 | /* shutdown_comp*/ {sIV, sCL, sCW, sCE, sES, sSS, sSR, sCL} | ||
147 | } | ||
148 | }; | ||
149 | |||
150 | static int sctp_pkt_to_tuple(const struct sk_buff *skb, | ||
151 | unsigned int dataoff, | ||
152 | struct ip_conntrack_tuple *tuple) | ||
153 | { | ||
154 | sctp_sctphdr_t _hdr, *hp; | ||
155 | |||
156 | DEBUGP(__FUNCTION__); | ||
157 | DEBUGP("\n"); | ||
158 | |||
159 | /* Actually only need first 8 bytes. */ | ||
160 | hp = skb_header_pointer(skb, dataoff, 8, &_hdr); | ||
161 | if (hp == NULL) | ||
162 | return 0; | ||
163 | |||
164 | tuple->src.u.sctp.port = hp->source; | ||
165 | tuple->dst.u.sctp.port = hp->dest; | ||
166 | return 1; | ||
167 | } | ||
168 | |||
169 | static int sctp_invert_tuple(struct ip_conntrack_tuple *tuple, | ||
170 | const struct ip_conntrack_tuple *orig) | ||
171 | { | ||
172 | DEBUGP(__FUNCTION__); | ||
173 | DEBUGP("\n"); | ||
174 | |||
175 | tuple->src.u.sctp.port = orig->dst.u.sctp.port; | ||
176 | tuple->dst.u.sctp.port = orig->src.u.sctp.port; | ||
177 | return 1; | ||
178 | } | ||
179 | |||
180 | /* Print out the per-protocol part of the tuple. */ | ||
181 | static int sctp_print_tuple(struct seq_file *s, | ||
182 | const struct ip_conntrack_tuple *tuple) | ||
183 | { | ||
184 | DEBUGP(__FUNCTION__); | ||
185 | DEBUGP("\n"); | ||
186 | |||
187 | return seq_printf(s, "sport=%hu dport=%hu ", | ||
188 | ntohs(tuple->src.u.sctp.port), | ||
189 | ntohs(tuple->dst.u.sctp.port)); | ||
190 | } | ||
191 | |||
192 | /* Print out the private part of the conntrack. */ | ||
193 | static int sctp_print_conntrack(struct seq_file *s, | ||
194 | const struct ip_conntrack *conntrack) | ||
195 | { | ||
196 | enum sctp_conntrack state; | ||
197 | |||
198 | DEBUGP(__FUNCTION__); | ||
199 | DEBUGP("\n"); | ||
200 | |||
201 | read_lock_bh(&sctp_lock); | ||
202 | state = conntrack->proto.sctp.state; | ||
203 | read_unlock_bh(&sctp_lock); | ||
204 | |||
205 | return seq_printf(s, "%s ", sctp_conntrack_names[state]); | ||
206 | } | ||
207 | |||
208 | #define for_each_sctp_chunk(skb, sch, _sch, offset, count) \ | ||
209 | for (offset = ip_hdrlen(skb) + sizeof(sctp_sctphdr_t), count = 0; \ | ||
210 | offset < skb->len && \ | ||
211 | (sch = skb_header_pointer(skb, offset, sizeof(_sch), &_sch)); \ | ||
212 | offset += (ntohs(sch->length) + 3) & ~3, count++) | ||
213 | |||
214 | /* Some validity checks to make sure the chunks are fine */ | ||
215 | static int do_basic_checks(struct ip_conntrack *conntrack, | ||
216 | const struct sk_buff *skb, | ||
217 | char *map) | ||
218 | { | ||
219 | u_int32_t offset, count; | ||
220 | sctp_chunkhdr_t _sch, *sch; | ||
221 | int flag; | ||
222 | |||
223 | DEBUGP(__FUNCTION__); | ||
224 | DEBUGP("\n"); | ||
225 | |||
226 | flag = 0; | ||
227 | |||
228 | for_each_sctp_chunk (skb, sch, _sch, offset, count) { | ||
229 | DEBUGP("Chunk Num: %d Type: %d\n", count, sch->type); | ||
230 | |||
231 | if (sch->type == SCTP_CID_INIT | ||
232 | || sch->type == SCTP_CID_INIT_ACK | ||
233 | || sch->type == SCTP_CID_SHUTDOWN_COMPLETE) { | ||
234 | flag = 1; | ||
235 | } | ||
236 | |||
237 | /* | ||
238 | * Cookie Ack/Echo chunks not the first OR | ||
239 | * Init / Init Ack / Shutdown compl chunks not the only chunks | ||
240 | * OR zero-length. | ||
241 | */ | ||
242 | if (((sch->type == SCTP_CID_COOKIE_ACK | ||
243 | || sch->type == SCTP_CID_COOKIE_ECHO | ||
244 | || flag) | ||
245 | && count !=0) || !sch->length) { | ||
246 | DEBUGP("Basic checks failed\n"); | ||
247 | return 1; | ||
248 | } | ||
249 | |||
250 | if (map) { | ||
251 | set_bit(sch->type, (void *)map); | ||
252 | } | ||
253 | } | ||
254 | |||
255 | DEBUGP("Basic checks passed\n"); | ||
256 | return count == 0; | ||
257 | } | ||
258 | |||
259 | static int new_state(enum ip_conntrack_dir dir, | ||
260 | enum sctp_conntrack cur_state, | ||
261 | int chunk_type) | ||
262 | { | ||
263 | int i; | ||
264 | |||
265 | DEBUGP(__FUNCTION__); | ||
266 | DEBUGP("\n"); | ||
267 | |||
268 | DEBUGP("Chunk type: %d\n", chunk_type); | ||
269 | |||
270 | switch (chunk_type) { | ||
271 | case SCTP_CID_INIT: | ||
272 | DEBUGP("SCTP_CID_INIT\n"); | ||
273 | i = 0; break; | ||
274 | case SCTP_CID_INIT_ACK: | ||
275 | DEBUGP("SCTP_CID_INIT_ACK\n"); | ||
276 | i = 1; break; | ||
277 | case SCTP_CID_ABORT: | ||
278 | DEBUGP("SCTP_CID_ABORT\n"); | ||
279 | i = 2; break; | ||
280 | case SCTP_CID_SHUTDOWN: | ||
281 | DEBUGP("SCTP_CID_SHUTDOWN\n"); | ||
282 | i = 3; break; | ||
283 | case SCTP_CID_SHUTDOWN_ACK: | ||
284 | DEBUGP("SCTP_CID_SHUTDOWN_ACK\n"); | ||
285 | i = 4; break; | ||
286 | case SCTP_CID_ERROR: | ||
287 | DEBUGP("SCTP_CID_ERROR\n"); | ||
288 | i = 5; break; | ||
289 | case SCTP_CID_COOKIE_ECHO: | ||
290 | DEBUGP("SCTP_CID_COOKIE_ECHO\n"); | ||
291 | i = 6; break; | ||
292 | case SCTP_CID_COOKIE_ACK: | ||
293 | DEBUGP("SCTP_CID_COOKIE_ACK\n"); | ||
294 | i = 7; break; | ||
295 | case SCTP_CID_SHUTDOWN_COMPLETE: | ||
296 | DEBUGP("SCTP_CID_SHUTDOWN_COMPLETE\n"); | ||
297 | i = 8; break; | ||
298 | default: | ||
299 | /* Other chunks like DATA, SACK, HEARTBEAT and | ||
300 | its ACK do not cause a change in state */ | ||
301 | DEBUGP("Unknown chunk type, Will stay in %s\n", | ||
302 | sctp_conntrack_names[cur_state]); | ||
303 | return cur_state; | ||
304 | } | ||
305 | |||
306 | DEBUGP("dir: %d cur_state: %s chunk_type: %d new_state: %s\n", | ||
307 | dir, sctp_conntrack_names[cur_state], chunk_type, | ||
308 | sctp_conntrack_names[sctp_conntracks[dir][i][cur_state]]); | ||
309 | |||
310 | return sctp_conntracks[dir][i][cur_state]; | ||
311 | } | ||
312 | |||
313 | /* Returns verdict for packet, or -1 for invalid. */ | ||
314 | static int sctp_packet(struct ip_conntrack *conntrack, | ||
315 | const struct sk_buff *skb, | ||
316 | enum ip_conntrack_info ctinfo) | ||
317 | { | ||
318 | enum sctp_conntrack newconntrack, oldsctpstate; | ||
319 | struct iphdr *iph = ip_hdr(skb); | ||
320 | sctp_sctphdr_t _sctph, *sh; | ||
321 | sctp_chunkhdr_t _sch, *sch; | ||
322 | u_int32_t offset, count; | ||
323 | char map[256 / sizeof (char)] = {0}; | ||
324 | |||
325 | DEBUGP(__FUNCTION__); | ||
326 | DEBUGP("\n"); | ||
327 | |||
328 | sh = skb_header_pointer(skb, iph->ihl * 4, sizeof(_sctph), &_sctph); | ||
329 | if (sh == NULL) | ||
330 | return -1; | ||
331 | |||
332 | if (do_basic_checks(conntrack, skb, map) != 0) | ||
333 | return -1; | ||
334 | |||
335 | /* Check the verification tag (Sec 8.5) */ | ||
336 | if (!test_bit(SCTP_CID_INIT, (void *)map) | ||
337 | && !test_bit(SCTP_CID_SHUTDOWN_COMPLETE, (void *)map) | ||
338 | && !test_bit(SCTP_CID_COOKIE_ECHO, (void *)map) | ||
339 | && !test_bit(SCTP_CID_ABORT, (void *)map) | ||
340 | && !test_bit(SCTP_CID_SHUTDOWN_ACK, (void *)map) | ||
341 | && (sh->vtag != conntrack->proto.sctp.vtag[CTINFO2DIR(ctinfo)])) { | ||
342 | DEBUGP("Verification tag check failed\n"); | ||
343 | return -1; | ||
344 | } | ||
345 | |||
346 | oldsctpstate = newconntrack = SCTP_CONNTRACK_MAX; | ||
347 | for_each_sctp_chunk (skb, sch, _sch, offset, count) { | ||
348 | write_lock_bh(&sctp_lock); | ||
349 | |||
350 | /* Special cases of Verification tag check (Sec 8.5.1) */ | ||
351 | if (sch->type == SCTP_CID_INIT) { | ||
352 | /* Sec 8.5.1 (A) */ | ||
353 | if (sh->vtag != 0) { | ||
354 | write_unlock_bh(&sctp_lock); | ||
355 | return -1; | ||
356 | } | ||
357 | } else if (sch->type == SCTP_CID_ABORT) { | ||
358 | /* Sec 8.5.1 (B) */ | ||
359 | if (!(sh->vtag == conntrack->proto.sctp.vtag[CTINFO2DIR(ctinfo)]) | ||
360 | && !(sh->vtag == conntrack->proto.sctp.vtag | ||
361 | [1 - CTINFO2DIR(ctinfo)])) { | ||
362 | write_unlock_bh(&sctp_lock); | ||
363 | return -1; | ||
364 | } | ||
365 | } else if (sch->type == SCTP_CID_SHUTDOWN_COMPLETE) { | ||
366 | /* Sec 8.5.1 (C) */ | ||
367 | if (!(sh->vtag == conntrack->proto.sctp.vtag[CTINFO2DIR(ctinfo)]) | ||
368 | && !(sh->vtag == conntrack->proto.sctp.vtag | ||
369 | [1 - CTINFO2DIR(ctinfo)] | ||
370 | && (sch->flags & 1))) { | ||
371 | write_unlock_bh(&sctp_lock); | ||
372 | return -1; | ||
373 | } | ||
374 | } else if (sch->type == SCTP_CID_COOKIE_ECHO) { | ||
375 | /* Sec 8.5.1 (D) */ | ||
376 | if (!(sh->vtag == conntrack->proto.sctp.vtag[CTINFO2DIR(ctinfo)])) { | ||
377 | write_unlock_bh(&sctp_lock); | ||
378 | return -1; | ||
379 | } | ||
380 | } | ||
381 | |||
382 | oldsctpstate = conntrack->proto.sctp.state; | ||
383 | newconntrack = new_state(CTINFO2DIR(ctinfo), oldsctpstate, sch->type); | ||
384 | |||
385 | /* Invalid */ | ||
386 | if (newconntrack == SCTP_CONNTRACK_MAX) { | ||
387 | DEBUGP("ip_conntrack_sctp: Invalid dir=%i ctype=%u conntrack=%u\n", | ||
388 | CTINFO2DIR(ctinfo), sch->type, oldsctpstate); | ||
389 | write_unlock_bh(&sctp_lock); | ||
390 | return -1; | ||
391 | } | ||
392 | |||
393 | /* If it is an INIT or an INIT ACK note down the vtag */ | ||
394 | if (sch->type == SCTP_CID_INIT | ||
395 | || sch->type == SCTP_CID_INIT_ACK) { | ||
396 | sctp_inithdr_t _inithdr, *ih; | ||
397 | |||
398 | ih = skb_header_pointer(skb, offset + sizeof(sctp_chunkhdr_t), | ||
399 | sizeof(_inithdr), &_inithdr); | ||
400 | if (ih == NULL) { | ||
401 | write_unlock_bh(&sctp_lock); | ||
402 | return -1; | ||
403 | } | ||
404 | DEBUGP("Setting vtag %x for dir %d\n", | ||
405 | ih->init_tag, !CTINFO2DIR(ctinfo)); | ||
406 | conntrack->proto.sctp.vtag[!CTINFO2DIR(ctinfo)] = ih->init_tag; | ||
407 | } | ||
408 | |||
409 | conntrack->proto.sctp.state = newconntrack; | ||
410 | if (oldsctpstate != newconntrack) | ||
411 | ip_conntrack_event_cache(IPCT_PROTOINFO, skb); | ||
412 | write_unlock_bh(&sctp_lock); | ||
413 | } | ||
414 | |||
415 | ip_ct_refresh_acct(conntrack, ctinfo, skb, *sctp_timeouts[newconntrack]); | ||
416 | |||
417 | if (oldsctpstate == SCTP_CONNTRACK_COOKIE_ECHOED | ||
418 | && CTINFO2DIR(ctinfo) == IP_CT_DIR_REPLY | ||
419 | && newconntrack == SCTP_CONNTRACK_ESTABLISHED) { | ||
420 | DEBUGP("Setting assured bit\n"); | ||
421 | set_bit(IPS_ASSURED_BIT, &conntrack->status); | ||
422 | ip_conntrack_event_cache(IPCT_STATUS, skb); | ||
423 | } | ||
424 | |||
425 | return NF_ACCEPT; | ||
426 | } | ||
427 | |||
428 | /* Called when a new connection for this protocol found. */ | ||
429 | static int sctp_new(struct ip_conntrack *conntrack, | ||
430 | const struct sk_buff *skb) | ||
431 | { | ||
432 | enum sctp_conntrack newconntrack; | ||
433 | struct iphdr *iph = ip_hdr(skb); | ||
434 | sctp_sctphdr_t _sctph, *sh; | ||
435 | sctp_chunkhdr_t _sch, *sch; | ||
436 | u_int32_t offset, count; | ||
437 | char map[256 / sizeof (char)] = {0}; | ||
438 | |||
439 | DEBUGP(__FUNCTION__); | ||
440 | DEBUGP("\n"); | ||
441 | |||
442 | sh = skb_header_pointer(skb, iph->ihl * 4, sizeof(_sctph), &_sctph); | ||
443 | if (sh == NULL) | ||
444 | return 0; | ||
445 | |||
446 | if (do_basic_checks(conntrack, skb, map) != 0) | ||
447 | return 0; | ||
448 | |||
449 | /* If an OOTB packet has any of these chunks discard (Sec 8.4) */ | ||
450 | if ((test_bit (SCTP_CID_ABORT, (void *)map)) | ||
451 | || (test_bit (SCTP_CID_SHUTDOWN_COMPLETE, (void *)map)) | ||
452 | || (test_bit (SCTP_CID_COOKIE_ACK, (void *)map))) { | ||
453 | return 0; | ||
454 | } | ||
455 | |||
456 | newconntrack = SCTP_CONNTRACK_MAX; | ||
457 | for_each_sctp_chunk (skb, sch, _sch, offset, count) { | ||
458 | /* Don't need lock here: this conntrack not in circulation yet */ | ||
459 | newconntrack = new_state (IP_CT_DIR_ORIGINAL, | ||
460 | SCTP_CONNTRACK_NONE, sch->type); | ||
461 | |||
462 | /* Invalid: delete conntrack */ | ||
463 | if (newconntrack == SCTP_CONNTRACK_MAX) { | ||
464 | DEBUGP("ip_conntrack_sctp: invalid new deleting.\n"); | ||
465 | return 0; | ||
466 | } | ||
467 | |||
468 | /* Copy the vtag into the state info */ | ||
469 | if (sch->type == SCTP_CID_INIT) { | ||
470 | if (sh->vtag == 0) { | ||
471 | sctp_inithdr_t _inithdr, *ih; | ||
472 | |||
473 | ih = skb_header_pointer(skb, offset + sizeof(sctp_chunkhdr_t), | ||
474 | sizeof(_inithdr), &_inithdr); | ||
475 | if (ih == NULL) | ||
476 | return 0; | ||
477 | |||
478 | DEBUGP("Setting vtag %x for new conn\n", | ||
479 | ih->init_tag); | ||
480 | |||
481 | conntrack->proto.sctp.vtag[IP_CT_DIR_REPLY] = | ||
482 | ih->init_tag; | ||
483 | } else { | ||
484 | /* Sec 8.5.1 (A) */ | ||
485 | return 0; | ||
486 | } | ||
487 | } | ||
488 | /* If it is a shutdown ack OOTB packet, we expect a return | ||
489 | shutdown complete, otherwise an ABORT Sec 8.4 (5) and (8) */ | ||
490 | else { | ||
491 | DEBUGP("Setting vtag %x for new conn OOTB\n", | ||
492 | sh->vtag); | ||
493 | conntrack->proto.sctp.vtag[IP_CT_DIR_REPLY] = sh->vtag; | ||
494 | } | ||
495 | |||
496 | conntrack->proto.sctp.state = newconntrack; | ||
497 | } | ||
498 | |||
499 | return 1; | ||
500 | } | ||
501 | |||
502 | static struct ip_conntrack_protocol ip_conntrack_protocol_sctp = { | ||
503 | .proto = IPPROTO_SCTP, | ||
504 | .name = "sctp", | ||
505 | .pkt_to_tuple = sctp_pkt_to_tuple, | ||
506 | .invert_tuple = sctp_invert_tuple, | ||
507 | .print_tuple = sctp_print_tuple, | ||
508 | .print_conntrack = sctp_print_conntrack, | ||
509 | .packet = sctp_packet, | ||
510 | .new = sctp_new, | ||
511 | .destroy = NULL, | ||
512 | .me = THIS_MODULE, | ||
513 | #if defined(CONFIG_IP_NF_CONNTRACK_NETLINK) || \ | ||
514 | defined(CONFIG_IP_NF_CONNTRACK_NETLINK_MODULE) | ||
515 | .tuple_to_nfattr = ip_ct_port_tuple_to_nfattr, | ||
516 | .nfattr_to_tuple = ip_ct_port_nfattr_to_tuple, | ||
517 | #endif | ||
518 | }; | ||
519 | |||
520 | #ifdef CONFIG_SYSCTL | ||
521 | static ctl_table ip_ct_sysctl_table[] = { | ||
522 | { | ||
523 | .ctl_name = NET_IPV4_NF_CONNTRACK_SCTP_TIMEOUT_CLOSED, | ||
524 | .procname = "ip_conntrack_sctp_timeout_closed", | ||
525 | .data = &ip_ct_sctp_timeout_closed, | ||
526 | .maxlen = sizeof(unsigned int), | ||
527 | .mode = 0644, | ||
528 | .proc_handler = &proc_dointvec_jiffies, | ||
529 | }, | ||
530 | { | ||
531 | .ctl_name = NET_IPV4_NF_CONNTRACK_SCTP_TIMEOUT_COOKIE_WAIT, | ||
532 | .procname = "ip_conntrack_sctp_timeout_cookie_wait", | ||
533 | .data = &ip_ct_sctp_timeout_cookie_wait, | ||
534 | .maxlen = sizeof(unsigned int), | ||
535 | .mode = 0644, | ||
536 | .proc_handler = &proc_dointvec_jiffies, | ||
537 | }, | ||
538 | { | ||
539 | .ctl_name = NET_IPV4_NF_CONNTRACK_SCTP_TIMEOUT_COOKIE_ECHOED, | ||
540 | .procname = "ip_conntrack_sctp_timeout_cookie_echoed", | ||
541 | .data = &ip_ct_sctp_timeout_cookie_echoed, | ||
542 | .maxlen = sizeof(unsigned int), | ||
543 | .mode = 0644, | ||
544 | .proc_handler = &proc_dointvec_jiffies, | ||
545 | }, | ||
546 | { | ||
547 | .ctl_name = NET_IPV4_NF_CONNTRACK_SCTP_TIMEOUT_ESTABLISHED, | ||
548 | .procname = "ip_conntrack_sctp_timeout_established", | ||
549 | .data = &ip_ct_sctp_timeout_established, | ||
550 | .maxlen = sizeof(unsigned int), | ||
551 | .mode = 0644, | ||
552 | .proc_handler = &proc_dointvec_jiffies, | ||
553 | }, | ||
554 | { | ||
555 | .ctl_name = NET_IPV4_NF_CONNTRACK_SCTP_TIMEOUT_SHUTDOWN_SENT, | ||
556 | .procname = "ip_conntrack_sctp_timeout_shutdown_sent", | ||
557 | .data = &ip_ct_sctp_timeout_shutdown_sent, | ||
558 | .maxlen = sizeof(unsigned int), | ||
559 | .mode = 0644, | ||
560 | .proc_handler = &proc_dointvec_jiffies, | ||
561 | }, | ||
562 | { | ||
563 | .ctl_name = NET_IPV4_NF_CONNTRACK_SCTP_TIMEOUT_SHUTDOWN_RECD, | ||
564 | .procname = "ip_conntrack_sctp_timeout_shutdown_recd", | ||
565 | .data = &ip_ct_sctp_timeout_shutdown_recd, | ||
566 | .maxlen = sizeof(unsigned int), | ||
567 | .mode = 0644, | ||
568 | .proc_handler = &proc_dointvec_jiffies, | ||
569 | }, | ||
570 | { | ||
571 | .ctl_name = NET_IPV4_NF_CONNTRACK_SCTP_TIMEOUT_SHUTDOWN_ACK_SENT, | ||
572 | .procname = "ip_conntrack_sctp_timeout_shutdown_ack_sent", | ||
573 | .data = &ip_ct_sctp_timeout_shutdown_ack_sent, | ||
574 | .maxlen = sizeof(unsigned int), | ||
575 | .mode = 0644, | ||
576 | .proc_handler = &proc_dointvec_jiffies, | ||
577 | }, | ||
578 | { .ctl_name = 0 } | ||
579 | }; | ||
580 | |||
581 | static ctl_table ip_ct_netfilter_table[] = { | ||
582 | { | ||
583 | .ctl_name = NET_IPV4_NETFILTER, | ||
584 | .procname = "netfilter", | ||
585 | .mode = 0555, | ||
586 | .child = ip_ct_sysctl_table, | ||
587 | }, | ||
588 | { .ctl_name = 0 } | ||
589 | }; | ||
590 | |||
591 | static ctl_table ip_ct_ipv4_table[] = { | ||
592 | { | ||
593 | .ctl_name = NET_IPV4, | ||
594 | .procname = "ipv4", | ||
595 | .mode = 0555, | ||
596 | .child = ip_ct_netfilter_table, | ||
597 | }, | ||
598 | { .ctl_name = 0 } | ||
599 | }; | ||
600 | |||
601 | static ctl_table ip_ct_net_table[] = { | ||
602 | { | ||
603 | .ctl_name = CTL_NET, | ||
604 | .procname = "net", | ||
605 | .mode = 0555, | ||
606 | .child = ip_ct_ipv4_table, | ||
607 | }, | ||
608 | { .ctl_name = 0 } | ||
609 | }; | ||
610 | |||
611 | static struct ctl_table_header *ip_ct_sysctl_header; | ||
612 | #endif | ||
613 | |||
614 | static int __init ip_conntrack_proto_sctp_init(void) | ||
615 | { | ||
616 | int ret; | ||
617 | |||
618 | ret = ip_conntrack_protocol_register(&ip_conntrack_protocol_sctp); | ||
619 | if (ret) { | ||
620 | printk("ip_conntrack_proto_sctp: protocol register failed\n"); | ||
621 | goto out; | ||
622 | } | ||
623 | |||
624 | #ifdef CONFIG_SYSCTL | ||
625 | ip_ct_sysctl_header = register_sysctl_table(ip_ct_net_table); | ||
626 | if (ip_ct_sysctl_header == NULL) { | ||
627 | ret = -ENOMEM; | ||
628 | printk("ip_conntrack_proto_sctp: can't register to sysctl.\n"); | ||
629 | goto cleanup; | ||
630 | } | ||
631 | #endif | ||
632 | |||
633 | return ret; | ||
634 | |||
635 | #ifdef CONFIG_SYSCTL | ||
636 | cleanup: | ||
637 | ip_conntrack_protocol_unregister(&ip_conntrack_protocol_sctp); | ||
638 | #endif | ||
639 | out: | ||
640 | DEBUGP("SCTP conntrack module loading %s\n", | ||
641 | ret ? "failed": "succeeded"); | ||
642 | return ret; | ||
643 | } | ||
644 | |||
645 | static void __exit ip_conntrack_proto_sctp_fini(void) | ||
646 | { | ||
647 | ip_conntrack_protocol_unregister(&ip_conntrack_protocol_sctp); | ||
648 | #ifdef CONFIG_SYSCTL | ||
649 | unregister_sysctl_table(ip_ct_sysctl_header); | ||
650 | #endif | ||
651 | DEBUGP("SCTP conntrack module unloaded\n"); | ||
652 | } | ||
653 | |||
654 | module_init(ip_conntrack_proto_sctp_init); | ||
655 | module_exit(ip_conntrack_proto_sctp_fini); | ||
656 | |||
657 | MODULE_LICENSE("GPL"); | ||
658 | MODULE_AUTHOR("Kiran Kumar Immidi"); | ||
659 | MODULE_DESCRIPTION("Netfilter connection tracking protocol helper for SCTP"); | ||
diff --git a/net/ipv4/netfilter/ip_conntrack_proto_tcp.c b/net/ipv4/netfilter/ip_conntrack_proto_tcp.c deleted file mode 100644 index d03436edfd93..000000000000 --- a/net/ipv4/netfilter/ip_conntrack_proto_tcp.c +++ /dev/null | |||
@@ -1,1163 +0,0 @@ | |||
1 | /* (C) 1999-2001 Paul `Rusty' Russell | ||
2 | * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | * | ||
8 | * Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>: | ||
9 | * - Real stateful connection tracking | ||
10 | * - Modified state transitions table | ||
11 | * - Window scaling support added | ||
12 | * - SACK support added | ||
13 | * | ||
14 | * Willy Tarreau: | ||
15 | * - State table bugfixes | ||
16 | * - More robust state changes | ||
17 | * - Tuning timer parameters | ||
18 | * | ||
19 | * version 2.2 | ||
20 | */ | ||
21 | |||
22 | #include <linux/types.h> | ||
23 | #include <linux/timer.h> | ||
24 | #include <linux/netfilter.h> | ||
25 | #include <linux/module.h> | ||
26 | #include <linux/in.h> | ||
27 | #include <linux/ip.h> | ||
28 | #include <linux/tcp.h> | ||
29 | #include <linux/spinlock.h> | ||
30 | |||
31 | #include <net/tcp.h> | ||
32 | |||
33 | #include <linux/netfilter_ipv4.h> | ||
34 | #include <linux/netfilter_ipv4/ip_conntrack.h> | ||
35 | #include <linux/netfilter_ipv4/ip_conntrack_protocol.h> | ||
36 | |||
37 | #if 0 | ||
38 | #define DEBUGP printk | ||
39 | #define DEBUGP_VARS | ||
40 | #else | ||
41 | #define DEBUGP(format, args...) | ||
42 | #endif | ||
43 | |||
44 | /* Protects conntrack->proto.tcp */ | ||
45 | static DEFINE_RWLOCK(tcp_lock); | ||
46 | |||
47 | /* "Be conservative in what you do, | ||
48 | be liberal in what you accept from others." | ||
49 | If it's non-zero, we mark only out of window RST segments as INVALID. */ | ||
50 | int ip_ct_tcp_be_liberal __read_mostly = 0; | ||
51 | |||
52 | /* If it is set to zero, we disable picking up already established | ||
53 | connections. */ | ||
54 | int ip_ct_tcp_loose __read_mostly = 1; | ||
55 | |||
56 | /* Max number of the retransmitted packets without receiving an (acceptable) | ||
57 | ACK from the destination. If this number is reached, a shorter timer | ||
58 | will be started. */ | ||
59 | int ip_ct_tcp_max_retrans __read_mostly = 3; | ||
60 | |||
61 | /* FIXME: Examine ipfilter's timeouts and conntrack transitions more | ||
62 | closely. They're more complex. --RR */ | ||
63 | |||
64 | static const char *tcp_conntrack_names[] = { | ||
65 | "NONE", | ||
66 | "SYN_SENT", | ||
67 | "SYN_RECV", | ||
68 | "ESTABLISHED", | ||
69 | "FIN_WAIT", | ||
70 | "CLOSE_WAIT", | ||
71 | "LAST_ACK", | ||
72 | "TIME_WAIT", | ||
73 | "CLOSE", | ||
74 | "LISTEN" | ||
75 | }; | ||
76 | |||
77 | #define SECS * HZ | ||
78 | #define MINS * 60 SECS | ||
79 | #define HOURS * 60 MINS | ||
80 | #define DAYS * 24 HOURS | ||
81 | |||
82 | unsigned int ip_ct_tcp_timeout_syn_sent __read_mostly = 2 MINS; | ||
83 | unsigned int ip_ct_tcp_timeout_syn_recv __read_mostly = 60 SECS; | ||
84 | unsigned int ip_ct_tcp_timeout_established __read_mostly = 5 DAYS; | ||
85 | unsigned int ip_ct_tcp_timeout_fin_wait __read_mostly = 2 MINS; | ||
86 | unsigned int ip_ct_tcp_timeout_close_wait __read_mostly = 60 SECS; | ||
87 | unsigned int ip_ct_tcp_timeout_last_ack __read_mostly = 30 SECS; | ||
88 | unsigned int ip_ct_tcp_timeout_time_wait __read_mostly = 2 MINS; | ||
89 | unsigned int ip_ct_tcp_timeout_close __read_mostly = 10 SECS; | ||
90 | |||
91 | /* RFC1122 says the R2 limit should be at least 100 seconds. | ||
92 | Linux uses 15 packets as limit, which corresponds | ||
93 | to ~13-30min depending on RTO. */ | ||
94 | unsigned int ip_ct_tcp_timeout_max_retrans __read_mostly = 5 MINS; | ||
95 | |||
96 | static const unsigned int * tcp_timeouts[] | ||
97 | = { NULL, /* TCP_CONNTRACK_NONE */ | ||
98 | &ip_ct_tcp_timeout_syn_sent, /* TCP_CONNTRACK_SYN_SENT, */ | ||
99 | &ip_ct_tcp_timeout_syn_recv, /* TCP_CONNTRACK_SYN_RECV, */ | ||
100 | &ip_ct_tcp_timeout_established, /* TCP_CONNTRACK_ESTABLISHED, */ | ||
101 | &ip_ct_tcp_timeout_fin_wait, /* TCP_CONNTRACK_FIN_WAIT, */ | ||
102 | &ip_ct_tcp_timeout_close_wait, /* TCP_CONNTRACK_CLOSE_WAIT, */ | ||
103 | &ip_ct_tcp_timeout_last_ack, /* TCP_CONNTRACK_LAST_ACK, */ | ||
104 | &ip_ct_tcp_timeout_time_wait, /* TCP_CONNTRACK_TIME_WAIT, */ | ||
105 | &ip_ct_tcp_timeout_close, /* TCP_CONNTRACK_CLOSE, */ | ||
106 | NULL, /* TCP_CONNTRACK_LISTEN */ | ||
107 | }; | ||
108 | |||
109 | #define sNO TCP_CONNTRACK_NONE | ||
110 | #define sSS TCP_CONNTRACK_SYN_SENT | ||
111 | #define sSR TCP_CONNTRACK_SYN_RECV | ||
112 | #define sES TCP_CONNTRACK_ESTABLISHED | ||
113 | #define sFW TCP_CONNTRACK_FIN_WAIT | ||
114 | #define sCW TCP_CONNTRACK_CLOSE_WAIT | ||
115 | #define sLA TCP_CONNTRACK_LAST_ACK | ||
116 | #define sTW TCP_CONNTRACK_TIME_WAIT | ||
117 | #define sCL TCP_CONNTRACK_CLOSE | ||
118 | #define sLI TCP_CONNTRACK_LISTEN | ||
119 | #define sIV TCP_CONNTRACK_MAX | ||
120 | #define sIG TCP_CONNTRACK_IGNORE | ||
121 | |||
122 | /* What TCP flags are set from RST/SYN/FIN/ACK. */ | ||
123 | enum tcp_bit_set { | ||
124 | TCP_SYN_SET, | ||
125 | TCP_SYNACK_SET, | ||
126 | TCP_FIN_SET, | ||
127 | TCP_ACK_SET, | ||
128 | TCP_RST_SET, | ||
129 | TCP_NONE_SET, | ||
130 | }; | ||
131 | |||
132 | /* | ||
133 | * The TCP state transition table needs a few words... | ||
134 | * | ||
135 | * We are the man in the middle. All the packets go through us | ||
136 | * but might get lost in transit to the destination. | ||
137 | * It is assumed that the destinations can't receive segments | ||
138 | * we haven't seen. | ||
139 | * | ||
140 | * The checked segment is in window, but our windows are *not* | ||
141 | * equivalent with the ones of the sender/receiver. We always | ||
142 | * try to guess the state of the current sender. | ||
143 | * | ||
144 | * The meaning of the states are: | ||
145 | * | ||
146 | * NONE: initial state | ||
147 | * SYN_SENT: SYN-only packet seen | ||
148 | * SYN_RECV: SYN-ACK packet seen | ||
149 | * ESTABLISHED: ACK packet seen | ||
150 | * FIN_WAIT: FIN packet seen | ||
151 | * CLOSE_WAIT: ACK seen (after FIN) | ||
152 | * LAST_ACK: FIN seen (after FIN) | ||
153 | * TIME_WAIT: last ACK seen | ||
154 | * CLOSE: closed connection | ||
155 | * | ||
156 | * LISTEN state is not used. | ||
157 | * | ||
158 | * Packets marked as IGNORED (sIG): | ||
159 | * if they may be either invalid or valid | ||
160 | * and the receiver may send back a connection | ||
161 | * closing RST or a SYN/ACK. | ||
162 | * | ||
163 | * Packets marked as INVALID (sIV): | ||
164 | * if they are invalid | ||
165 | * or we do not support the request (simultaneous open) | ||
166 | */ | ||
167 | static const enum tcp_conntrack tcp_conntracks[2][6][TCP_CONNTRACK_MAX] = { | ||
168 | { | ||
169 | /* ORIGINAL */ | ||
170 | /* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sLI */ | ||
171 | /*syn*/ { sSS, sSS, sIG, sIG, sIG, sIG, sIG, sSS, sSS, sIV }, | ||
172 | /* | ||
173 | * sNO -> sSS Initialize a new connection | ||
174 | * sSS -> sSS Retransmitted SYN | ||
175 | * sSR -> sIG Late retransmitted SYN? | ||
176 | * sES -> sIG Error: SYNs in window outside the SYN_SENT state | ||
177 | * are errors. Receiver will reply with RST | ||
178 | * and close the connection. | ||
179 | * Or we are not in sync and hold a dead connection. | ||
180 | * sFW -> sIG | ||
181 | * sCW -> sIG | ||
182 | * sLA -> sIG | ||
183 | * sTW -> sSS Reopened connection (RFC 1122). | ||
184 | * sCL -> sSS | ||
185 | */ | ||
186 | /* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sLI */ | ||
187 | /*synack*/ { sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV }, | ||
188 | /* | ||
189 | * A SYN/ACK from the client is always invalid: | ||
190 | * - either it tries to set up a simultaneous open, which is | ||
191 | * not supported; | ||
192 | * - or the firewall has just been inserted between the two hosts | ||
193 | * during the session set-up. The SYN will be retransmitted | ||
194 | * by the true client (or it'll time out). | ||
195 | */ | ||
196 | /* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sLI */ | ||
197 | /*fin*/ { sIV, sIV, sFW, sFW, sLA, sLA, sLA, sTW, sCL, sIV }, | ||
198 | /* | ||
199 | * sNO -> sIV Too late and no reason to do anything... | ||
200 | * sSS -> sIV Client migth not send FIN in this state: | ||
201 | * we enforce waiting for a SYN/ACK reply first. | ||
202 | * sSR -> sFW Close started. | ||
203 | * sES -> sFW | ||
204 | * sFW -> sLA FIN seen in both directions, waiting for | ||
205 | * the last ACK. | ||
206 | * Migth be a retransmitted FIN as well... | ||
207 | * sCW -> sLA | ||
208 | * sLA -> sLA Retransmitted FIN. Remain in the same state. | ||
209 | * sTW -> sTW | ||
210 | * sCL -> sCL | ||
211 | */ | ||
212 | /* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sLI */ | ||
213 | /*ack*/ { sES, sIV, sES, sES, sCW, sCW, sTW, sTW, sCL, sIV }, | ||
214 | /* | ||
215 | * sNO -> sES Assumed. | ||
216 | * sSS -> sIV ACK is invalid: we haven't seen a SYN/ACK yet. | ||
217 | * sSR -> sES Established state is reached. | ||
218 | * sES -> sES :-) | ||
219 | * sFW -> sCW Normal close request answered by ACK. | ||
220 | * sCW -> sCW | ||
221 | * sLA -> sTW Last ACK detected. | ||
222 | * sTW -> sTW Retransmitted last ACK. Remain in the same state. | ||
223 | * sCL -> sCL | ||
224 | */ | ||
225 | /* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sLI */ | ||
226 | /*rst*/ { sIV, sCL, sCL, sCL, sCL, sCL, sCL, sCL, sCL, sIV }, | ||
227 | /*none*/ { sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV } | ||
228 | }, | ||
229 | { | ||
230 | /* REPLY */ | ||
231 | /* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sLI */ | ||
232 | /*syn*/ { sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV }, | ||
233 | /* | ||
234 | * sNO -> sIV Never reached. | ||
235 | * sSS -> sIV Simultaneous open, not supported | ||
236 | * sSR -> sIV Simultaneous open, not supported. | ||
237 | * sES -> sIV Server may not initiate a connection. | ||
238 | * sFW -> sIV | ||
239 | * sCW -> sIV | ||
240 | * sLA -> sIV | ||
241 | * sTW -> sIV Reopened connection, but server may not do it. | ||
242 | * sCL -> sIV | ||
243 | */ | ||
244 | /* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sLI */ | ||
245 | /*synack*/ { sIV, sSR, sSR, sIG, sIG, sIG, sIG, sIG, sIG, sIV }, | ||
246 | /* | ||
247 | * sSS -> sSR Standard open. | ||
248 | * sSR -> sSR Retransmitted SYN/ACK. | ||
249 | * sES -> sIG Late retransmitted SYN/ACK? | ||
250 | * sFW -> sIG Might be SYN/ACK answering ignored SYN | ||
251 | * sCW -> sIG | ||
252 | * sLA -> sIG | ||
253 | * sTW -> sIG | ||
254 | * sCL -> sIG | ||
255 | */ | ||
256 | /* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sLI */ | ||
257 | /*fin*/ { sIV, sIV, sFW, sFW, sLA, sLA, sLA, sTW, sCL, sIV }, | ||
258 | /* | ||
259 | * sSS -> sIV Server might not send FIN in this state. | ||
260 | * sSR -> sFW Close started. | ||
261 | * sES -> sFW | ||
262 | * sFW -> sLA FIN seen in both directions. | ||
263 | * sCW -> sLA | ||
264 | * sLA -> sLA Retransmitted FIN. | ||
265 | * sTW -> sTW | ||
266 | * sCL -> sCL | ||
267 | */ | ||
268 | /* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sLI */ | ||
269 | /*ack*/ { sIV, sIG, sSR, sES, sCW, sCW, sTW, sTW, sCL, sIV }, | ||
270 | /* | ||
271 | * sSS -> sIG Might be a half-open connection. | ||
272 | * sSR -> sSR Might answer late resent SYN. | ||
273 | * sES -> sES :-) | ||
274 | * sFW -> sCW Normal close request answered by ACK. | ||
275 | * sCW -> sCW | ||
276 | * sLA -> sTW Last ACK detected. | ||
277 | * sTW -> sTW Retransmitted last ACK. | ||
278 | * sCL -> sCL | ||
279 | */ | ||
280 | /* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sLI */ | ||
281 | /*rst*/ { sIV, sCL, sCL, sCL, sCL, sCL, sCL, sCL, sCL, sIV }, | ||
282 | /*none*/ { sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV } | ||
283 | } | ||
284 | }; | ||
285 | |||
286 | static int tcp_pkt_to_tuple(const struct sk_buff *skb, | ||
287 | unsigned int dataoff, | ||
288 | struct ip_conntrack_tuple *tuple) | ||
289 | { | ||
290 | struct tcphdr _hdr, *hp; | ||
291 | |||
292 | /* Actually only need first 8 bytes. */ | ||
293 | hp = skb_header_pointer(skb, dataoff, 8, &_hdr); | ||
294 | if (hp == NULL) | ||
295 | return 0; | ||
296 | |||
297 | tuple->src.u.tcp.port = hp->source; | ||
298 | tuple->dst.u.tcp.port = hp->dest; | ||
299 | |||
300 | return 1; | ||
301 | } | ||
302 | |||
303 | static int tcp_invert_tuple(struct ip_conntrack_tuple *tuple, | ||
304 | const struct ip_conntrack_tuple *orig) | ||
305 | { | ||
306 | tuple->src.u.tcp.port = orig->dst.u.tcp.port; | ||
307 | tuple->dst.u.tcp.port = orig->src.u.tcp.port; | ||
308 | return 1; | ||
309 | } | ||
310 | |||
311 | /* Print out the per-protocol part of the tuple. */ | ||
312 | static int tcp_print_tuple(struct seq_file *s, | ||
313 | const struct ip_conntrack_tuple *tuple) | ||
314 | { | ||
315 | return seq_printf(s, "sport=%hu dport=%hu ", | ||
316 | ntohs(tuple->src.u.tcp.port), | ||
317 | ntohs(tuple->dst.u.tcp.port)); | ||
318 | } | ||
319 | |||
320 | /* Print out the private part of the conntrack. */ | ||
321 | static int tcp_print_conntrack(struct seq_file *s, | ||
322 | const struct ip_conntrack *conntrack) | ||
323 | { | ||
324 | enum tcp_conntrack state; | ||
325 | |||
326 | read_lock_bh(&tcp_lock); | ||
327 | state = conntrack->proto.tcp.state; | ||
328 | read_unlock_bh(&tcp_lock); | ||
329 | |||
330 | return seq_printf(s, "%s ", tcp_conntrack_names[state]); | ||
331 | } | ||
332 | |||
333 | #if defined(CONFIG_IP_NF_CONNTRACK_NETLINK) || \ | ||
334 | defined(CONFIG_IP_NF_CONNTRACK_NETLINK_MODULE) | ||
335 | static int tcp_to_nfattr(struct sk_buff *skb, struct nfattr *nfa, | ||
336 | const struct ip_conntrack *ct) | ||
337 | { | ||
338 | struct nfattr *nest_parms; | ||
339 | |||
340 | read_lock_bh(&tcp_lock); | ||
341 | nest_parms = NFA_NEST(skb, CTA_PROTOINFO_TCP); | ||
342 | NFA_PUT(skb, CTA_PROTOINFO_TCP_STATE, sizeof(u_int8_t), | ||
343 | &ct->proto.tcp.state); | ||
344 | read_unlock_bh(&tcp_lock); | ||
345 | |||
346 | NFA_NEST_END(skb, nest_parms); | ||
347 | |||
348 | return 0; | ||
349 | |||
350 | nfattr_failure: | ||
351 | read_unlock_bh(&tcp_lock); | ||
352 | return -1; | ||
353 | } | ||
354 | |||
355 | static const size_t cta_min_tcp[CTA_PROTOINFO_TCP_MAX] = { | ||
356 | [CTA_PROTOINFO_TCP_STATE-1] = sizeof(u_int8_t), | ||
357 | }; | ||
358 | |||
359 | static int nfattr_to_tcp(struct nfattr *cda[], struct ip_conntrack *ct) | ||
360 | { | ||
361 | struct nfattr *attr = cda[CTA_PROTOINFO_TCP-1]; | ||
362 | struct nfattr *tb[CTA_PROTOINFO_TCP_MAX]; | ||
363 | |||
364 | /* updates could not contain anything about the private | ||
365 | * protocol info, in that case skip the parsing */ | ||
366 | if (!attr) | ||
367 | return 0; | ||
368 | |||
369 | nfattr_parse_nested(tb, CTA_PROTOINFO_TCP_MAX, attr); | ||
370 | |||
371 | if (nfattr_bad_size(tb, CTA_PROTOINFO_TCP_MAX, cta_min_tcp)) | ||
372 | return -EINVAL; | ||
373 | |||
374 | if (!tb[CTA_PROTOINFO_TCP_STATE-1]) | ||
375 | return -EINVAL; | ||
376 | |||
377 | write_lock_bh(&tcp_lock); | ||
378 | ct->proto.tcp.state = | ||
379 | *(u_int8_t *)NFA_DATA(tb[CTA_PROTOINFO_TCP_STATE-1]); | ||
380 | write_unlock_bh(&tcp_lock); | ||
381 | |||
382 | return 0; | ||
383 | } | ||
384 | #endif | ||
385 | |||
386 | static unsigned int get_conntrack_index(const struct tcphdr *tcph) | ||
387 | { | ||
388 | if (tcph->rst) return TCP_RST_SET; | ||
389 | else if (tcph->syn) return (tcph->ack ? TCP_SYNACK_SET : TCP_SYN_SET); | ||
390 | else if (tcph->fin) return TCP_FIN_SET; | ||
391 | else if (tcph->ack) return TCP_ACK_SET; | ||
392 | else return TCP_NONE_SET; | ||
393 | } | ||
394 | |||
395 | /* TCP connection tracking based on 'Real Stateful TCP Packet Filtering | ||
396 | in IP Filter' by Guido van Rooij. | ||
397 | |||
398 | http://www.nluug.nl/events/sane2000/papers.html | ||
399 | http://www.iae.nl/users/guido/papers/tcp_filtering.ps.gz | ||
400 | |||
401 | The boundaries and the conditions are changed according to RFC793: | ||
402 | the packet must intersect the window (i.e. segments may be | ||
403 | after the right or before the left edge) and thus receivers may ACK | ||
404 | segments after the right edge of the window. | ||
405 | |||
406 | td_maxend = max(sack + max(win,1)) seen in reply packets | ||
407 | td_maxwin = max(max(win, 1)) + (sack - ack) seen in sent packets | ||
408 | td_maxwin += seq + len - sender.td_maxend | ||
409 | if seq + len > sender.td_maxend | ||
410 | td_end = max(seq + len) seen in sent packets | ||
411 | |||
412 | I. Upper bound for valid data: seq <= sender.td_maxend | ||
413 | II. Lower bound for valid data: seq + len >= sender.td_end - receiver.td_maxwin | ||
414 | III. Upper bound for valid ack: sack <= receiver.td_end | ||
415 | IV. Lower bound for valid ack: ack >= receiver.td_end - MAXACKWINDOW | ||
416 | |||
417 | where sack is the highest right edge of sack block found in the packet. | ||
418 | |||
419 | The upper bound limit for a valid ack is not ignored - | ||
420 | we doesn't have to deal with fragments. | ||
421 | */ | ||
422 | |||
423 | static inline __u32 segment_seq_plus_len(__u32 seq, | ||
424 | size_t len, | ||
425 | struct iphdr *iph, | ||
426 | struct tcphdr *tcph) | ||
427 | { | ||
428 | return (seq + len - (iph->ihl + tcph->doff)*4 | ||
429 | + (tcph->syn ? 1 : 0) + (tcph->fin ? 1 : 0)); | ||
430 | } | ||
431 | |||
432 | /* Fixme: what about big packets? */ | ||
433 | #define MAXACKWINCONST 66000 | ||
434 | #define MAXACKWINDOW(sender) \ | ||
435 | ((sender)->td_maxwin > MAXACKWINCONST ? (sender)->td_maxwin \ | ||
436 | : MAXACKWINCONST) | ||
437 | |||
438 | /* | ||
439 | * Simplified tcp_parse_options routine from tcp_input.c | ||
440 | */ | ||
441 | static void tcp_options(const struct sk_buff *skb, | ||
442 | struct iphdr *iph, | ||
443 | struct tcphdr *tcph, | ||
444 | struct ip_ct_tcp_state *state) | ||
445 | { | ||
446 | unsigned char buff[(15 * 4) - sizeof(struct tcphdr)]; | ||
447 | unsigned char *ptr; | ||
448 | int length = (tcph->doff*4) - sizeof(struct tcphdr); | ||
449 | |||
450 | if (!length) | ||
451 | return; | ||
452 | |||
453 | ptr = skb_header_pointer(skb, | ||
454 | (iph->ihl * 4) + sizeof(struct tcphdr), | ||
455 | length, buff); | ||
456 | BUG_ON(ptr == NULL); | ||
457 | |||
458 | state->td_scale = | ||
459 | state->flags = 0; | ||
460 | |||
461 | while (length > 0) { | ||
462 | int opcode=*ptr++; | ||
463 | int opsize; | ||
464 | |||
465 | switch (opcode) { | ||
466 | case TCPOPT_EOL: | ||
467 | return; | ||
468 | case TCPOPT_NOP: /* Ref: RFC 793 section 3.1 */ | ||
469 | length--; | ||
470 | continue; | ||
471 | default: | ||
472 | opsize=*ptr++; | ||
473 | if (opsize < 2) /* "silly options" */ | ||
474 | return; | ||
475 | if (opsize > length) | ||
476 | break; /* don't parse partial options */ | ||
477 | |||
478 | if (opcode == TCPOPT_SACK_PERM | ||
479 | && opsize == TCPOLEN_SACK_PERM) | ||
480 | state->flags |= IP_CT_TCP_FLAG_SACK_PERM; | ||
481 | else if (opcode == TCPOPT_WINDOW | ||
482 | && opsize == TCPOLEN_WINDOW) { | ||
483 | state->td_scale = *(u_int8_t *)ptr; | ||
484 | |||
485 | if (state->td_scale > 14) { | ||
486 | /* See RFC1323 */ | ||
487 | state->td_scale = 14; | ||
488 | } | ||
489 | state->flags |= | ||
490 | IP_CT_TCP_FLAG_WINDOW_SCALE; | ||
491 | } | ||
492 | ptr += opsize - 2; | ||
493 | length -= opsize; | ||
494 | } | ||
495 | } | ||
496 | } | ||
497 | |||
498 | static void tcp_sack(const struct sk_buff *skb, | ||
499 | struct iphdr *iph, | ||
500 | struct tcphdr *tcph, | ||
501 | __u32 *sack) | ||
502 | { | ||
503 | unsigned char buff[(15 * 4) - sizeof(struct tcphdr)]; | ||
504 | unsigned char *ptr; | ||
505 | int length = (tcph->doff*4) - sizeof(struct tcphdr); | ||
506 | __u32 tmp; | ||
507 | |||
508 | if (!length) | ||
509 | return; | ||
510 | |||
511 | ptr = skb_header_pointer(skb, | ||
512 | (iph->ihl * 4) + sizeof(struct tcphdr), | ||
513 | length, buff); | ||
514 | BUG_ON(ptr == NULL); | ||
515 | |||
516 | /* Fast path for timestamp-only option */ | ||
517 | if (length == TCPOLEN_TSTAMP_ALIGNED*4 | ||
518 | && *(__be32 *)ptr == htonl((TCPOPT_NOP << 24) | ||
519 | | (TCPOPT_NOP << 16) | ||
520 | | (TCPOPT_TIMESTAMP << 8) | ||
521 | | TCPOLEN_TIMESTAMP)) | ||
522 | return; | ||
523 | |||
524 | while (length > 0) { | ||
525 | int opcode=*ptr++; | ||
526 | int opsize, i; | ||
527 | |||
528 | switch (opcode) { | ||
529 | case TCPOPT_EOL: | ||
530 | return; | ||
531 | case TCPOPT_NOP: /* Ref: RFC 793 section 3.1 */ | ||
532 | length--; | ||
533 | continue; | ||
534 | default: | ||
535 | opsize=*ptr++; | ||
536 | if (opsize < 2) /* "silly options" */ | ||
537 | return; | ||
538 | if (opsize > length) | ||
539 | break; /* don't parse partial options */ | ||
540 | |||
541 | if (opcode == TCPOPT_SACK | ||
542 | && opsize >= (TCPOLEN_SACK_BASE | ||
543 | + TCPOLEN_SACK_PERBLOCK) | ||
544 | && !((opsize - TCPOLEN_SACK_BASE) | ||
545 | % TCPOLEN_SACK_PERBLOCK)) { | ||
546 | for (i = 0; | ||
547 | i < (opsize - TCPOLEN_SACK_BASE); | ||
548 | i += TCPOLEN_SACK_PERBLOCK) { | ||
549 | tmp = ntohl(*((__be32 *)(ptr+i)+1)); | ||
550 | |||
551 | if (after(tmp, *sack)) | ||
552 | *sack = tmp; | ||
553 | } | ||
554 | return; | ||
555 | } | ||
556 | ptr += opsize - 2; | ||
557 | length -= opsize; | ||
558 | } | ||
559 | } | ||
560 | } | ||
561 | |||
562 | static int tcp_in_window(struct ip_ct_tcp *state, | ||
563 | enum ip_conntrack_dir dir, | ||
564 | unsigned int index, | ||
565 | const struct sk_buff *skb, | ||
566 | struct iphdr *iph, | ||
567 | struct tcphdr *tcph) | ||
568 | { | ||
569 | struct ip_ct_tcp_state *sender = &state->seen[dir]; | ||
570 | struct ip_ct_tcp_state *receiver = &state->seen[!dir]; | ||
571 | __u32 seq, ack, sack, end, win, swin; | ||
572 | int res; | ||
573 | |||
574 | /* | ||
575 | * Get the required data from the packet. | ||
576 | */ | ||
577 | seq = ntohl(tcph->seq); | ||
578 | ack = sack = ntohl(tcph->ack_seq); | ||
579 | win = ntohs(tcph->window); | ||
580 | end = segment_seq_plus_len(seq, skb->len, iph, tcph); | ||
581 | |||
582 | if (receiver->flags & IP_CT_TCP_FLAG_SACK_PERM) | ||
583 | tcp_sack(skb, iph, tcph, &sack); | ||
584 | |||
585 | DEBUGP("tcp_in_window: START\n"); | ||
586 | DEBUGP("tcp_in_window: src=%u.%u.%u.%u:%hu dst=%u.%u.%u.%u:%hu " | ||
587 | "seq=%u ack=%u sack=%u win=%u end=%u\n", | ||
588 | NIPQUAD(iph->saddr), ntohs(tcph->source), | ||
589 | NIPQUAD(iph->daddr), ntohs(tcph->dest), | ||
590 | seq, ack, sack, win, end); | ||
591 | DEBUGP("tcp_in_window: sender end=%u maxend=%u maxwin=%u scale=%i " | ||
592 | "receiver end=%u maxend=%u maxwin=%u scale=%i\n", | ||
593 | sender->td_end, sender->td_maxend, sender->td_maxwin, | ||
594 | sender->td_scale, | ||
595 | receiver->td_end, receiver->td_maxend, receiver->td_maxwin, | ||
596 | receiver->td_scale); | ||
597 | |||
598 | if (sender->td_end == 0) { | ||
599 | /* | ||
600 | * Initialize sender data. | ||
601 | */ | ||
602 | if (tcph->syn && tcph->ack) { | ||
603 | /* | ||
604 | * Outgoing SYN-ACK in reply to a SYN. | ||
605 | */ | ||
606 | sender->td_end = | ||
607 | sender->td_maxend = end; | ||
608 | sender->td_maxwin = (win == 0 ? 1 : win); | ||
609 | |||
610 | tcp_options(skb, iph, tcph, sender); | ||
611 | /* | ||
612 | * RFC 1323: | ||
613 | * Both sides must send the Window Scale option | ||
614 | * to enable window scaling in either direction. | ||
615 | */ | ||
616 | if (!(sender->flags & IP_CT_TCP_FLAG_WINDOW_SCALE | ||
617 | && receiver->flags & IP_CT_TCP_FLAG_WINDOW_SCALE)) | ||
618 | sender->td_scale = | ||
619 | receiver->td_scale = 0; | ||
620 | } else { | ||
621 | /* | ||
622 | * We are in the middle of a connection, | ||
623 | * its history is lost for us. | ||
624 | * Let's try to use the data from the packet. | ||
625 | */ | ||
626 | sender->td_end = end; | ||
627 | sender->td_maxwin = (win == 0 ? 1 : win); | ||
628 | sender->td_maxend = end + sender->td_maxwin; | ||
629 | } | ||
630 | } else if (((state->state == TCP_CONNTRACK_SYN_SENT | ||
631 | && dir == IP_CT_DIR_ORIGINAL) | ||
632 | || (state->state == TCP_CONNTRACK_SYN_RECV | ||
633 | && dir == IP_CT_DIR_REPLY)) | ||
634 | && after(end, sender->td_end)) { | ||
635 | /* | ||
636 | * RFC 793: "if a TCP is reinitialized ... then it need | ||
637 | * not wait at all; it must only be sure to use sequence | ||
638 | * numbers larger than those recently used." | ||
639 | */ | ||
640 | sender->td_end = | ||
641 | sender->td_maxend = end; | ||
642 | sender->td_maxwin = (win == 0 ? 1 : win); | ||
643 | |||
644 | tcp_options(skb, iph, tcph, sender); | ||
645 | } | ||
646 | |||
647 | if (!(tcph->ack)) { | ||
648 | /* | ||
649 | * If there is no ACK, just pretend it was set and OK. | ||
650 | */ | ||
651 | ack = sack = receiver->td_end; | ||
652 | } else if (((tcp_flag_word(tcph) & (TCP_FLAG_ACK|TCP_FLAG_RST)) == | ||
653 | (TCP_FLAG_ACK|TCP_FLAG_RST)) | ||
654 | && (ack == 0)) { | ||
655 | /* | ||
656 | * Broken TCP stacks, that set ACK in RST packets as well | ||
657 | * with zero ack value. | ||
658 | */ | ||
659 | ack = sack = receiver->td_end; | ||
660 | } | ||
661 | |||
662 | if (seq == end | ||
663 | && (!tcph->rst | ||
664 | || (seq == 0 && state->state == TCP_CONNTRACK_SYN_SENT))) | ||
665 | /* | ||
666 | * Packets contains no data: we assume it is valid | ||
667 | * and check the ack value only. | ||
668 | * However RST segments are always validated by their | ||
669 | * SEQ number, except when seq == 0 (reset sent answering | ||
670 | * SYN. | ||
671 | */ | ||
672 | seq = end = sender->td_end; | ||
673 | |||
674 | DEBUGP("tcp_in_window: src=%u.%u.%u.%u:%hu dst=%u.%u.%u.%u:%hu " | ||
675 | "seq=%u ack=%u sack =%u win=%u end=%u\n", | ||
676 | NIPQUAD(iph->saddr), ntohs(tcph->source), | ||
677 | NIPQUAD(iph->daddr), ntohs(tcph->dest), | ||
678 | seq, ack, sack, win, end); | ||
679 | DEBUGP("tcp_in_window: sender end=%u maxend=%u maxwin=%u scale=%i " | ||
680 | "receiver end=%u maxend=%u maxwin=%u scale=%i\n", | ||
681 | sender->td_end, sender->td_maxend, sender->td_maxwin, | ||
682 | sender->td_scale, | ||
683 | receiver->td_end, receiver->td_maxend, receiver->td_maxwin, | ||
684 | receiver->td_scale); | ||
685 | |||
686 | DEBUGP("tcp_in_window: I=%i II=%i III=%i IV=%i\n", | ||
687 | before(seq, sender->td_maxend + 1), | ||
688 | after(end, sender->td_end - receiver->td_maxwin - 1), | ||
689 | before(sack, receiver->td_end + 1), | ||
690 | after(ack, receiver->td_end - MAXACKWINDOW(sender))); | ||
691 | |||
692 | if (before(seq, sender->td_maxend + 1) && | ||
693 | after(end, sender->td_end - receiver->td_maxwin - 1) && | ||
694 | before(sack, receiver->td_end + 1) && | ||
695 | after(ack, receiver->td_end - MAXACKWINDOW(sender))) { | ||
696 | /* | ||
697 | * Take into account window scaling (RFC 1323). | ||
698 | */ | ||
699 | if (!tcph->syn) | ||
700 | win <<= sender->td_scale; | ||
701 | |||
702 | /* | ||
703 | * Update sender data. | ||
704 | */ | ||
705 | swin = win + (sack - ack); | ||
706 | if (sender->td_maxwin < swin) | ||
707 | sender->td_maxwin = swin; | ||
708 | if (after(end, sender->td_end)) | ||
709 | sender->td_end = end; | ||
710 | /* | ||
711 | * Update receiver data. | ||
712 | */ | ||
713 | if (after(end, sender->td_maxend)) | ||
714 | receiver->td_maxwin += end - sender->td_maxend; | ||
715 | if (after(sack + win, receiver->td_maxend - 1)) { | ||
716 | receiver->td_maxend = sack + win; | ||
717 | if (win == 0) | ||
718 | receiver->td_maxend++; | ||
719 | } | ||
720 | |||
721 | /* | ||
722 | * Check retransmissions. | ||
723 | */ | ||
724 | if (index == TCP_ACK_SET) { | ||
725 | if (state->last_dir == dir | ||
726 | && state->last_seq == seq | ||
727 | && state->last_ack == ack | ||
728 | && state->last_end == end | ||
729 | && state->last_win == win) | ||
730 | state->retrans++; | ||
731 | else { | ||
732 | state->last_dir = dir; | ||
733 | state->last_seq = seq; | ||
734 | state->last_ack = ack; | ||
735 | state->last_end = end; | ||
736 | state->last_win = win; | ||
737 | state->retrans = 0; | ||
738 | } | ||
739 | } | ||
740 | res = 1; | ||
741 | } else { | ||
742 | res = 0; | ||
743 | if (sender->flags & IP_CT_TCP_FLAG_BE_LIBERAL || | ||
744 | ip_ct_tcp_be_liberal) | ||
745 | res = 1; | ||
746 | if (!res && LOG_INVALID(IPPROTO_TCP)) | ||
747 | nf_log_packet(PF_INET, 0, skb, NULL, NULL, NULL, | ||
748 | "ip_ct_tcp: %s ", | ||
749 | before(seq, sender->td_maxend + 1) ? | ||
750 | after(end, sender->td_end - receiver->td_maxwin - 1) ? | ||
751 | before(sack, receiver->td_end + 1) ? | ||
752 | after(ack, receiver->td_end - MAXACKWINDOW(sender)) ? "BUG" | ||
753 | : "ACK is under the lower bound (possible overly delayed ACK)" | ||
754 | : "ACK is over the upper bound (ACKed data not seen yet)" | ||
755 | : "SEQ is under the lower bound (already ACKed data retransmitted)" | ||
756 | : "SEQ is over the upper bound (over the window of the receiver)"); | ||
757 | } | ||
758 | |||
759 | DEBUGP("tcp_in_window: res=%i sender end=%u maxend=%u maxwin=%u " | ||
760 | "receiver end=%u maxend=%u maxwin=%u\n", | ||
761 | res, sender->td_end, sender->td_maxend, sender->td_maxwin, | ||
762 | receiver->td_end, receiver->td_maxend, receiver->td_maxwin); | ||
763 | |||
764 | return res; | ||
765 | } | ||
766 | |||
767 | #ifdef CONFIG_IP_NF_NAT_NEEDED | ||
768 | /* Update sender->td_end after NAT successfully mangled the packet */ | ||
769 | void ip_conntrack_tcp_update(struct sk_buff *skb, | ||
770 | struct ip_conntrack *conntrack, | ||
771 | enum ip_conntrack_dir dir) | ||
772 | { | ||
773 | struct iphdr *iph = ip_hdr(skb); | ||
774 | struct tcphdr *tcph = (void *)iph + ip_hdrlen(skb); | ||
775 | __u32 end; | ||
776 | #ifdef DEBUGP_VARS | ||
777 | struct ip_ct_tcp_state *sender = &conntrack->proto.tcp.seen[dir]; | ||
778 | struct ip_ct_tcp_state *receiver = &conntrack->proto.tcp.seen[!dir]; | ||
779 | #endif | ||
780 | |||
781 | end = segment_seq_plus_len(ntohl(tcph->seq), skb->len, iph, tcph); | ||
782 | |||
783 | write_lock_bh(&tcp_lock); | ||
784 | /* | ||
785 | * We have to worry for the ack in the reply packet only... | ||
786 | */ | ||
787 | if (after(end, conntrack->proto.tcp.seen[dir].td_end)) | ||
788 | conntrack->proto.tcp.seen[dir].td_end = end; | ||
789 | conntrack->proto.tcp.last_end = end; | ||
790 | write_unlock_bh(&tcp_lock); | ||
791 | DEBUGP("tcp_update: sender end=%u maxend=%u maxwin=%u scale=%i " | ||
792 | "receiver end=%u maxend=%u maxwin=%u scale=%i\n", | ||
793 | sender->td_end, sender->td_maxend, sender->td_maxwin, | ||
794 | sender->td_scale, | ||
795 | receiver->td_end, receiver->td_maxend, receiver->td_maxwin, | ||
796 | receiver->td_scale); | ||
797 | } | ||
798 | |||
799 | #endif | ||
800 | |||
801 | #define TH_FIN 0x01 | ||
802 | #define TH_SYN 0x02 | ||
803 | #define TH_RST 0x04 | ||
804 | #define TH_PUSH 0x08 | ||
805 | #define TH_ACK 0x10 | ||
806 | #define TH_URG 0x20 | ||
807 | #define TH_ECE 0x40 | ||
808 | #define TH_CWR 0x80 | ||
809 | |||
810 | /* table of valid flag combinations - ECE and CWR are always valid */ | ||
811 | static const u8 tcp_valid_flags[(TH_FIN|TH_SYN|TH_RST|TH_PUSH|TH_ACK|TH_URG) + 1] = | ||
812 | { | ||
813 | [TH_SYN] = 1, | ||
814 | [TH_SYN|TH_PUSH] = 1, | ||
815 | [TH_SYN|TH_URG] = 1, | ||
816 | [TH_SYN|TH_PUSH|TH_URG] = 1, | ||
817 | [TH_SYN|TH_ACK] = 1, | ||
818 | [TH_SYN|TH_ACK|TH_PUSH] = 1, | ||
819 | [TH_RST] = 1, | ||
820 | [TH_RST|TH_ACK] = 1, | ||
821 | [TH_RST|TH_ACK|TH_PUSH] = 1, | ||
822 | [TH_FIN|TH_ACK] = 1, | ||
823 | [TH_ACK] = 1, | ||
824 | [TH_ACK|TH_PUSH] = 1, | ||
825 | [TH_ACK|TH_URG] = 1, | ||
826 | [TH_ACK|TH_URG|TH_PUSH] = 1, | ||
827 | [TH_FIN|TH_ACK|TH_PUSH] = 1, | ||
828 | [TH_FIN|TH_ACK|TH_URG] = 1, | ||
829 | [TH_FIN|TH_ACK|TH_URG|TH_PUSH] = 1, | ||
830 | }; | ||
831 | |||
832 | /* Protect conntrack agaist broken packets. Code taken from ipt_unclean.c. */ | ||
833 | static int tcp_error(struct sk_buff *skb, | ||
834 | enum ip_conntrack_info *ctinfo, | ||
835 | unsigned int hooknum) | ||
836 | { | ||
837 | const unsigned int hdrlen = ip_hdrlen(skb); | ||
838 | struct tcphdr _tcph, *th; | ||
839 | unsigned int tcplen = skb->len - hdrlen; | ||
840 | u_int8_t tcpflags; | ||
841 | |||
842 | /* Smaller that minimal TCP header? */ | ||
843 | th = skb_header_pointer(skb, hdrlen, | ||
844 | sizeof(_tcph), &_tcph); | ||
845 | if (th == NULL) { | ||
846 | if (LOG_INVALID(IPPROTO_TCP)) | ||
847 | nf_log_packet(PF_INET, 0, skb, NULL, NULL, NULL, | ||
848 | "ip_ct_tcp: short packet "); | ||
849 | return -NF_ACCEPT; | ||
850 | } | ||
851 | |||
852 | /* Not whole TCP header or malformed packet */ | ||
853 | if (th->doff*4 < sizeof(struct tcphdr) || tcplen < th->doff*4) { | ||
854 | if (LOG_INVALID(IPPROTO_TCP)) | ||
855 | nf_log_packet(PF_INET, 0, skb, NULL, NULL, NULL, | ||
856 | "ip_ct_tcp: truncated/malformed packet "); | ||
857 | return -NF_ACCEPT; | ||
858 | } | ||
859 | |||
860 | /* Checksum invalid? Ignore. | ||
861 | * We skip checking packets on the outgoing path | ||
862 | * because it is assumed to be correct. | ||
863 | */ | ||
864 | /* FIXME: Source route IP option packets --RR */ | ||
865 | if (ip_conntrack_checksum && hooknum == NF_IP_PRE_ROUTING && | ||
866 | nf_ip_checksum(skb, hooknum, hdrlen, IPPROTO_TCP)) { | ||
867 | if (LOG_INVALID(IPPROTO_TCP)) | ||
868 | nf_log_packet(PF_INET, 0, skb, NULL, NULL, NULL, | ||
869 | "ip_ct_tcp: bad TCP checksum "); | ||
870 | return -NF_ACCEPT; | ||
871 | } | ||
872 | |||
873 | /* Check TCP flags. */ | ||
874 | tcpflags = (((u_int8_t *)th)[13] & ~(TH_ECE|TH_CWR)); | ||
875 | if (!tcp_valid_flags[tcpflags]) { | ||
876 | if (LOG_INVALID(IPPROTO_TCP)) | ||
877 | nf_log_packet(PF_INET, 0, skb, NULL, NULL, NULL, | ||
878 | "ip_ct_tcp: invalid TCP flag combination "); | ||
879 | return -NF_ACCEPT; | ||
880 | } | ||
881 | |||
882 | return NF_ACCEPT; | ||
883 | } | ||
884 | |||
885 | /* Returns verdict for packet, or -1 for invalid. */ | ||
886 | static int tcp_packet(struct ip_conntrack *conntrack, | ||
887 | const struct sk_buff *skb, | ||
888 | enum ip_conntrack_info ctinfo) | ||
889 | { | ||
890 | enum tcp_conntrack new_state, old_state; | ||
891 | enum ip_conntrack_dir dir; | ||
892 | struct iphdr *iph = ip_hdr(skb); | ||
893 | struct tcphdr *th, _tcph; | ||
894 | unsigned long timeout; | ||
895 | unsigned int index; | ||
896 | |||
897 | th = skb_header_pointer(skb, iph->ihl * 4, | ||
898 | sizeof(_tcph), &_tcph); | ||
899 | BUG_ON(th == NULL); | ||
900 | |||
901 | write_lock_bh(&tcp_lock); | ||
902 | old_state = conntrack->proto.tcp.state; | ||
903 | dir = CTINFO2DIR(ctinfo); | ||
904 | index = get_conntrack_index(th); | ||
905 | new_state = tcp_conntracks[dir][index][old_state]; | ||
906 | |||
907 | switch (new_state) { | ||
908 | case TCP_CONNTRACK_IGNORE: | ||
909 | /* Ignored packets: | ||
910 | * | ||
911 | * a) SYN in ORIGINAL | ||
912 | * b) SYN/ACK in REPLY | ||
913 | * c) ACK in reply direction after initial SYN in original. | ||
914 | */ | ||
915 | if (index == TCP_SYNACK_SET | ||
916 | && conntrack->proto.tcp.last_index == TCP_SYN_SET | ||
917 | && conntrack->proto.tcp.last_dir != dir | ||
918 | && ntohl(th->ack_seq) == | ||
919 | conntrack->proto.tcp.last_end) { | ||
920 | /* This SYN/ACK acknowledges a SYN that we earlier | ||
921 | * ignored as invalid. This means that the client and | ||
922 | * the server are both in sync, while the firewall is | ||
923 | * not. We kill this session and block the SYN/ACK so | ||
924 | * that the client cannot but retransmit its SYN and | ||
925 | * thus initiate a clean new session. | ||
926 | */ | ||
927 | write_unlock_bh(&tcp_lock); | ||
928 | if (LOG_INVALID(IPPROTO_TCP)) | ||
929 | nf_log_packet(PF_INET, 0, skb, NULL, NULL, | ||
930 | NULL, "ip_ct_tcp: " | ||
931 | "killing out of sync session "); | ||
932 | if (del_timer(&conntrack->timeout)) | ||
933 | conntrack->timeout.function((unsigned long) | ||
934 | conntrack); | ||
935 | return -NF_DROP; | ||
936 | } | ||
937 | conntrack->proto.tcp.last_index = index; | ||
938 | conntrack->proto.tcp.last_dir = dir; | ||
939 | conntrack->proto.tcp.last_seq = ntohl(th->seq); | ||
940 | conntrack->proto.tcp.last_end = | ||
941 | segment_seq_plus_len(ntohl(th->seq), skb->len, iph, th); | ||
942 | |||
943 | write_unlock_bh(&tcp_lock); | ||
944 | if (LOG_INVALID(IPPROTO_TCP)) | ||
945 | nf_log_packet(PF_INET, 0, skb, NULL, NULL, NULL, | ||
946 | "ip_ct_tcp: invalid packet ignored "); | ||
947 | return NF_ACCEPT; | ||
948 | case TCP_CONNTRACK_MAX: | ||
949 | /* Invalid packet */ | ||
950 | DEBUGP("ip_ct_tcp: Invalid dir=%i index=%u ostate=%u\n", | ||
951 | dir, get_conntrack_index(th), | ||
952 | old_state); | ||
953 | write_unlock_bh(&tcp_lock); | ||
954 | if (LOG_INVALID(IPPROTO_TCP)) | ||
955 | nf_log_packet(PF_INET, 0, skb, NULL, NULL, NULL, | ||
956 | "ip_ct_tcp: invalid state "); | ||
957 | return -NF_ACCEPT; | ||
958 | case TCP_CONNTRACK_SYN_SENT: | ||
959 | if (old_state < TCP_CONNTRACK_TIME_WAIT) | ||
960 | break; | ||
961 | if ((conntrack->proto.tcp.seen[dir].flags & | ||
962 | IP_CT_TCP_FLAG_CLOSE_INIT) | ||
963 | || after(ntohl(th->seq), | ||
964 | conntrack->proto.tcp.seen[dir].td_end)) { | ||
965 | /* Attempt to reopen a closed connection. | ||
966 | * Delete this connection and look up again. */ | ||
967 | write_unlock_bh(&tcp_lock); | ||
968 | if (del_timer(&conntrack->timeout)) | ||
969 | conntrack->timeout.function((unsigned long) | ||
970 | conntrack); | ||
971 | return -NF_REPEAT; | ||
972 | } else { | ||
973 | write_unlock_bh(&tcp_lock); | ||
974 | if (LOG_INVALID(IPPROTO_TCP)) | ||
975 | nf_log_packet(PF_INET, 0, skb, NULL, NULL, | ||
976 | NULL, "ip_ct_tcp: invalid SYN"); | ||
977 | return -NF_ACCEPT; | ||
978 | } | ||
979 | case TCP_CONNTRACK_CLOSE: | ||
980 | if (index == TCP_RST_SET | ||
981 | && ((test_bit(IPS_SEEN_REPLY_BIT, &conntrack->status) | ||
982 | && conntrack->proto.tcp.last_index == TCP_SYN_SET) | ||
983 | || (!test_bit(IPS_ASSURED_BIT, &conntrack->status) | ||
984 | && conntrack->proto.tcp.last_index == TCP_ACK_SET)) | ||
985 | && ntohl(th->ack_seq) == conntrack->proto.tcp.last_end) { | ||
986 | /* RST sent to invalid SYN or ACK we had let through | ||
987 | * at a) and c) above: | ||
988 | * | ||
989 | * a) SYN was in window then | ||
990 | * c) we hold a half-open connection. | ||
991 | * | ||
992 | * Delete our connection entry. | ||
993 | * We skip window checking, because packet might ACK | ||
994 | * segments we ignored. */ | ||
995 | goto in_window; | ||
996 | } | ||
997 | /* Just fall through */ | ||
998 | default: | ||
999 | /* Keep compilers happy. */ | ||
1000 | break; | ||
1001 | } | ||
1002 | |||
1003 | if (!tcp_in_window(&conntrack->proto.tcp, dir, index, | ||
1004 | skb, iph, th)) { | ||
1005 | write_unlock_bh(&tcp_lock); | ||
1006 | return -NF_ACCEPT; | ||
1007 | } | ||
1008 | in_window: | ||
1009 | /* From now on we have got in-window packets */ | ||
1010 | conntrack->proto.tcp.last_index = index; | ||
1011 | |||
1012 | DEBUGP("tcp_conntracks: src=%u.%u.%u.%u:%hu dst=%u.%u.%u.%u:%hu " | ||
1013 | "syn=%i ack=%i fin=%i rst=%i old=%i new=%i\n", | ||
1014 | NIPQUAD(iph->saddr), ntohs(th->source), | ||
1015 | NIPQUAD(iph->daddr), ntohs(th->dest), | ||
1016 | (th->syn ? 1 : 0), (th->ack ? 1 : 0), | ||
1017 | (th->fin ? 1 : 0), (th->rst ? 1 : 0), | ||
1018 | old_state, new_state); | ||
1019 | |||
1020 | conntrack->proto.tcp.state = new_state; | ||
1021 | if (old_state != new_state | ||
1022 | && (new_state == TCP_CONNTRACK_FIN_WAIT | ||
1023 | || new_state == TCP_CONNTRACK_CLOSE)) | ||
1024 | conntrack->proto.tcp.seen[dir].flags |= IP_CT_TCP_FLAG_CLOSE_INIT; | ||
1025 | timeout = conntrack->proto.tcp.retrans >= ip_ct_tcp_max_retrans | ||
1026 | && *tcp_timeouts[new_state] > ip_ct_tcp_timeout_max_retrans | ||
1027 | ? ip_ct_tcp_timeout_max_retrans : *tcp_timeouts[new_state]; | ||
1028 | write_unlock_bh(&tcp_lock); | ||
1029 | |||
1030 | ip_conntrack_event_cache(IPCT_PROTOINFO_VOLATILE, skb); | ||
1031 | if (new_state != old_state) | ||
1032 | ip_conntrack_event_cache(IPCT_PROTOINFO, skb); | ||
1033 | |||
1034 | if (!test_bit(IPS_SEEN_REPLY_BIT, &conntrack->status)) { | ||
1035 | /* If only reply is a RST, we can consider ourselves not to | ||
1036 | have an established connection: this is a fairly common | ||
1037 | problem case, so we can delete the conntrack | ||
1038 | immediately. --RR */ | ||
1039 | if (th->rst) { | ||
1040 | if (del_timer(&conntrack->timeout)) | ||
1041 | conntrack->timeout.function((unsigned long) | ||
1042 | conntrack); | ||
1043 | return NF_ACCEPT; | ||
1044 | } | ||
1045 | } else if (!test_bit(IPS_ASSURED_BIT, &conntrack->status) | ||
1046 | && (old_state == TCP_CONNTRACK_SYN_RECV | ||
1047 | || old_state == TCP_CONNTRACK_ESTABLISHED) | ||
1048 | && new_state == TCP_CONNTRACK_ESTABLISHED) { | ||
1049 | /* Set ASSURED if we see see valid ack in ESTABLISHED | ||
1050 | after SYN_RECV or a valid answer for a picked up | ||
1051 | connection. */ | ||
1052 | set_bit(IPS_ASSURED_BIT, &conntrack->status); | ||
1053 | ip_conntrack_event_cache(IPCT_STATUS, skb); | ||
1054 | } | ||
1055 | ip_ct_refresh_acct(conntrack, ctinfo, skb, timeout); | ||
1056 | |||
1057 | return NF_ACCEPT; | ||
1058 | } | ||
1059 | |||
1060 | /* Called when a new connection for this protocol found. */ | ||
1061 | static int tcp_new(struct ip_conntrack *conntrack, | ||
1062 | const struct sk_buff *skb) | ||
1063 | { | ||
1064 | enum tcp_conntrack new_state; | ||
1065 | struct iphdr *iph = ip_hdr(skb); | ||
1066 | struct tcphdr *th, _tcph; | ||
1067 | #ifdef DEBUGP_VARS | ||
1068 | struct ip_ct_tcp_state *sender = &conntrack->proto.tcp.seen[0]; | ||
1069 | struct ip_ct_tcp_state *receiver = &conntrack->proto.tcp.seen[1]; | ||
1070 | #endif | ||
1071 | |||
1072 | th = skb_header_pointer(skb, iph->ihl * 4, | ||
1073 | sizeof(_tcph), &_tcph); | ||
1074 | BUG_ON(th == NULL); | ||
1075 | |||
1076 | /* Don't need lock here: this conntrack not in circulation yet */ | ||
1077 | new_state | ||
1078 | = tcp_conntracks[0][get_conntrack_index(th)] | ||
1079 | [TCP_CONNTRACK_NONE]; | ||
1080 | |||
1081 | /* Invalid: delete conntrack */ | ||
1082 | if (new_state >= TCP_CONNTRACK_MAX) { | ||
1083 | DEBUGP("ip_ct_tcp: invalid new deleting.\n"); | ||
1084 | return 0; | ||
1085 | } | ||
1086 | |||
1087 | if (new_state == TCP_CONNTRACK_SYN_SENT) { | ||
1088 | /* SYN packet */ | ||
1089 | conntrack->proto.tcp.seen[0].td_end = | ||
1090 | segment_seq_plus_len(ntohl(th->seq), skb->len, | ||
1091 | iph, th); | ||
1092 | conntrack->proto.tcp.seen[0].td_maxwin = ntohs(th->window); | ||
1093 | if (conntrack->proto.tcp.seen[0].td_maxwin == 0) | ||
1094 | conntrack->proto.tcp.seen[0].td_maxwin = 1; | ||
1095 | conntrack->proto.tcp.seen[0].td_maxend = | ||
1096 | conntrack->proto.tcp.seen[0].td_end; | ||
1097 | |||
1098 | tcp_options(skb, iph, th, &conntrack->proto.tcp.seen[0]); | ||
1099 | conntrack->proto.tcp.seen[1].flags = 0; | ||
1100 | } else if (ip_ct_tcp_loose == 0) { | ||
1101 | /* Don't try to pick up connections. */ | ||
1102 | return 0; | ||
1103 | } else { | ||
1104 | /* | ||
1105 | * We are in the middle of a connection, | ||
1106 | * its history is lost for us. | ||
1107 | * Let's try to use the data from the packet. | ||
1108 | */ | ||
1109 | conntrack->proto.tcp.seen[0].td_end = | ||
1110 | segment_seq_plus_len(ntohl(th->seq), skb->len, | ||
1111 | iph, th); | ||
1112 | conntrack->proto.tcp.seen[0].td_maxwin = ntohs(th->window); | ||
1113 | if (conntrack->proto.tcp.seen[0].td_maxwin == 0) | ||
1114 | conntrack->proto.tcp.seen[0].td_maxwin = 1; | ||
1115 | conntrack->proto.tcp.seen[0].td_maxend = | ||
1116 | conntrack->proto.tcp.seen[0].td_end + | ||
1117 | conntrack->proto.tcp.seen[0].td_maxwin; | ||
1118 | conntrack->proto.tcp.seen[0].td_scale = 0; | ||
1119 | |||
1120 | /* We assume SACK and liberal window checking to handle | ||
1121 | * window scaling */ | ||
1122 | conntrack->proto.tcp.seen[0].flags = | ||
1123 | conntrack->proto.tcp.seen[1].flags = IP_CT_TCP_FLAG_SACK_PERM | | ||
1124 | IP_CT_TCP_FLAG_BE_LIBERAL; | ||
1125 | } | ||
1126 | |||
1127 | conntrack->proto.tcp.seen[1].td_end = 0; | ||
1128 | conntrack->proto.tcp.seen[1].td_maxend = 0; | ||
1129 | conntrack->proto.tcp.seen[1].td_maxwin = 1; | ||
1130 | conntrack->proto.tcp.seen[1].td_scale = 0; | ||
1131 | |||
1132 | /* tcp_packet will set them */ | ||
1133 | conntrack->proto.tcp.state = TCP_CONNTRACK_NONE; | ||
1134 | conntrack->proto.tcp.last_index = TCP_NONE_SET; | ||
1135 | |||
1136 | DEBUGP("tcp_new: sender end=%u maxend=%u maxwin=%u scale=%i " | ||
1137 | "receiver end=%u maxend=%u maxwin=%u scale=%i\n", | ||
1138 | sender->td_end, sender->td_maxend, sender->td_maxwin, | ||
1139 | sender->td_scale, | ||
1140 | receiver->td_end, receiver->td_maxend, receiver->td_maxwin, | ||
1141 | receiver->td_scale); | ||
1142 | return 1; | ||
1143 | } | ||
1144 | |||
1145 | struct ip_conntrack_protocol ip_conntrack_protocol_tcp = | ||
1146 | { | ||
1147 | .proto = IPPROTO_TCP, | ||
1148 | .name = "tcp", | ||
1149 | .pkt_to_tuple = tcp_pkt_to_tuple, | ||
1150 | .invert_tuple = tcp_invert_tuple, | ||
1151 | .print_tuple = tcp_print_tuple, | ||
1152 | .print_conntrack = tcp_print_conntrack, | ||
1153 | .packet = tcp_packet, | ||
1154 | .new = tcp_new, | ||
1155 | .error = tcp_error, | ||
1156 | #if defined(CONFIG_IP_NF_CONNTRACK_NETLINK) || \ | ||
1157 | defined(CONFIG_IP_NF_CONNTRACK_NETLINK_MODULE) | ||
1158 | .to_nfattr = tcp_to_nfattr, | ||
1159 | .from_nfattr = nfattr_to_tcp, | ||
1160 | .tuple_to_nfattr = ip_ct_port_tuple_to_nfattr, | ||
1161 | .nfattr_to_tuple = ip_ct_port_nfattr_to_tuple, | ||
1162 | #endif | ||
1163 | }; | ||
diff --git a/net/ipv4/netfilter/ip_conntrack_proto_udp.c b/net/ipv4/netfilter/ip_conntrack_proto_udp.c deleted file mode 100644 index 3b47987bf1bb..000000000000 --- a/net/ipv4/netfilter/ip_conntrack_proto_udp.c +++ /dev/null | |||
@@ -1,148 +0,0 @@ | |||
1 | /* (C) 1999-2001 Paul `Rusty' Russell | ||
2 | * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | */ | ||
8 | |||
9 | #include <linux/types.h> | ||
10 | #include <linux/timer.h> | ||
11 | #include <linux/netfilter.h> | ||
12 | #include <linux/in.h> | ||
13 | #include <linux/ip.h> | ||
14 | #include <linux/udp.h> | ||
15 | #include <linux/seq_file.h> | ||
16 | #include <net/checksum.h> | ||
17 | #include <linux/netfilter_ipv4.h> | ||
18 | #include <linux/netfilter_ipv4/ip_conntrack_protocol.h> | ||
19 | |||
20 | unsigned int ip_ct_udp_timeout __read_mostly = 30*HZ; | ||
21 | unsigned int ip_ct_udp_timeout_stream __read_mostly = 180*HZ; | ||
22 | |||
23 | static int udp_pkt_to_tuple(const struct sk_buff *skb, | ||
24 | unsigned int dataoff, | ||
25 | struct ip_conntrack_tuple *tuple) | ||
26 | { | ||
27 | struct udphdr _hdr, *hp; | ||
28 | |||
29 | /* Actually only need first 8 bytes. */ | ||
30 | hp = skb_header_pointer(skb, dataoff, sizeof(_hdr), &_hdr); | ||
31 | if (hp == NULL) | ||
32 | return 0; | ||
33 | |||
34 | tuple->src.u.udp.port = hp->source; | ||
35 | tuple->dst.u.udp.port = hp->dest; | ||
36 | |||
37 | return 1; | ||
38 | } | ||
39 | |||
40 | static int udp_invert_tuple(struct ip_conntrack_tuple *tuple, | ||
41 | const struct ip_conntrack_tuple *orig) | ||
42 | { | ||
43 | tuple->src.u.udp.port = orig->dst.u.udp.port; | ||
44 | tuple->dst.u.udp.port = orig->src.u.udp.port; | ||
45 | return 1; | ||
46 | } | ||
47 | |||
48 | /* Print out the per-protocol part of the tuple. */ | ||
49 | static int udp_print_tuple(struct seq_file *s, | ||
50 | const struct ip_conntrack_tuple *tuple) | ||
51 | { | ||
52 | return seq_printf(s, "sport=%hu dport=%hu ", | ||
53 | ntohs(tuple->src.u.udp.port), | ||
54 | ntohs(tuple->dst.u.udp.port)); | ||
55 | } | ||
56 | |||
57 | /* Print out the private part of the conntrack. */ | ||
58 | static int udp_print_conntrack(struct seq_file *s, | ||
59 | const struct ip_conntrack *conntrack) | ||
60 | { | ||
61 | return 0; | ||
62 | } | ||
63 | |||
64 | /* Returns verdict for packet, and may modify conntracktype */ | ||
65 | static int udp_packet(struct ip_conntrack *conntrack, | ||
66 | const struct sk_buff *skb, | ||
67 | enum ip_conntrack_info ctinfo) | ||
68 | { | ||
69 | /* If we've seen traffic both ways, this is some kind of UDP | ||
70 | stream. Extend timeout. */ | ||
71 | if (test_bit(IPS_SEEN_REPLY_BIT, &conntrack->status)) { | ||
72 | ip_ct_refresh_acct(conntrack, ctinfo, skb, | ||
73 | ip_ct_udp_timeout_stream); | ||
74 | /* Also, more likely to be important, and not a probe */ | ||
75 | if (!test_and_set_bit(IPS_ASSURED_BIT, &conntrack->status)) | ||
76 | ip_conntrack_event_cache(IPCT_STATUS, skb); | ||
77 | } else | ||
78 | ip_ct_refresh_acct(conntrack, ctinfo, skb, ip_ct_udp_timeout); | ||
79 | |||
80 | return NF_ACCEPT; | ||
81 | } | ||
82 | |||
83 | /* Called when a new connection for this protocol found. */ | ||
84 | static int udp_new(struct ip_conntrack *conntrack, const struct sk_buff *skb) | ||
85 | { | ||
86 | return 1; | ||
87 | } | ||
88 | |||
89 | static int udp_error(struct sk_buff *skb, enum ip_conntrack_info *ctinfo, | ||
90 | unsigned int hooknum) | ||
91 | { | ||
92 | const unsigned int hdrlen = ip_hdrlen(skb); | ||
93 | unsigned int udplen = skb->len - hdrlen; | ||
94 | struct udphdr _hdr, *hdr; | ||
95 | |||
96 | /* Header is too small? */ | ||
97 | hdr = skb_header_pointer(skb, hdrlen, sizeof(_hdr), &_hdr); | ||
98 | if (hdr == NULL) { | ||
99 | if (LOG_INVALID(IPPROTO_UDP)) | ||
100 | nf_log_packet(PF_INET, 0, skb, NULL, NULL, NULL, | ||
101 | "ip_ct_udp: short packet "); | ||
102 | return -NF_ACCEPT; | ||
103 | } | ||
104 | |||
105 | /* Truncated/malformed packets */ | ||
106 | if (ntohs(hdr->len) > udplen || ntohs(hdr->len) < sizeof(*hdr)) { | ||
107 | if (LOG_INVALID(IPPROTO_UDP)) | ||
108 | nf_log_packet(PF_INET, 0, skb, NULL, NULL, NULL, | ||
109 | "ip_ct_udp: truncated/malformed packet "); | ||
110 | return -NF_ACCEPT; | ||
111 | } | ||
112 | |||
113 | /* Packet with no checksum */ | ||
114 | if (!hdr->check) | ||
115 | return NF_ACCEPT; | ||
116 | |||
117 | /* Checksum invalid? Ignore. | ||
118 | * We skip checking packets on the outgoing path | ||
119 | * because the checksum is assumed to be correct. | ||
120 | * FIXME: Source route IP option packets --RR */ | ||
121 | if (ip_conntrack_checksum && hooknum == NF_IP_PRE_ROUTING && | ||
122 | nf_ip_checksum(skb, hooknum, hdrlen, IPPROTO_UDP)) { | ||
123 | if (LOG_INVALID(IPPROTO_UDP)) | ||
124 | nf_log_packet(PF_INET, 0, skb, NULL, NULL, NULL, | ||
125 | "ip_ct_udp: bad UDP checksum "); | ||
126 | return -NF_ACCEPT; | ||
127 | } | ||
128 | |||
129 | return NF_ACCEPT; | ||
130 | } | ||
131 | |||
132 | struct ip_conntrack_protocol ip_conntrack_protocol_udp = | ||
133 | { | ||
134 | .proto = IPPROTO_UDP, | ||
135 | .name = "udp", | ||
136 | .pkt_to_tuple = udp_pkt_to_tuple, | ||
137 | .invert_tuple = udp_invert_tuple, | ||
138 | .print_tuple = udp_print_tuple, | ||
139 | .print_conntrack = udp_print_conntrack, | ||
140 | .packet = udp_packet, | ||
141 | .new = udp_new, | ||
142 | .error = udp_error, | ||
143 | #if defined(CONFIG_IP_NF_CONNTRACK_NETLINK) || \ | ||
144 | defined(CONFIG_IP_NF_CONNTRACK_NETLINK_MODULE) | ||
145 | .tuple_to_nfattr = ip_ct_port_tuple_to_nfattr, | ||
146 | .nfattr_to_tuple = ip_ct_port_nfattr_to_tuple, | ||
147 | #endif | ||
148 | }; | ||
diff --git a/net/ipv4/netfilter/ip_conntrack_sip.c b/net/ipv4/netfilter/ip_conntrack_sip.c deleted file mode 100644 index 7363e2a5cea4..000000000000 --- a/net/ipv4/netfilter/ip_conntrack_sip.c +++ /dev/null | |||
@@ -1,520 +0,0 @@ | |||
1 | /* SIP extension for IP connection tracking. | ||
2 | * | ||
3 | * (C) 2005 by Christian Hentschel <chentschel@arnet.com.ar> | ||
4 | * based on RR's ip_conntrack_ftp.c and other modules. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | */ | ||
10 | |||
11 | #include <linux/module.h> | ||
12 | #include <linux/ctype.h> | ||
13 | #include <linux/skbuff.h> | ||
14 | #include <linux/in.h> | ||
15 | #include <linux/ip.h> | ||
16 | #include <linux/udp.h> | ||
17 | |||
18 | #include <linux/netfilter.h> | ||
19 | #include <linux/netfilter_ipv4.h> | ||
20 | #include <linux/netfilter_ipv4/ip_conntrack_helper.h> | ||
21 | #include <linux/netfilter_ipv4/ip_conntrack_sip.h> | ||
22 | |||
23 | #if 0 | ||
24 | #define DEBUGP printk | ||
25 | #else | ||
26 | #define DEBUGP(format, args...) | ||
27 | #endif | ||
28 | |||
29 | MODULE_LICENSE("GPL"); | ||
30 | MODULE_AUTHOR("Christian Hentschel <chentschel@arnet.com.ar>"); | ||
31 | MODULE_DESCRIPTION("SIP connection tracking helper"); | ||
32 | |||
33 | #define MAX_PORTS 8 | ||
34 | static unsigned short ports[MAX_PORTS]; | ||
35 | static int ports_c; | ||
36 | module_param_array(ports, ushort, &ports_c, 0400); | ||
37 | MODULE_PARM_DESC(ports, "port numbers of sip servers"); | ||
38 | |||
39 | static unsigned int sip_timeout = SIP_TIMEOUT; | ||
40 | module_param(sip_timeout, uint, 0600); | ||
41 | MODULE_PARM_DESC(sip_timeout, "timeout for the master SIP session"); | ||
42 | |||
43 | unsigned int (*ip_nat_sip_hook)(struct sk_buff **pskb, | ||
44 | enum ip_conntrack_info ctinfo, | ||
45 | struct ip_conntrack *ct, | ||
46 | const char **dptr); | ||
47 | EXPORT_SYMBOL_GPL(ip_nat_sip_hook); | ||
48 | |||
49 | unsigned int (*ip_nat_sdp_hook)(struct sk_buff **pskb, | ||
50 | enum ip_conntrack_info ctinfo, | ||
51 | struct ip_conntrack_expect *exp, | ||
52 | const char *dptr); | ||
53 | EXPORT_SYMBOL_GPL(ip_nat_sdp_hook); | ||
54 | |||
55 | static int digits_len(const char *dptr, const char *limit, int *shift); | ||
56 | static int epaddr_len(const char *dptr, const char *limit, int *shift); | ||
57 | static int skp_digits_len(const char *dptr, const char *limit, int *shift); | ||
58 | static int skp_epaddr_len(const char *dptr, const char *limit, int *shift); | ||
59 | |||
60 | struct sip_header_nfo { | ||
61 | const char *lname; | ||
62 | const char *sname; | ||
63 | const char *ln_str; | ||
64 | size_t lnlen; | ||
65 | size_t snlen; | ||
66 | size_t ln_strlen; | ||
67 | int case_sensitive; | ||
68 | int (*match_len)(const char *, const char *, int *); | ||
69 | }; | ||
70 | |||
71 | static struct sip_header_nfo ct_sip_hdrs[] = { | ||
72 | [POS_REG_REQ_URI] = { /* SIP REGISTER request URI */ | ||
73 | .lname = "sip:", | ||
74 | .lnlen = sizeof("sip:") - 1, | ||
75 | .ln_str = ":", | ||
76 | .ln_strlen = sizeof(":") - 1, | ||
77 | .match_len = epaddr_len | ||
78 | }, | ||
79 | [POS_REQ_URI] = { /* SIP request URI */ | ||
80 | .lname = "sip:", | ||
81 | .lnlen = sizeof("sip:") - 1, | ||
82 | .ln_str = "@", | ||
83 | .ln_strlen = sizeof("@") - 1, | ||
84 | .match_len = epaddr_len | ||
85 | }, | ||
86 | [POS_FROM] = { /* SIP From header */ | ||
87 | .lname = "From:", | ||
88 | .lnlen = sizeof("From:") - 1, | ||
89 | .sname = "\r\nf:", | ||
90 | .snlen = sizeof("\r\nf:") - 1, | ||
91 | .ln_str = "sip:", | ||
92 | .ln_strlen = sizeof("sip:") - 1, | ||
93 | .match_len = skp_epaddr_len, | ||
94 | }, | ||
95 | [POS_TO] = { /* SIP To header */ | ||
96 | .lname = "To:", | ||
97 | .lnlen = sizeof("To:") - 1, | ||
98 | .sname = "\r\nt:", | ||
99 | .snlen = sizeof("\r\nt:") - 1, | ||
100 | .ln_str = "sip:", | ||
101 | .ln_strlen = sizeof("sip:") - 1, | ||
102 | .match_len = skp_epaddr_len, | ||
103 | }, | ||
104 | [POS_VIA] = { /* SIP Via header */ | ||
105 | .lname = "Via:", | ||
106 | .lnlen = sizeof("Via:") - 1, | ||
107 | .sname = "\r\nv:", | ||
108 | .snlen = sizeof("\r\nv:") - 1, /* rfc3261 "\r\n" */ | ||
109 | .ln_str = "UDP ", | ||
110 | .ln_strlen = sizeof("UDP ") - 1, | ||
111 | .match_len = epaddr_len, | ||
112 | }, | ||
113 | [POS_CONTACT] = { /* SIP Contact header */ | ||
114 | .lname = "Contact:", | ||
115 | .lnlen = sizeof("Contact:") - 1, | ||
116 | .sname = "\r\nm:", | ||
117 | .snlen = sizeof("\r\nm:") - 1, | ||
118 | .ln_str = "sip:", | ||
119 | .ln_strlen = sizeof("sip:") - 1, | ||
120 | .match_len = skp_epaddr_len | ||
121 | }, | ||
122 | [POS_CONTENT] = { /* SIP Content length header */ | ||
123 | .lname = "Content-Length:", | ||
124 | .lnlen = sizeof("Content-Length:") - 1, | ||
125 | .sname = "\r\nl:", | ||
126 | .snlen = sizeof("\r\nl:") - 1, | ||
127 | .ln_str = ":", | ||
128 | .ln_strlen = sizeof(":") - 1, | ||
129 | .match_len = skp_digits_len | ||
130 | }, | ||
131 | [POS_MEDIA] = { /* SDP media info */ | ||
132 | .case_sensitive = 1, | ||
133 | .lname = "\nm=", | ||
134 | .lnlen = sizeof("\nm=") - 1, | ||
135 | .sname = "\rm=", | ||
136 | .snlen = sizeof("\rm=") - 1, | ||
137 | .ln_str = "audio ", | ||
138 | .ln_strlen = sizeof("audio ") - 1, | ||
139 | .match_len = digits_len | ||
140 | }, | ||
141 | [POS_OWNER] = { /* SDP owner address*/ | ||
142 | .case_sensitive = 1, | ||
143 | .lname = "\no=", | ||
144 | .lnlen = sizeof("\no=") - 1, | ||
145 | .sname = "\ro=", | ||
146 | .snlen = sizeof("\ro=") - 1, | ||
147 | .ln_str = "IN IP4 ", | ||
148 | .ln_strlen = sizeof("IN IP4 ") - 1, | ||
149 | .match_len = epaddr_len | ||
150 | }, | ||
151 | [POS_CONNECTION] = { /* SDP connection info */ | ||
152 | .case_sensitive = 1, | ||
153 | .lname = "\nc=", | ||
154 | .lnlen = sizeof("\nc=") - 1, | ||
155 | .sname = "\rc=", | ||
156 | .snlen = sizeof("\rc=") - 1, | ||
157 | .ln_str = "IN IP4 ", | ||
158 | .ln_strlen = sizeof("IN IP4 ") - 1, | ||
159 | .match_len = epaddr_len | ||
160 | }, | ||
161 | [POS_SDP_HEADER] = { /* SDP version header */ | ||
162 | .case_sensitive = 1, | ||
163 | .lname = "\nv=", | ||
164 | .lnlen = sizeof("\nv=") - 1, | ||
165 | .sname = "\rv=", | ||
166 | .snlen = sizeof("\rv=") - 1, | ||
167 | .ln_str = "=", | ||
168 | .ln_strlen = sizeof("=") - 1, | ||
169 | .match_len = digits_len | ||
170 | } | ||
171 | }; | ||
172 | |||
173 | /* get line lenght until first CR or LF seen. */ | ||
174 | int ct_sip_lnlen(const char *line, const char *limit) | ||
175 | { | ||
176 | const char *k = line; | ||
177 | |||
178 | while ((line <= limit) && (*line == '\r' || *line == '\n')) | ||
179 | line++; | ||
180 | |||
181 | while (line <= limit) { | ||
182 | if (*line == '\r' || *line == '\n') | ||
183 | break; | ||
184 | line++; | ||
185 | } | ||
186 | return line - k; | ||
187 | } | ||
188 | EXPORT_SYMBOL_GPL(ct_sip_lnlen); | ||
189 | |||
190 | /* Linear string search, case sensitive. */ | ||
191 | const char *ct_sip_search(const char *needle, const char *haystack, | ||
192 | size_t needle_len, size_t haystack_len, | ||
193 | int case_sensitive) | ||
194 | { | ||
195 | const char *limit = haystack + (haystack_len - needle_len); | ||
196 | |||
197 | while (haystack <= limit) { | ||
198 | if (case_sensitive) { | ||
199 | if (strncmp(haystack, needle, needle_len) == 0) | ||
200 | return haystack; | ||
201 | } else { | ||
202 | if (strnicmp(haystack, needle, needle_len) == 0) | ||
203 | return haystack; | ||
204 | } | ||
205 | haystack++; | ||
206 | } | ||
207 | return NULL; | ||
208 | } | ||
209 | EXPORT_SYMBOL_GPL(ct_sip_search); | ||
210 | |||
211 | static int digits_len(const char *dptr, const char *limit, int *shift) | ||
212 | { | ||
213 | int len = 0; | ||
214 | while (dptr <= limit && isdigit(*dptr)) { | ||
215 | dptr++; | ||
216 | len++; | ||
217 | } | ||
218 | return len; | ||
219 | } | ||
220 | |||
221 | /* get digits lenght, skiping blank spaces. */ | ||
222 | static int skp_digits_len(const char *dptr, const char *limit, int *shift) | ||
223 | { | ||
224 | for (; dptr <= limit && *dptr == ' '; dptr++) | ||
225 | (*shift)++; | ||
226 | |||
227 | return digits_len(dptr, limit, shift); | ||
228 | } | ||
229 | |||
230 | /* Simple ipaddr parser.. */ | ||
231 | static int parse_ipaddr(const char *cp, const char **endp, | ||
232 | __be32 *ipaddr, const char *limit) | ||
233 | { | ||
234 | unsigned long int val; | ||
235 | int i, digit = 0; | ||
236 | |||
237 | for (i = 0, *ipaddr = 0; cp <= limit && i < 4; i++) { | ||
238 | digit = 0; | ||
239 | if (!isdigit(*cp)) | ||
240 | break; | ||
241 | |||
242 | val = simple_strtoul(cp, (char **)&cp, 10); | ||
243 | if (val > 0xFF) | ||
244 | return -1; | ||
245 | |||
246 | ((u_int8_t *)ipaddr)[i] = val; | ||
247 | digit = 1; | ||
248 | |||
249 | if (*cp != '.') | ||
250 | break; | ||
251 | cp++; | ||
252 | } | ||
253 | if (!digit) | ||
254 | return -1; | ||
255 | |||
256 | if (endp) | ||
257 | *endp = cp; | ||
258 | |||
259 | return 0; | ||
260 | } | ||
261 | |||
262 | /* skip ip address. returns it lenght. */ | ||
263 | static int epaddr_len(const char *dptr, const char *limit, int *shift) | ||
264 | { | ||
265 | const char *aux = dptr; | ||
266 | __be32 ip; | ||
267 | |||
268 | if (parse_ipaddr(dptr, &dptr, &ip, limit) < 0) { | ||
269 | DEBUGP("ip: %s parse failed.!\n", dptr); | ||
270 | return 0; | ||
271 | } | ||
272 | |||
273 | /* Port number */ | ||
274 | if (*dptr == ':') { | ||
275 | dptr++; | ||
276 | dptr += digits_len(dptr, limit, shift); | ||
277 | } | ||
278 | return dptr - aux; | ||
279 | } | ||
280 | |||
281 | /* get address length, skiping user info. */ | ||
282 | static int skp_epaddr_len(const char *dptr, const char *limit, int *shift) | ||
283 | { | ||
284 | int s = *shift; | ||
285 | |||
286 | /* Search for @, but stop at the end of the line. | ||
287 | * We are inside a sip: URI, so we don't need to worry about | ||
288 | * continuation lines. */ | ||
289 | while (dptr <= limit && | ||
290 | *dptr != '@' && *dptr != '\r' && *dptr != '\n') { | ||
291 | (*shift)++; | ||
292 | dptr++; | ||
293 | } | ||
294 | |||
295 | if (dptr <= limit && *dptr == '@') { | ||
296 | dptr++; | ||
297 | (*shift)++; | ||
298 | } else | ||
299 | *shift = s; | ||
300 | |||
301 | return epaddr_len(dptr, limit, shift); | ||
302 | } | ||
303 | |||
304 | /* Returns 0 if not found, -1 error parsing. */ | ||
305 | int ct_sip_get_info(const char *dptr, size_t dlen, | ||
306 | unsigned int *matchoff, | ||
307 | unsigned int *matchlen, | ||
308 | enum sip_header_pos pos) | ||
309 | { | ||
310 | struct sip_header_nfo *hnfo = &ct_sip_hdrs[pos]; | ||
311 | const char *limit, *aux, *k = dptr; | ||
312 | int shift = 0; | ||
313 | |||
314 | limit = dptr + (dlen - hnfo->lnlen); | ||
315 | |||
316 | while (dptr <= limit) { | ||
317 | if ((strncmp(dptr, hnfo->lname, hnfo->lnlen) != 0) && | ||
318 | (hnfo->sname == NULL || | ||
319 | strncmp(dptr, hnfo->sname, hnfo->snlen) != 0)) { | ||
320 | dptr++; | ||
321 | continue; | ||
322 | } | ||
323 | aux = ct_sip_search(hnfo->ln_str, dptr, hnfo->ln_strlen, | ||
324 | ct_sip_lnlen(dptr, limit), | ||
325 | hnfo->case_sensitive); | ||
326 | if (!aux) { | ||
327 | DEBUGP("'%s' not found in '%s'.\n", hnfo->ln_str, | ||
328 | hnfo->lname); | ||
329 | return -1; | ||
330 | } | ||
331 | aux += hnfo->ln_strlen; | ||
332 | |||
333 | *matchlen = hnfo->match_len(aux, limit, &shift); | ||
334 | if (!*matchlen) | ||
335 | return -1; | ||
336 | |||
337 | *matchoff = (aux - k) + shift; | ||
338 | |||
339 | DEBUGP("%s match succeeded! - len: %u\n", hnfo->lname, | ||
340 | *matchlen); | ||
341 | return 1; | ||
342 | } | ||
343 | DEBUGP("%s header not found.\n", hnfo->lname); | ||
344 | return 0; | ||
345 | } | ||
346 | EXPORT_SYMBOL_GPL(ct_sip_get_info); | ||
347 | |||
348 | static int set_expected_rtp(struct sk_buff **pskb, | ||
349 | struct ip_conntrack *ct, | ||
350 | enum ip_conntrack_info ctinfo, | ||
351 | __be32 ipaddr, u_int16_t port, | ||
352 | const char *dptr) | ||
353 | { | ||
354 | struct ip_conntrack_expect *exp; | ||
355 | enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); | ||
356 | int ret; | ||
357 | typeof(ip_nat_sdp_hook) ip_nat_sdp; | ||
358 | |||
359 | exp = ip_conntrack_expect_alloc(ct); | ||
360 | if (exp == NULL) | ||
361 | return NF_DROP; | ||
362 | |||
363 | exp->tuple.src.ip = ct->tuplehash[!dir].tuple.src.ip; | ||
364 | exp->tuple.src.u.udp.port = 0; | ||
365 | exp->tuple.dst.ip = ipaddr; | ||
366 | exp->tuple.dst.u.udp.port = htons(port); | ||
367 | exp->tuple.dst.protonum = IPPROTO_UDP; | ||
368 | |||
369 | exp->mask.src.ip = htonl(0xFFFFFFFF); | ||
370 | exp->mask.src.u.udp.port = 0; | ||
371 | exp->mask.dst.ip = htonl(0xFFFFFFFF); | ||
372 | exp->mask.dst.u.udp.port = htons(0xFFFF); | ||
373 | exp->mask.dst.protonum = 0xFF; | ||
374 | |||
375 | exp->expectfn = NULL; | ||
376 | exp->flags = 0; | ||
377 | |||
378 | ip_nat_sdp = rcu_dereference(ip_nat_sdp_hook); | ||
379 | if (ip_nat_sdp) | ||
380 | ret = ip_nat_sdp(pskb, ctinfo, exp, dptr); | ||
381 | else { | ||
382 | if (ip_conntrack_expect_related(exp) != 0) | ||
383 | ret = NF_DROP; | ||
384 | else | ||
385 | ret = NF_ACCEPT; | ||
386 | } | ||
387 | ip_conntrack_expect_put(exp); | ||
388 | |||
389 | return ret; | ||
390 | } | ||
391 | |||
392 | static int sip_help(struct sk_buff **pskb, | ||
393 | struct ip_conntrack *ct, | ||
394 | enum ip_conntrack_info ctinfo) | ||
395 | { | ||
396 | unsigned int dataoff, datalen; | ||
397 | const char *dptr; | ||
398 | int ret = NF_ACCEPT; | ||
399 | int matchoff, matchlen; | ||
400 | __be32 ipaddr; | ||
401 | u_int16_t port; | ||
402 | typeof(ip_nat_sip_hook) ip_nat_sip; | ||
403 | |||
404 | /* No Data ? */ | ||
405 | dataoff = ip_hdrlen(*pskb) + sizeof(struct udphdr); | ||
406 | if (dataoff >= (*pskb)->len) { | ||
407 | DEBUGP("skb->len = %u\n", (*pskb)->len); | ||
408 | return NF_ACCEPT; | ||
409 | } | ||
410 | |||
411 | ip_ct_refresh(ct, *pskb, sip_timeout * HZ); | ||
412 | |||
413 | if (!skb_is_nonlinear(*pskb)) | ||
414 | dptr = (*pskb)->data + dataoff; | ||
415 | else { | ||
416 | DEBUGP("Copy of skbuff not supported yet.\n"); | ||
417 | goto out; | ||
418 | } | ||
419 | |||
420 | ip_nat_sip = rcu_dereference(ip_nat_sip_hook); | ||
421 | if (ip_nat_sip) { | ||
422 | if (!ip_nat_sip(pskb, ctinfo, ct, &dptr)) { | ||
423 | ret = NF_DROP; | ||
424 | goto out; | ||
425 | } | ||
426 | } | ||
427 | |||
428 | /* After this point NAT, could have mangled skb, so | ||
429 | we need to recalculate payload lenght. */ | ||
430 | datalen = (*pskb)->len - dataoff; | ||
431 | |||
432 | if (datalen < (sizeof("SIP/2.0 200") - 1)) | ||
433 | goto out; | ||
434 | |||
435 | /* RTP info only in some SDP pkts */ | ||
436 | if (memcmp(dptr, "INVITE", sizeof("INVITE") - 1) != 0 && | ||
437 | memcmp(dptr, "SIP/2.0 200", sizeof("SIP/2.0 200") - 1) != 0) { | ||
438 | goto out; | ||
439 | } | ||
440 | /* Get ip and port address from SDP packet. */ | ||
441 | if (ct_sip_get_info(dptr, datalen, &matchoff, &matchlen, | ||
442 | POS_CONNECTION) > 0) { | ||
443 | |||
444 | /* We'll drop only if there are parse problems. */ | ||
445 | if (parse_ipaddr(dptr + matchoff, NULL, &ipaddr, | ||
446 | dptr + datalen) < 0) { | ||
447 | ret = NF_DROP; | ||
448 | goto out; | ||
449 | } | ||
450 | if (ct_sip_get_info(dptr, datalen, &matchoff, &matchlen, | ||
451 | POS_MEDIA) > 0) { | ||
452 | |||
453 | port = simple_strtoul(dptr + matchoff, NULL, 10); | ||
454 | if (port < 1024) { | ||
455 | ret = NF_DROP; | ||
456 | goto out; | ||
457 | } | ||
458 | ret = set_expected_rtp(pskb, ct, ctinfo, | ||
459 | ipaddr, port, dptr); | ||
460 | } | ||
461 | } | ||
462 | out: | ||
463 | return ret; | ||
464 | } | ||
465 | |||
466 | static struct ip_conntrack_helper sip[MAX_PORTS]; | ||
467 | static char sip_names[MAX_PORTS][10]; | ||
468 | |||
469 | static void fini(void) | ||
470 | { | ||
471 | int i; | ||
472 | for (i = 0; i < ports_c; i++) { | ||
473 | DEBUGP("unregistering helper for port %d\n", ports[i]); | ||
474 | ip_conntrack_helper_unregister(&sip[i]); | ||
475 | } | ||
476 | } | ||
477 | |||
478 | static int __init init(void) | ||
479 | { | ||
480 | int i, ret; | ||
481 | char *tmpname; | ||
482 | |||
483 | if (ports_c == 0) | ||
484 | ports[ports_c++] = SIP_PORT; | ||
485 | |||
486 | for (i = 0; i < ports_c; i++) { | ||
487 | /* Create helper structure */ | ||
488 | memset(&sip[i], 0, sizeof(struct ip_conntrack_helper)); | ||
489 | |||
490 | sip[i].tuple.dst.protonum = IPPROTO_UDP; | ||
491 | sip[i].tuple.src.u.udp.port = htons(ports[i]); | ||
492 | sip[i].mask.src.u.udp.port = htons(0xFFFF); | ||
493 | sip[i].mask.dst.protonum = 0xFF; | ||
494 | sip[i].max_expected = 2; | ||
495 | sip[i].timeout = 3 * 60; /* 3 minutes */ | ||
496 | sip[i].me = THIS_MODULE; | ||
497 | sip[i].help = sip_help; | ||
498 | |||
499 | tmpname = &sip_names[i][0]; | ||
500 | if (ports[i] == SIP_PORT) | ||
501 | sprintf(tmpname, "sip"); | ||
502 | else | ||
503 | sprintf(tmpname, "sip-%d", i); | ||
504 | sip[i].name = tmpname; | ||
505 | |||
506 | DEBUGP("port #%d: %d\n", i, ports[i]); | ||
507 | |||
508 | ret = ip_conntrack_helper_register(&sip[i]); | ||
509 | if (ret) { | ||
510 | printk("ERROR registering helper for port %d\n", | ||
511 | ports[i]); | ||
512 | fini(); | ||
513 | return ret; | ||
514 | } | ||
515 | } | ||
516 | return 0; | ||
517 | } | ||
518 | |||
519 | module_init(init); | ||
520 | module_exit(fini); | ||
diff --git a/net/ipv4/netfilter/ip_conntrack_standalone.c b/net/ipv4/netfilter/ip_conntrack_standalone.c deleted file mode 100644 index c32200153d62..000000000000 --- a/net/ipv4/netfilter/ip_conntrack_standalone.c +++ /dev/null | |||
@@ -1,962 +0,0 @@ | |||
1 | /* This file contains all the functions required for the standalone | ||
2 | ip_conntrack module. | ||
3 | |||
4 | These are not required by the compatibility layer. | ||
5 | */ | ||
6 | |||
7 | /* (C) 1999-2001 Paul `Rusty' Russell | ||
8 | * (C) 2002-2005 Netfilter Core Team <coreteam@netfilter.org> | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License version 2 as | ||
12 | * published by the Free Software Foundation. | ||
13 | */ | ||
14 | |||
15 | #include <linux/types.h> | ||
16 | #include <linux/ip.h> | ||
17 | #include <linux/netfilter.h> | ||
18 | #include <linux/netfilter_ipv4.h> | ||
19 | #include <linux/module.h> | ||
20 | #include <linux/skbuff.h> | ||
21 | #include <linux/proc_fs.h> | ||
22 | #include <linux/seq_file.h> | ||
23 | #include <linux/percpu.h> | ||
24 | #ifdef CONFIG_SYSCTL | ||
25 | #include <linux/sysctl.h> | ||
26 | #endif | ||
27 | #include <net/checksum.h> | ||
28 | #include <net/ip.h> | ||
29 | #include <net/route.h> | ||
30 | |||
31 | #include <linux/netfilter_ipv4/ip_conntrack.h> | ||
32 | #include <linux/netfilter_ipv4/ip_conntrack_protocol.h> | ||
33 | #include <linux/netfilter_ipv4/ip_conntrack_core.h> | ||
34 | #include <linux/netfilter_ipv4/ip_conntrack_helper.h> | ||
35 | |||
36 | #if 0 | ||
37 | #define DEBUGP printk | ||
38 | #else | ||
39 | #define DEBUGP(format, args...) | ||
40 | #endif | ||
41 | |||
42 | MODULE_LICENSE("GPL"); | ||
43 | |||
44 | extern atomic_t ip_conntrack_count; | ||
45 | DECLARE_PER_CPU(struct ip_conntrack_stat, ip_conntrack_stat); | ||
46 | |||
47 | static int kill_proto(struct ip_conntrack *i, void *data) | ||
48 | { | ||
49 | return (i->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum == | ||
50 | *((u_int8_t *) data)); | ||
51 | } | ||
52 | |||
53 | #ifdef CONFIG_PROC_FS | ||
54 | static int | ||
55 | print_tuple(struct seq_file *s, const struct ip_conntrack_tuple *tuple, | ||
56 | struct ip_conntrack_protocol *proto) | ||
57 | { | ||
58 | seq_printf(s, "src=%u.%u.%u.%u dst=%u.%u.%u.%u ", | ||
59 | NIPQUAD(tuple->src.ip), NIPQUAD(tuple->dst.ip)); | ||
60 | return proto->print_tuple(s, tuple); | ||
61 | } | ||
62 | |||
63 | #ifdef CONFIG_IP_NF_CT_ACCT | ||
64 | static unsigned int | ||
65 | seq_print_counters(struct seq_file *s, | ||
66 | const struct ip_conntrack_counter *counter) | ||
67 | { | ||
68 | return seq_printf(s, "packets=%llu bytes=%llu ", | ||
69 | (unsigned long long)counter->packets, | ||
70 | (unsigned long long)counter->bytes); | ||
71 | } | ||
72 | #else | ||
73 | #define seq_print_counters(x, y) 0 | ||
74 | #endif | ||
75 | |||
76 | struct ct_iter_state { | ||
77 | unsigned int bucket; | ||
78 | }; | ||
79 | |||
80 | static struct list_head *ct_get_first(struct seq_file *seq) | ||
81 | { | ||
82 | struct ct_iter_state *st = seq->private; | ||
83 | |||
84 | for (st->bucket = 0; | ||
85 | st->bucket < ip_conntrack_htable_size; | ||
86 | st->bucket++) { | ||
87 | if (!list_empty(&ip_conntrack_hash[st->bucket])) | ||
88 | return ip_conntrack_hash[st->bucket].next; | ||
89 | } | ||
90 | return NULL; | ||
91 | } | ||
92 | |||
93 | static struct list_head *ct_get_next(struct seq_file *seq, struct list_head *head) | ||
94 | { | ||
95 | struct ct_iter_state *st = seq->private; | ||
96 | |||
97 | head = head->next; | ||
98 | while (head == &ip_conntrack_hash[st->bucket]) { | ||
99 | if (++st->bucket >= ip_conntrack_htable_size) | ||
100 | return NULL; | ||
101 | head = ip_conntrack_hash[st->bucket].next; | ||
102 | } | ||
103 | return head; | ||
104 | } | ||
105 | |||
106 | static struct list_head *ct_get_idx(struct seq_file *seq, loff_t pos) | ||
107 | { | ||
108 | struct list_head *head = ct_get_first(seq); | ||
109 | |||
110 | if (head) | ||
111 | while (pos && (head = ct_get_next(seq, head))) | ||
112 | pos--; | ||
113 | return pos ? NULL : head; | ||
114 | } | ||
115 | |||
116 | static void *ct_seq_start(struct seq_file *seq, loff_t *pos) | ||
117 | { | ||
118 | read_lock_bh(&ip_conntrack_lock); | ||
119 | return ct_get_idx(seq, *pos); | ||
120 | } | ||
121 | |||
122 | static void *ct_seq_next(struct seq_file *s, void *v, loff_t *pos) | ||
123 | { | ||
124 | (*pos)++; | ||
125 | return ct_get_next(s, v); | ||
126 | } | ||
127 | |||
128 | static void ct_seq_stop(struct seq_file *s, void *v) | ||
129 | { | ||
130 | read_unlock_bh(&ip_conntrack_lock); | ||
131 | } | ||
132 | |||
133 | static int ct_seq_show(struct seq_file *s, void *v) | ||
134 | { | ||
135 | const struct ip_conntrack_tuple_hash *hash = v; | ||
136 | const struct ip_conntrack *conntrack = tuplehash_to_ctrack(hash); | ||
137 | struct ip_conntrack_protocol *proto; | ||
138 | |||
139 | IP_NF_ASSERT(conntrack); | ||
140 | |||
141 | /* we only want to print DIR_ORIGINAL */ | ||
142 | if (DIRECTION(hash)) | ||
143 | return 0; | ||
144 | |||
145 | proto = __ip_conntrack_proto_find(conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum); | ||
146 | IP_NF_ASSERT(proto); | ||
147 | |||
148 | if (seq_printf(s, "%-8s %u %ld ", | ||
149 | proto->name, | ||
150 | conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum, | ||
151 | timer_pending(&conntrack->timeout) | ||
152 | ? (long)(conntrack->timeout.expires - jiffies)/HZ | ||
153 | : 0) != 0) | ||
154 | return -ENOSPC; | ||
155 | |||
156 | if (proto->print_conntrack(s, conntrack)) | ||
157 | return -ENOSPC; | ||
158 | |||
159 | if (print_tuple(s, &conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple, | ||
160 | proto)) | ||
161 | return -ENOSPC; | ||
162 | |||
163 | if (seq_print_counters(s, &conntrack->counters[IP_CT_DIR_ORIGINAL])) | ||
164 | return -ENOSPC; | ||
165 | |||
166 | if (!(test_bit(IPS_SEEN_REPLY_BIT, &conntrack->status))) | ||
167 | if (seq_printf(s, "[UNREPLIED] ")) | ||
168 | return -ENOSPC; | ||
169 | |||
170 | if (print_tuple(s, &conntrack->tuplehash[IP_CT_DIR_REPLY].tuple, | ||
171 | proto)) | ||
172 | return -ENOSPC; | ||
173 | |||
174 | if (seq_print_counters(s, &conntrack->counters[IP_CT_DIR_REPLY])) | ||
175 | return -ENOSPC; | ||
176 | |||
177 | if (test_bit(IPS_ASSURED_BIT, &conntrack->status)) | ||
178 | if (seq_printf(s, "[ASSURED] ")) | ||
179 | return -ENOSPC; | ||
180 | |||
181 | #if defined(CONFIG_IP_NF_CONNTRACK_MARK) | ||
182 | if (seq_printf(s, "mark=%u ", conntrack->mark)) | ||
183 | return -ENOSPC; | ||
184 | #endif | ||
185 | |||
186 | #ifdef CONFIG_IP_NF_CONNTRACK_SECMARK | ||
187 | if (seq_printf(s, "secmark=%u ", conntrack->secmark)) | ||
188 | return -ENOSPC; | ||
189 | #endif | ||
190 | |||
191 | if (seq_printf(s, "use=%u\n", atomic_read(&conntrack->ct_general.use))) | ||
192 | return -ENOSPC; | ||
193 | |||
194 | return 0; | ||
195 | } | ||
196 | |||
197 | static struct seq_operations ct_seq_ops = { | ||
198 | .start = ct_seq_start, | ||
199 | .next = ct_seq_next, | ||
200 | .stop = ct_seq_stop, | ||
201 | .show = ct_seq_show | ||
202 | }; | ||
203 | |||
204 | static int ct_open(struct inode *inode, struct file *file) | ||
205 | { | ||
206 | struct seq_file *seq; | ||
207 | struct ct_iter_state *st; | ||
208 | int ret; | ||
209 | |||
210 | st = kmalloc(sizeof(struct ct_iter_state), GFP_KERNEL); | ||
211 | if (st == NULL) | ||
212 | return -ENOMEM; | ||
213 | ret = seq_open(file, &ct_seq_ops); | ||
214 | if (ret) | ||
215 | goto out_free; | ||
216 | seq = file->private_data; | ||
217 | seq->private = st; | ||
218 | memset(st, 0, sizeof(struct ct_iter_state)); | ||
219 | return ret; | ||
220 | out_free: | ||
221 | kfree(st); | ||
222 | return ret; | ||
223 | } | ||
224 | |||
225 | static const struct file_operations ct_file_ops = { | ||
226 | .owner = THIS_MODULE, | ||
227 | .open = ct_open, | ||
228 | .read = seq_read, | ||
229 | .llseek = seq_lseek, | ||
230 | .release = seq_release_private, | ||
231 | }; | ||
232 | |||
233 | /* expects */ | ||
234 | static void *exp_seq_start(struct seq_file *s, loff_t *pos) | ||
235 | { | ||
236 | struct list_head *e = &ip_conntrack_expect_list; | ||
237 | loff_t i; | ||
238 | |||
239 | /* strange seq_file api calls stop even if we fail, | ||
240 | * thus we need to grab lock since stop unlocks */ | ||
241 | read_lock_bh(&ip_conntrack_lock); | ||
242 | |||
243 | if (list_empty(e)) | ||
244 | return NULL; | ||
245 | |||
246 | for (i = 0; i <= *pos; i++) { | ||
247 | e = e->next; | ||
248 | if (e == &ip_conntrack_expect_list) | ||
249 | return NULL; | ||
250 | } | ||
251 | return e; | ||
252 | } | ||
253 | |||
254 | static void *exp_seq_next(struct seq_file *s, void *v, loff_t *pos) | ||
255 | { | ||
256 | struct list_head *e = v; | ||
257 | |||
258 | ++*pos; | ||
259 | e = e->next; | ||
260 | |||
261 | if (e == &ip_conntrack_expect_list) | ||
262 | return NULL; | ||
263 | |||
264 | return e; | ||
265 | } | ||
266 | |||
267 | static void exp_seq_stop(struct seq_file *s, void *v) | ||
268 | { | ||
269 | read_unlock_bh(&ip_conntrack_lock); | ||
270 | } | ||
271 | |||
272 | static int exp_seq_show(struct seq_file *s, void *v) | ||
273 | { | ||
274 | struct ip_conntrack_expect *expect = v; | ||
275 | |||
276 | if (expect->timeout.function) | ||
277 | seq_printf(s, "%ld ", timer_pending(&expect->timeout) | ||
278 | ? (long)(expect->timeout.expires - jiffies)/HZ : 0); | ||
279 | else | ||
280 | seq_printf(s, "- "); | ||
281 | |||
282 | seq_printf(s, "proto=%u ", expect->tuple.dst.protonum); | ||
283 | |||
284 | print_tuple(s, &expect->tuple, | ||
285 | __ip_conntrack_proto_find(expect->tuple.dst.protonum)); | ||
286 | return seq_putc(s, '\n'); | ||
287 | } | ||
288 | |||
289 | static struct seq_operations exp_seq_ops = { | ||
290 | .start = exp_seq_start, | ||
291 | .next = exp_seq_next, | ||
292 | .stop = exp_seq_stop, | ||
293 | .show = exp_seq_show | ||
294 | }; | ||
295 | |||
296 | static int exp_open(struct inode *inode, struct file *file) | ||
297 | { | ||
298 | return seq_open(file, &exp_seq_ops); | ||
299 | } | ||
300 | |||
301 | static const struct file_operations exp_file_ops = { | ||
302 | .owner = THIS_MODULE, | ||
303 | .open = exp_open, | ||
304 | .read = seq_read, | ||
305 | .llseek = seq_lseek, | ||
306 | .release = seq_release | ||
307 | }; | ||
308 | |||
309 | static void *ct_cpu_seq_start(struct seq_file *seq, loff_t *pos) | ||
310 | { | ||
311 | int cpu; | ||
312 | |||
313 | if (*pos == 0) | ||
314 | return SEQ_START_TOKEN; | ||
315 | |||
316 | for (cpu = *pos-1; cpu < NR_CPUS; ++cpu) { | ||
317 | if (!cpu_possible(cpu)) | ||
318 | continue; | ||
319 | *pos = cpu+1; | ||
320 | return &per_cpu(ip_conntrack_stat, cpu); | ||
321 | } | ||
322 | |||
323 | return NULL; | ||
324 | } | ||
325 | |||
326 | static void *ct_cpu_seq_next(struct seq_file *seq, void *v, loff_t *pos) | ||
327 | { | ||
328 | int cpu; | ||
329 | |||
330 | for (cpu = *pos; cpu < NR_CPUS; ++cpu) { | ||
331 | if (!cpu_possible(cpu)) | ||
332 | continue; | ||
333 | *pos = cpu+1; | ||
334 | return &per_cpu(ip_conntrack_stat, cpu); | ||
335 | } | ||
336 | |||
337 | return NULL; | ||
338 | } | ||
339 | |||
340 | static void ct_cpu_seq_stop(struct seq_file *seq, void *v) | ||
341 | { | ||
342 | } | ||
343 | |||
344 | static int ct_cpu_seq_show(struct seq_file *seq, void *v) | ||
345 | { | ||
346 | unsigned int nr_conntracks = atomic_read(&ip_conntrack_count); | ||
347 | struct ip_conntrack_stat *st = v; | ||
348 | |||
349 | if (v == SEQ_START_TOKEN) { | ||
350 | seq_printf(seq, "entries searched found new invalid ignore delete delete_list insert insert_failed drop early_drop icmp_error expect_new expect_create expect_delete\n"); | ||
351 | return 0; | ||
352 | } | ||
353 | |||
354 | seq_printf(seq, "%08x %08x %08x %08x %08x %08x %08x %08x " | ||
355 | "%08x %08x %08x %08x %08x %08x %08x %08x \n", | ||
356 | nr_conntracks, | ||
357 | st->searched, | ||
358 | st->found, | ||
359 | st->new, | ||
360 | st->invalid, | ||
361 | st->ignore, | ||
362 | st->delete, | ||
363 | st->delete_list, | ||
364 | st->insert, | ||
365 | st->insert_failed, | ||
366 | st->drop, | ||
367 | st->early_drop, | ||
368 | st->error, | ||
369 | |||
370 | st->expect_new, | ||
371 | st->expect_create, | ||
372 | st->expect_delete | ||
373 | ); | ||
374 | return 0; | ||
375 | } | ||
376 | |||
377 | static struct seq_operations ct_cpu_seq_ops = { | ||
378 | .start = ct_cpu_seq_start, | ||
379 | .next = ct_cpu_seq_next, | ||
380 | .stop = ct_cpu_seq_stop, | ||
381 | .show = ct_cpu_seq_show, | ||
382 | }; | ||
383 | |||
384 | static int ct_cpu_seq_open(struct inode *inode, struct file *file) | ||
385 | { | ||
386 | return seq_open(file, &ct_cpu_seq_ops); | ||
387 | } | ||
388 | |||
389 | static const struct file_operations ct_cpu_seq_fops = { | ||
390 | .owner = THIS_MODULE, | ||
391 | .open = ct_cpu_seq_open, | ||
392 | .read = seq_read, | ||
393 | .llseek = seq_lseek, | ||
394 | .release = seq_release_private, | ||
395 | }; | ||
396 | #endif | ||
397 | |||
398 | static unsigned int ip_confirm(unsigned int hooknum, | ||
399 | struct sk_buff **pskb, | ||
400 | const struct net_device *in, | ||
401 | const struct net_device *out, | ||
402 | int (*okfn)(struct sk_buff *)) | ||
403 | { | ||
404 | /* We've seen it coming out the other side: confirm it */ | ||
405 | return ip_conntrack_confirm(pskb); | ||
406 | } | ||
407 | |||
408 | static unsigned int ip_conntrack_help(unsigned int hooknum, | ||
409 | struct sk_buff **pskb, | ||
410 | const struct net_device *in, | ||
411 | const struct net_device *out, | ||
412 | int (*okfn)(struct sk_buff *)) | ||
413 | { | ||
414 | struct ip_conntrack *ct; | ||
415 | enum ip_conntrack_info ctinfo; | ||
416 | |||
417 | /* This is where we call the helper: as the packet goes out. */ | ||
418 | ct = ip_conntrack_get(*pskb, &ctinfo); | ||
419 | if (ct && ct->helper && ctinfo != IP_CT_RELATED + IP_CT_IS_REPLY) { | ||
420 | unsigned int ret; | ||
421 | ret = ct->helper->help(pskb, ct, ctinfo); | ||
422 | if (ret != NF_ACCEPT) | ||
423 | return ret; | ||
424 | } | ||
425 | return NF_ACCEPT; | ||
426 | } | ||
427 | |||
428 | static unsigned int ip_conntrack_defrag(unsigned int hooknum, | ||
429 | struct sk_buff **pskb, | ||
430 | const struct net_device *in, | ||
431 | const struct net_device *out, | ||
432 | int (*okfn)(struct sk_buff *)) | ||
433 | { | ||
434 | #if !defined(CONFIG_IP_NF_NAT) && !defined(CONFIG_IP_NF_NAT_MODULE) | ||
435 | /* Previously seen (loopback)? Ignore. Do this before | ||
436 | fragment check. */ | ||
437 | if ((*pskb)->nfct) | ||
438 | return NF_ACCEPT; | ||
439 | #endif | ||
440 | |||
441 | /* Gather fragments. */ | ||
442 | if (ip_hdr(*pskb)->frag_off & htons(IP_MF | IP_OFFSET)) { | ||
443 | *pskb = ip_ct_gather_frags(*pskb, | ||
444 | hooknum == NF_IP_PRE_ROUTING ? | ||
445 | IP_DEFRAG_CONNTRACK_IN : | ||
446 | IP_DEFRAG_CONNTRACK_OUT); | ||
447 | if (!*pskb) | ||
448 | return NF_STOLEN; | ||
449 | } | ||
450 | return NF_ACCEPT; | ||
451 | } | ||
452 | |||
453 | static unsigned int ip_conntrack_local(unsigned int hooknum, | ||
454 | struct sk_buff **pskb, | ||
455 | const struct net_device *in, | ||
456 | const struct net_device *out, | ||
457 | int (*okfn)(struct sk_buff *)) | ||
458 | { | ||
459 | /* root is playing with raw sockets. */ | ||
460 | if ((*pskb)->len < sizeof(struct iphdr) | ||
461 | || ip_hdrlen(*pskb) < sizeof(struct iphdr)) { | ||
462 | if (net_ratelimit()) | ||
463 | printk("ipt_hook: happy cracking.\n"); | ||
464 | return NF_ACCEPT; | ||
465 | } | ||
466 | return ip_conntrack_in(hooknum, pskb, in, out, okfn); | ||
467 | } | ||
468 | |||
469 | /* Connection tracking may drop packets, but never alters them, so | ||
470 | make it the first hook. */ | ||
471 | static struct nf_hook_ops ip_conntrack_ops[] = { | ||
472 | { | ||
473 | .hook = ip_conntrack_defrag, | ||
474 | .owner = THIS_MODULE, | ||
475 | .pf = PF_INET, | ||
476 | .hooknum = NF_IP_PRE_ROUTING, | ||
477 | .priority = NF_IP_PRI_CONNTRACK_DEFRAG, | ||
478 | }, | ||
479 | { | ||
480 | .hook = ip_conntrack_in, | ||
481 | .owner = THIS_MODULE, | ||
482 | .pf = PF_INET, | ||
483 | .hooknum = NF_IP_PRE_ROUTING, | ||
484 | .priority = NF_IP_PRI_CONNTRACK, | ||
485 | }, | ||
486 | { | ||
487 | .hook = ip_conntrack_defrag, | ||
488 | .owner = THIS_MODULE, | ||
489 | .pf = PF_INET, | ||
490 | .hooknum = NF_IP_LOCAL_OUT, | ||
491 | .priority = NF_IP_PRI_CONNTRACK_DEFRAG, | ||
492 | }, | ||
493 | { | ||
494 | .hook = ip_conntrack_local, | ||
495 | .owner = THIS_MODULE, | ||
496 | .pf = PF_INET, | ||
497 | .hooknum = NF_IP_LOCAL_OUT, | ||
498 | .priority = NF_IP_PRI_CONNTRACK, | ||
499 | }, | ||
500 | { | ||
501 | .hook = ip_conntrack_help, | ||
502 | .owner = THIS_MODULE, | ||
503 | .pf = PF_INET, | ||
504 | .hooknum = NF_IP_POST_ROUTING, | ||
505 | .priority = NF_IP_PRI_CONNTRACK_HELPER, | ||
506 | }, | ||
507 | { | ||
508 | .hook = ip_conntrack_help, | ||
509 | .owner = THIS_MODULE, | ||
510 | .pf = PF_INET, | ||
511 | .hooknum = NF_IP_LOCAL_IN, | ||
512 | .priority = NF_IP_PRI_CONNTRACK_HELPER, | ||
513 | }, | ||
514 | { | ||
515 | .hook = ip_confirm, | ||
516 | .owner = THIS_MODULE, | ||
517 | .pf = PF_INET, | ||
518 | .hooknum = NF_IP_POST_ROUTING, | ||
519 | .priority = NF_IP_PRI_CONNTRACK_CONFIRM, | ||
520 | }, | ||
521 | { | ||
522 | .hook = ip_confirm, | ||
523 | .owner = THIS_MODULE, | ||
524 | .pf = PF_INET, | ||
525 | .hooknum = NF_IP_LOCAL_IN, | ||
526 | .priority = NF_IP_PRI_CONNTRACK_CONFIRM, | ||
527 | }, | ||
528 | }; | ||
529 | |||
530 | /* Sysctl support */ | ||
531 | |||
532 | int ip_conntrack_checksum __read_mostly = 1; | ||
533 | |||
534 | #ifdef CONFIG_SYSCTL | ||
535 | |||
536 | /* From ip_conntrack_core.c */ | ||
537 | extern int ip_conntrack_max; | ||
538 | extern unsigned int ip_conntrack_htable_size; | ||
539 | |||
540 | /* From ip_conntrack_proto_tcp.c */ | ||
541 | extern unsigned int ip_ct_tcp_timeout_syn_sent; | ||
542 | extern unsigned int ip_ct_tcp_timeout_syn_recv; | ||
543 | extern unsigned int ip_ct_tcp_timeout_established; | ||
544 | extern unsigned int ip_ct_tcp_timeout_fin_wait; | ||
545 | extern unsigned int ip_ct_tcp_timeout_close_wait; | ||
546 | extern unsigned int ip_ct_tcp_timeout_last_ack; | ||
547 | extern unsigned int ip_ct_tcp_timeout_time_wait; | ||
548 | extern unsigned int ip_ct_tcp_timeout_close; | ||
549 | extern unsigned int ip_ct_tcp_timeout_max_retrans; | ||
550 | extern int ip_ct_tcp_loose; | ||
551 | extern int ip_ct_tcp_be_liberal; | ||
552 | extern int ip_ct_tcp_max_retrans; | ||
553 | |||
554 | /* From ip_conntrack_proto_udp.c */ | ||
555 | extern unsigned int ip_ct_udp_timeout; | ||
556 | extern unsigned int ip_ct_udp_timeout_stream; | ||
557 | |||
558 | /* From ip_conntrack_proto_icmp.c */ | ||
559 | extern unsigned int ip_ct_icmp_timeout; | ||
560 | |||
561 | /* From ip_conntrack_proto_generic.c */ | ||
562 | extern unsigned int ip_ct_generic_timeout; | ||
563 | |||
564 | /* Log invalid packets of a given protocol */ | ||
565 | static int log_invalid_proto_min = 0; | ||
566 | static int log_invalid_proto_max = 255; | ||
567 | |||
568 | static struct ctl_table_header *ip_ct_sysctl_header; | ||
569 | |||
570 | static ctl_table ip_ct_sysctl_table[] = { | ||
571 | { | ||
572 | .ctl_name = NET_IPV4_NF_CONNTRACK_MAX, | ||
573 | .procname = "ip_conntrack_max", | ||
574 | .data = &ip_conntrack_max, | ||
575 | .maxlen = sizeof(int), | ||
576 | .mode = 0644, | ||
577 | .proc_handler = &proc_dointvec, | ||
578 | }, | ||
579 | { | ||
580 | .ctl_name = NET_IPV4_NF_CONNTRACK_COUNT, | ||
581 | .procname = "ip_conntrack_count", | ||
582 | .data = &ip_conntrack_count, | ||
583 | .maxlen = sizeof(int), | ||
584 | .mode = 0444, | ||
585 | .proc_handler = &proc_dointvec, | ||
586 | }, | ||
587 | { | ||
588 | .ctl_name = NET_IPV4_NF_CONNTRACK_BUCKETS, | ||
589 | .procname = "ip_conntrack_buckets", | ||
590 | .data = &ip_conntrack_htable_size, | ||
591 | .maxlen = sizeof(unsigned int), | ||
592 | .mode = 0444, | ||
593 | .proc_handler = &proc_dointvec, | ||
594 | }, | ||
595 | { | ||
596 | .ctl_name = NET_IPV4_NF_CONNTRACK_CHECKSUM, | ||
597 | .procname = "ip_conntrack_checksum", | ||
598 | .data = &ip_conntrack_checksum, | ||
599 | .maxlen = sizeof(int), | ||
600 | .mode = 0644, | ||
601 | .proc_handler = &proc_dointvec, | ||
602 | }, | ||
603 | { | ||
604 | .ctl_name = NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_SYN_SENT, | ||
605 | .procname = "ip_conntrack_tcp_timeout_syn_sent", | ||
606 | .data = &ip_ct_tcp_timeout_syn_sent, | ||
607 | .maxlen = sizeof(unsigned int), | ||
608 | .mode = 0644, | ||
609 | .proc_handler = &proc_dointvec_jiffies, | ||
610 | }, | ||
611 | { | ||
612 | .ctl_name = NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_SYN_RECV, | ||
613 | .procname = "ip_conntrack_tcp_timeout_syn_recv", | ||
614 | .data = &ip_ct_tcp_timeout_syn_recv, | ||
615 | .maxlen = sizeof(unsigned int), | ||
616 | .mode = 0644, | ||
617 | .proc_handler = &proc_dointvec_jiffies, | ||
618 | }, | ||
619 | { | ||
620 | .ctl_name = NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_ESTABLISHED, | ||
621 | .procname = "ip_conntrack_tcp_timeout_established", | ||
622 | .data = &ip_ct_tcp_timeout_established, | ||
623 | .maxlen = sizeof(unsigned int), | ||
624 | .mode = 0644, | ||
625 | .proc_handler = &proc_dointvec_jiffies, | ||
626 | }, | ||
627 | { | ||
628 | .ctl_name = NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_FIN_WAIT, | ||
629 | .procname = "ip_conntrack_tcp_timeout_fin_wait", | ||
630 | .data = &ip_ct_tcp_timeout_fin_wait, | ||
631 | .maxlen = sizeof(unsigned int), | ||
632 | .mode = 0644, | ||
633 | .proc_handler = &proc_dointvec_jiffies, | ||
634 | }, | ||
635 | { | ||
636 | .ctl_name = NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_CLOSE_WAIT, | ||
637 | .procname = "ip_conntrack_tcp_timeout_close_wait", | ||
638 | .data = &ip_ct_tcp_timeout_close_wait, | ||
639 | .maxlen = sizeof(unsigned int), | ||
640 | .mode = 0644, | ||
641 | .proc_handler = &proc_dointvec_jiffies, | ||
642 | }, | ||
643 | { | ||
644 | .ctl_name = NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_LAST_ACK, | ||
645 | .procname = "ip_conntrack_tcp_timeout_last_ack", | ||
646 | .data = &ip_ct_tcp_timeout_last_ack, | ||
647 | .maxlen = sizeof(unsigned int), | ||
648 | .mode = 0644, | ||
649 | .proc_handler = &proc_dointvec_jiffies, | ||
650 | }, | ||
651 | { | ||
652 | .ctl_name = NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_TIME_WAIT, | ||
653 | .procname = "ip_conntrack_tcp_timeout_time_wait", | ||
654 | .data = &ip_ct_tcp_timeout_time_wait, | ||
655 | .maxlen = sizeof(unsigned int), | ||
656 | .mode = 0644, | ||
657 | .proc_handler = &proc_dointvec_jiffies, | ||
658 | }, | ||
659 | { | ||
660 | .ctl_name = NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_CLOSE, | ||
661 | .procname = "ip_conntrack_tcp_timeout_close", | ||
662 | .data = &ip_ct_tcp_timeout_close, | ||
663 | .maxlen = sizeof(unsigned int), | ||
664 | .mode = 0644, | ||
665 | .proc_handler = &proc_dointvec_jiffies, | ||
666 | }, | ||
667 | { | ||
668 | .ctl_name = NET_IPV4_NF_CONNTRACK_UDP_TIMEOUT, | ||
669 | .procname = "ip_conntrack_udp_timeout", | ||
670 | .data = &ip_ct_udp_timeout, | ||
671 | .maxlen = sizeof(unsigned int), | ||
672 | .mode = 0644, | ||
673 | .proc_handler = &proc_dointvec_jiffies, | ||
674 | }, | ||
675 | { | ||
676 | .ctl_name = NET_IPV4_NF_CONNTRACK_UDP_TIMEOUT_STREAM, | ||
677 | .procname = "ip_conntrack_udp_timeout_stream", | ||
678 | .data = &ip_ct_udp_timeout_stream, | ||
679 | .maxlen = sizeof(unsigned int), | ||
680 | .mode = 0644, | ||
681 | .proc_handler = &proc_dointvec_jiffies, | ||
682 | }, | ||
683 | { | ||
684 | .ctl_name = NET_IPV4_NF_CONNTRACK_ICMP_TIMEOUT, | ||
685 | .procname = "ip_conntrack_icmp_timeout", | ||
686 | .data = &ip_ct_icmp_timeout, | ||
687 | .maxlen = sizeof(unsigned int), | ||
688 | .mode = 0644, | ||
689 | .proc_handler = &proc_dointvec_jiffies, | ||
690 | }, | ||
691 | { | ||
692 | .ctl_name = NET_IPV4_NF_CONNTRACK_GENERIC_TIMEOUT, | ||
693 | .procname = "ip_conntrack_generic_timeout", | ||
694 | .data = &ip_ct_generic_timeout, | ||
695 | .maxlen = sizeof(unsigned int), | ||
696 | .mode = 0644, | ||
697 | .proc_handler = &proc_dointvec_jiffies, | ||
698 | }, | ||
699 | { | ||
700 | .ctl_name = NET_IPV4_NF_CONNTRACK_LOG_INVALID, | ||
701 | .procname = "ip_conntrack_log_invalid", | ||
702 | .data = &ip_ct_log_invalid, | ||
703 | .maxlen = sizeof(unsigned int), | ||
704 | .mode = 0644, | ||
705 | .proc_handler = &proc_dointvec_minmax, | ||
706 | .strategy = &sysctl_intvec, | ||
707 | .extra1 = &log_invalid_proto_min, | ||
708 | .extra2 = &log_invalid_proto_max, | ||
709 | }, | ||
710 | { | ||
711 | .ctl_name = NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_MAX_RETRANS, | ||
712 | .procname = "ip_conntrack_tcp_timeout_max_retrans", | ||
713 | .data = &ip_ct_tcp_timeout_max_retrans, | ||
714 | .maxlen = sizeof(unsigned int), | ||
715 | .mode = 0644, | ||
716 | .proc_handler = &proc_dointvec_jiffies, | ||
717 | }, | ||
718 | { | ||
719 | .ctl_name = NET_IPV4_NF_CONNTRACK_TCP_LOOSE, | ||
720 | .procname = "ip_conntrack_tcp_loose", | ||
721 | .data = &ip_ct_tcp_loose, | ||
722 | .maxlen = sizeof(unsigned int), | ||
723 | .mode = 0644, | ||
724 | .proc_handler = &proc_dointvec, | ||
725 | }, | ||
726 | { | ||
727 | .ctl_name = NET_IPV4_NF_CONNTRACK_TCP_BE_LIBERAL, | ||
728 | .procname = "ip_conntrack_tcp_be_liberal", | ||
729 | .data = &ip_ct_tcp_be_liberal, | ||
730 | .maxlen = sizeof(unsigned int), | ||
731 | .mode = 0644, | ||
732 | .proc_handler = &proc_dointvec, | ||
733 | }, | ||
734 | { | ||
735 | .ctl_name = NET_IPV4_NF_CONNTRACK_TCP_MAX_RETRANS, | ||
736 | .procname = "ip_conntrack_tcp_max_retrans", | ||
737 | .data = &ip_ct_tcp_max_retrans, | ||
738 | .maxlen = sizeof(unsigned int), | ||
739 | .mode = 0644, | ||
740 | .proc_handler = &proc_dointvec, | ||
741 | }, | ||
742 | { .ctl_name = 0 } | ||
743 | }; | ||
744 | |||
745 | #define NET_IP_CONNTRACK_MAX 2089 | ||
746 | |||
747 | static ctl_table ip_ct_netfilter_table[] = { | ||
748 | { | ||
749 | .ctl_name = NET_IPV4_NETFILTER, | ||
750 | .procname = "netfilter", | ||
751 | .mode = 0555, | ||
752 | .child = ip_ct_sysctl_table, | ||
753 | }, | ||
754 | { | ||
755 | .ctl_name = NET_IP_CONNTRACK_MAX, | ||
756 | .procname = "ip_conntrack_max", | ||
757 | .data = &ip_conntrack_max, | ||
758 | .maxlen = sizeof(int), | ||
759 | .mode = 0644, | ||
760 | .proc_handler = &proc_dointvec | ||
761 | }, | ||
762 | { .ctl_name = 0 } | ||
763 | }; | ||
764 | |||
765 | static ctl_table ip_ct_ipv4_table[] = { | ||
766 | { | ||
767 | .ctl_name = NET_IPV4, | ||
768 | .procname = "ipv4", | ||
769 | .mode = 0555, | ||
770 | .child = ip_ct_netfilter_table, | ||
771 | }, | ||
772 | { .ctl_name = 0 } | ||
773 | }; | ||
774 | |||
775 | static ctl_table ip_ct_net_table[] = { | ||
776 | { | ||
777 | .ctl_name = CTL_NET, | ||
778 | .procname = "net", | ||
779 | .mode = 0555, | ||
780 | .child = ip_ct_ipv4_table, | ||
781 | }, | ||
782 | { .ctl_name = 0 } | ||
783 | }; | ||
784 | |||
785 | EXPORT_SYMBOL(ip_ct_log_invalid); | ||
786 | #endif /* CONFIG_SYSCTL */ | ||
787 | |||
788 | /* FIXME: Allow NULL functions and sub in pointers to generic for | ||
789 | them. --RR */ | ||
790 | int ip_conntrack_protocol_register(struct ip_conntrack_protocol *proto) | ||
791 | { | ||
792 | int ret = 0; | ||
793 | |||
794 | write_lock_bh(&ip_conntrack_lock); | ||
795 | if (ip_ct_protos[proto->proto] != &ip_conntrack_generic_protocol) { | ||
796 | ret = -EBUSY; | ||
797 | goto out; | ||
798 | } | ||
799 | rcu_assign_pointer(ip_ct_protos[proto->proto], proto); | ||
800 | out: | ||
801 | write_unlock_bh(&ip_conntrack_lock); | ||
802 | return ret; | ||
803 | } | ||
804 | |||
805 | void ip_conntrack_protocol_unregister(struct ip_conntrack_protocol *proto) | ||
806 | { | ||
807 | write_lock_bh(&ip_conntrack_lock); | ||
808 | rcu_assign_pointer(ip_ct_protos[proto->proto], | ||
809 | &ip_conntrack_generic_protocol); | ||
810 | write_unlock_bh(&ip_conntrack_lock); | ||
811 | synchronize_rcu(); | ||
812 | |||
813 | /* Remove all contrack entries for this protocol */ | ||
814 | ip_ct_iterate_cleanup(kill_proto, &proto->proto); | ||
815 | } | ||
816 | |||
817 | static int __init ip_conntrack_standalone_init(void) | ||
818 | { | ||
819 | #ifdef CONFIG_PROC_FS | ||
820 | struct proc_dir_entry *proc, *proc_exp, *proc_stat; | ||
821 | #endif | ||
822 | int ret = 0; | ||
823 | |||
824 | ret = ip_conntrack_init(); | ||
825 | if (ret < 0) | ||
826 | return ret; | ||
827 | |||
828 | #ifdef CONFIG_PROC_FS | ||
829 | ret = -ENOMEM; | ||
830 | proc = proc_net_fops_create("ip_conntrack", 0440, &ct_file_ops); | ||
831 | if (!proc) goto cleanup_init; | ||
832 | |||
833 | proc_exp = proc_net_fops_create("ip_conntrack_expect", 0440, | ||
834 | &exp_file_ops); | ||
835 | if (!proc_exp) goto cleanup_proc; | ||
836 | |||
837 | proc_stat = create_proc_entry("ip_conntrack", S_IRUGO, proc_net_stat); | ||
838 | if (!proc_stat) | ||
839 | goto cleanup_proc_exp; | ||
840 | |||
841 | proc_stat->proc_fops = &ct_cpu_seq_fops; | ||
842 | proc_stat->owner = THIS_MODULE; | ||
843 | #endif | ||
844 | |||
845 | ret = nf_register_hooks(ip_conntrack_ops, ARRAY_SIZE(ip_conntrack_ops)); | ||
846 | if (ret < 0) { | ||
847 | printk("ip_conntrack: can't register hooks.\n"); | ||
848 | goto cleanup_proc_stat; | ||
849 | } | ||
850 | #ifdef CONFIG_SYSCTL | ||
851 | ip_ct_sysctl_header = register_sysctl_table(ip_ct_net_table); | ||
852 | if (ip_ct_sysctl_header == NULL) { | ||
853 | printk("ip_conntrack: can't register to sysctl.\n"); | ||
854 | ret = -ENOMEM; | ||
855 | goto cleanup_hooks; | ||
856 | } | ||
857 | #endif | ||
858 | return ret; | ||
859 | |||
860 | #ifdef CONFIG_SYSCTL | ||
861 | cleanup_hooks: | ||
862 | nf_unregister_hooks(ip_conntrack_ops, ARRAY_SIZE(ip_conntrack_ops)); | ||
863 | #endif | ||
864 | cleanup_proc_stat: | ||
865 | #ifdef CONFIG_PROC_FS | ||
866 | remove_proc_entry("ip_conntrack", proc_net_stat); | ||
867 | cleanup_proc_exp: | ||
868 | proc_net_remove("ip_conntrack_expect"); | ||
869 | cleanup_proc: | ||
870 | proc_net_remove("ip_conntrack"); | ||
871 | cleanup_init: | ||
872 | #endif /* CONFIG_PROC_FS */ | ||
873 | ip_conntrack_cleanup(); | ||
874 | return ret; | ||
875 | } | ||
876 | |||
877 | static void __exit ip_conntrack_standalone_fini(void) | ||
878 | { | ||
879 | synchronize_net(); | ||
880 | #ifdef CONFIG_SYSCTL | ||
881 | unregister_sysctl_table(ip_ct_sysctl_header); | ||
882 | #endif | ||
883 | nf_unregister_hooks(ip_conntrack_ops, ARRAY_SIZE(ip_conntrack_ops)); | ||
884 | #ifdef CONFIG_PROC_FS | ||
885 | remove_proc_entry("ip_conntrack", proc_net_stat); | ||
886 | proc_net_remove("ip_conntrack_expect"); | ||
887 | proc_net_remove("ip_conntrack"); | ||
888 | #endif /* CONFIG_PROC_FS */ | ||
889 | ip_conntrack_cleanup(); | ||
890 | } | ||
891 | |||
892 | module_init(ip_conntrack_standalone_init); | ||
893 | module_exit(ip_conntrack_standalone_fini); | ||
894 | |||
895 | /* Some modules need us, but don't depend directly on any symbol. | ||
896 | They should call this. */ | ||
897 | void need_conntrack(void) | ||
898 | { | ||
899 | } | ||
900 | |||
901 | #ifdef CONFIG_IP_NF_CONNTRACK_EVENTS | ||
902 | EXPORT_SYMBOL_GPL(ip_conntrack_chain); | ||
903 | EXPORT_SYMBOL_GPL(ip_conntrack_expect_chain); | ||
904 | EXPORT_SYMBOL_GPL(ip_conntrack_register_notifier); | ||
905 | EXPORT_SYMBOL_GPL(ip_conntrack_unregister_notifier); | ||
906 | EXPORT_SYMBOL_GPL(__ip_ct_event_cache_init); | ||
907 | EXPORT_PER_CPU_SYMBOL_GPL(ip_conntrack_ecache); | ||
908 | #endif | ||
909 | EXPORT_SYMBOL(ip_conntrack_protocol_register); | ||
910 | EXPORT_SYMBOL(ip_conntrack_protocol_unregister); | ||
911 | EXPORT_SYMBOL(ip_ct_get_tuple); | ||
912 | EXPORT_SYMBOL(invert_tuplepr); | ||
913 | EXPORT_SYMBOL(ip_conntrack_alter_reply); | ||
914 | EXPORT_SYMBOL(ip_conntrack_destroyed); | ||
915 | EXPORT_SYMBOL(need_conntrack); | ||
916 | EXPORT_SYMBOL(ip_conntrack_helper_register); | ||
917 | EXPORT_SYMBOL(ip_conntrack_helper_unregister); | ||
918 | EXPORT_SYMBOL(ip_ct_iterate_cleanup); | ||
919 | EXPORT_SYMBOL(__ip_ct_refresh_acct); | ||
920 | |||
921 | EXPORT_SYMBOL(ip_conntrack_expect_alloc); | ||
922 | EXPORT_SYMBOL(ip_conntrack_expect_put); | ||
923 | EXPORT_SYMBOL_GPL(__ip_conntrack_expect_find); | ||
924 | EXPORT_SYMBOL_GPL(ip_conntrack_expect_find_get); | ||
925 | EXPORT_SYMBOL(ip_conntrack_expect_related); | ||
926 | EXPORT_SYMBOL(ip_conntrack_unexpect_related); | ||
927 | EXPORT_SYMBOL_GPL(ip_conntrack_expect_list); | ||
928 | EXPORT_SYMBOL_GPL(ip_ct_unlink_expect); | ||
929 | |||
930 | EXPORT_SYMBOL(ip_conntrack_tuple_taken); | ||
931 | EXPORT_SYMBOL(ip_ct_gather_frags); | ||
932 | EXPORT_SYMBOL(ip_conntrack_htable_size); | ||
933 | EXPORT_SYMBOL(ip_conntrack_lock); | ||
934 | EXPORT_SYMBOL(ip_conntrack_hash); | ||
935 | EXPORT_SYMBOL(ip_conntrack_untracked); | ||
936 | EXPORT_SYMBOL_GPL(ip_conntrack_find_get); | ||
937 | #ifdef CONFIG_IP_NF_NAT_NEEDED | ||
938 | EXPORT_SYMBOL(ip_conntrack_tcp_update); | ||
939 | #endif | ||
940 | |||
941 | EXPORT_SYMBOL_GPL(ip_conntrack_flush); | ||
942 | EXPORT_SYMBOL_GPL(__ip_conntrack_find); | ||
943 | |||
944 | EXPORT_SYMBOL_GPL(ip_conntrack_alloc); | ||
945 | EXPORT_SYMBOL_GPL(ip_conntrack_free); | ||
946 | EXPORT_SYMBOL_GPL(ip_conntrack_hash_insert); | ||
947 | |||
948 | EXPORT_SYMBOL_GPL(ip_ct_remove_expectations); | ||
949 | |||
950 | EXPORT_SYMBOL_GPL(ip_conntrack_helper_find_get); | ||
951 | EXPORT_SYMBOL_GPL(ip_conntrack_helper_put); | ||
952 | EXPORT_SYMBOL_GPL(__ip_conntrack_helper_find_byname); | ||
953 | |||
954 | EXPORT_SYMBOL_GPL(ip_conntrack_proto_find_get); | ||
955 | EXPORT_SYMBOL_GPL(ip_conntrack_proto_put); | ||
956 | EXPORT_SYMBOL_GPL(__ip_conntrack_proto_find); | ||
957 | EXPORT_SYMBOL_GPL(ip_conntrack_checksum); | ||
958 | #if defined(CONFIG_IP_NF_CONNTRACK_NETLINK) || \ | ||
959 | defined(CONFIG_IP_NF_CONNTRACK_NETLINK_MODULE) | ||
960 | EXPORT_SYMBOL_GPL(ip_ct_port_tuple_to_nfattr); | ||
961 | EXPORT_SYMBOL_GPL(ip_ct_port_nfattr_to_tuple); | ||
962 | #endif | ||
diff --git a/net/ipv4/netfilter/ip_conntrack_tftp.c b/net/ipv4/netfilter/ip_conntrack_tftp.c deleted file mode 100644 index afc6809a3888..000000000000 --- a/net/ipv4/netfilter/ip_conntrack_tftp.c +++ /dev/null | |||
@@ -1,161 +0,0 @@ | |||
1 | /* (C) 2001-2002 Magnus Boden <mb@ozaba.mine.nu> | ||
2 | * | ||
3 | * This program is free software; you can redistribute it and/or modify | ||
4 | * it under the terms of the GNU General Public License version 2 as | ||
5 | * published by the Free Software Foundation. | ||
6 | * | ||
7 | * Version: 0.0.7 | ||
8 | * | ||
9 | * Thu 21 Mar 2002 Harald Welte <laforge@gnumonks.org> | ||
10 | * - port to newnat API | ||
11 | * | ||
12 | */ | ||
13 | |||
14 | #include <linux/module.h> | ||
15 | #include <linux/ip.h> | ||
16 | #include <linux/udp.h> | ||
17 | |||
18 | #include <linux/netfilter.h> | ||
19 | #include <linux/netfilter_ipv4/ip_tables.h> | ||
20 | #include <linux/netfilter_ipv4/ip_conntrack_helper.h> | ||
21 | #include <linux/netfilter_ipv4/ip_conntrack_tftp.h> | ||
22 | #include <linux/moduleparam.h> | ||
23 | |||
24 | MODULE_AUTHOR("Magnus Boden <mb@ozaba.mine.nu>"); | ||
25 | MODULE_DESCRIPTION("tftp connection tracking helper"); | ||
26 | MODULE_LICENSE("GPL"); | ||
27 | |||
28 | #define MAX_PORTS 8 | ||
29 | static unsigned short ports[MAX_PORTS]; | ||
30 | static int ports_c; | ||
31 | module_param_array(ports, ushort, &ports_c, 0400); | ||
32 | MODULE_PARM_DESC(ports, "port numbers of tftp servers"); | ||
33 | |||
34 | #if 0 | ||
35 | #define DEBUGP(format, args...) printk("%s:%s:" format, \ | ||
36 | __FILE__, __FUNCTION__ , ## args) | ||
37 | #else | ||
38 | #define DEBUGP(format, args...) | ||
39 | #endif | ||
40 | |||
41 | unsigned int (*ip_nat_tftp_hook)(struct sk_buff **pskb, | ||
42 | enum ip_conntrack_info ctinfo, | ||
43 | struct ip_conntrack_expect *exp); | ||
44 | EXPORT_SYMBOL_GPL(ip_nat_tftp_hook); | ||
45 | |||
46 | static int tftp_help(struct sk_buff **pskb, | ||
47 | struct ip_conntrack *ct, | ||
48 | enum ip_conntrack_info ctinfo) | ||
49 | { | ||
50 | struct tftphdr _tftph, *tfh; | ||
51 | struct ip_conntrack_expect *exp; | ||
52 | unsigned int ret = NF_ACCEPT; | ||
53 | typeof(ip_nat_tftp_hook) ip_nat_tftp; | ||
54 | |||
55 | tfh = skb_header_pointer(*pskb, | ||
56 | ip_hdrlen(*pskb) + sizeof(struct udphdr), | ||
57 | sizeof(_tftph), &_tftph); | ||
58 | if (tfh == NULL) | ||
59 | return NF_ACCEPT; | ||
60 | |||
61 | switch (ntohs(tfh->opcode)) { | ||
62 | /* RRQ and WRQ works the same way */ | ||
63 | case TFTP_OPCODE_READ: | ||
64 | case TFTP_OPCODE_WRITE: | ||
65 | DEBUGP(""); | ||
66 | DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); | ||
67 | DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_REPLY].tuple); | ||
68 | |||
69 | exp = ip_conntrack_expect_alloc(ct); | ||
70 | if (exp == NULL) | ||
71 | return NF_DROP; | ||
72 | |||
73 | exp->tuple = ct->tuplehash[IP_CT_DIR_REPLY].tuple; | ||
74 | exp->mask.src.ip = htonl(0xffffffff); | ||
75 | exp->mask.src.u.udp.port = 0; | ||
76 | exp->mask.dst.ip = htonl(0xffffffff); | ||
77 | exp->mask.dst.u.udp.port = htons(0xffff); | ||
78 | exp->mask.dst.protonum = 0xff; | ||
79 | exp->expectfn = NULL; | ||
80 | exp->flags = 0; | ||
81 | |||
82 | DEBUGP("expect: "); | ||
83 | DUMP_TUPLE(&exp->tuple); | ||
84 | DUMP_TUPLE(&exp->mask); | ||
85 | ip_nat_tftp = rcu_dereference(ip_nat_tftp_hook); | ||
86 | if (ip_nat_tftp) | ||
87 | ret = ip_nat_tftp(pskb, ctinfo, exp); | ||
88 | else if (ip_conntrack_expect_related(exp) != 0) | ||
89 | ret = NF_DROP; | ||
90 | ip_conntrack_expect_put(exp); | ||
91 | break; | ||
92 | case TFTP_OPCODE_DATA: | ||
93 | case TFTP_OPCODE_ACK: | ||
94 | DEBUGP("Data/ACK opcode\n"); | ||
95 | break; | ||
96 | case TFTP_OPCODE_ERROR: | ||
97 | DEBUGP("Error opcode\n"); | ||
98 | break; | ||
99 | default: | ||
100 | DEBUGP("Unknown opcode\n"); | ||
101 | } | ||
102 | return NF_ACCEPT; | ||
103 | } | ||
104 | |||
105 | static struct ip_conntrack_helper tftp[MAX_PORTS]; | ||
106 | static char tftp_names[MAX_PORTS][sizeof("tftp-65535")]; | ||
107 | |||
108 | static void ip_conntrack_tftp_fini(void) | ||
109 | { | ||
110 | int i; | ||
111 | |||
112 | for (i = 0 ; i < ports_c; i++) { | ||
113 | DEBUGP("unregistering helper for port %d\n", | ||
114 | ports[i]); | ||
115 | ip_conntrack_helper_unregister(&tftp[i]); | ||
116 | } | ||
117 | } | ||
118 | |||
119 | static int __init ip_conntrack_tftp_init(void) | ||
120 | { | ||
121 | int i, ret; | ||
122 | char *tmpname; | ||
123 | |||
124 | if (ports_c == 0) | ||
125 | ports[ports_c++] = TFTP_PORT; | ||
126 | |||
127 | for (i = 0; i < ports_c; i++) { | ||
128 | /* Create helper structure */ | ||
129 | memset(&tftp[i], 0, sizeof(struct ip_conntrack_helper)); | ||
130 | |||
131 | tftp[i].tuple.dst.protonum = IPPROTO_UDP; | ||
132 | tftp[i].tuple.src.u.udp.port = htons(ports[i]); | ||
133 | tftp[i].mask.dst.protonum = 0xFF; | ||
134 | tftp[i].mask.src.u.udp.port = htons(0xFFFF); | ||
135 | tftp[i].max_expected = 1; | ||
136 | tftp[i].timeout = 5 * 60; /* 5 minutes */ | ||
137 | tftp[i].me = THIS_MODULE; | ||
138 | tftp[i].help = tftp_help; | ||
139 | |||
140 | tmpname = &tftp_names[i][0]; | ||
141 | if (ports[i] == TFTP_PORT) | ||
142 | sprintf(tmpname, "tftp"); | ||
143 | else | ||
144 | sprintf(tmpname, "tftp-%d", i); | ||
145 | tftp[i].name = tmpname; | ||
146 | |||
147 | DEBUGP("port #%d: %d\n", i, ports[i]); | ||
148 | |||
149 | ret=ip_conntrack_helper_register(&tftp[i]); | ||
150 | if (ret) { | ||
151 | printk("ERROR registering helper for port %d\n", | ||
152 | ports[i]); | ||
153 | ip_conntrack_tftp_fini(); | ||
154 | return(ret); | ||
155 | } | ||
156 | } | ||
157 | return(0); | ||
158 | } | ||
159 | |||
160 | module_init(ip_conntrack_tftp_init); | ||
161 | module_exit(ip_conntrack_tftp_fini); | ||
diff --git a/net/ipv4/netfilter/ip_nat_amanda.c b/net/ipv4/netfilter/ip_nat_amanda.c deleted file mode 100644 index 85df1a9aed33..000000000000 --- a/net/ipv4/netfilter/ip_nat_amanda.c +++ /dev/null | |||
@@ -1,85 +0,0 @@ | |||
1 | /* Amanda extension for TCP NAT alteration. | ||
2 | * (C) 2002 by Brian J. Murrell <netfilter@interlinx.bc.ca> | ||
3 | * based on a copy of HW's ip_nat_irc.c as well as other modules | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or | ||
6 | * modify it under the terms of the GNU General Public License | ||
7 | * as published by the Free Software Foundation; either version | ||
8 | * 2 of the License, or (at your option) any later version. | ||
9 | * | ||
10 | * Module load syntax: | ||
11 | * insmod ip_nat_amanda.o | ||
12 | */ | ||
13 | |||
14 | #include <linux/kernel.h> | ||
15 | #include <linux/module.h> | ||
16 | #include <linux/netfilter.h> | ||
17 | #include <linux/skbuff.h> | ||
18 | #include <linux/ip.h> | ||
19 | #include <linux/udp.h> | ||
20 | #include <net/tcp.h> | ||
21 | #include <net/udp.h> | ||
22 | |||
23 | #include <linux/netfilter_ipv4.h> | ||
24 | #include <linux/netfilter_ipv4/ip_nat.h> | ||
25 | #include <linux/netfilter_ipv4/ip_nat_helper.h> | ||
26 | #include <linux/netfilter_ipv4/ip_conntrack_helper.h> | ||
27 | #include <linux/netfilter_ipv4/ip_conntrack_amanda.h> | ||
28 | |||
29 | |||
30 | MODULE_AUTHOR("Brian J. Murrell <netfilter@interlinx.bc.ca>"); | ||
31 | MODULE_DESCRIPTION("Amanda NAT helper"); | ||
32 | MODULE_LICENSE("GPL"); | ||
33 | |||
34 | static unsigned int help(struct sk_buff **pskb, | ||
35 | enum ip_conntrack_info ctinfo, | ||
36 | unsigned int matchoff, | ||
37 | unsigned int matchlen, | ||
38 | struct ip_conntrack_expect *exp) | ||
39 | { | ||
40 | char buffer[sizeof("65535")]; | ||
41 | u_int16_t port; | ||
42 | unsigned int ret; | ||
43 | |||
44 | /* Connection comes from client. */ | ||
45 | exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port; | ||
46 | exp->dir = IP_CT_DIR_ORIGINAL; | ||
47 | |||
48 | /* When you see the packet, we need to NAT it the same as the | ||
49 | * this one (ie. same IP: it will be TCP and master is UDP). */ | ||
50 | exp->expectfn = ip_nat_follow_master; | ||
51 | |||
52 | /* Try to get same port: if not, try to change it. */ | ||
53 | for (port = ntohs(exp->saved_proto.tcp.port); port != 0; port++) { | ||
54 | exp->tuple.dst.u.tcp.port = htons(port); | ||
55 | if (ip_conntrack_expect_related(exp) == 0) | ||
56 | break; | ||
57 | } | ||
58 | |||
59 | if (port == 0) | ||
60 | return NF_DROP; | ||
61 | |||
62 | sprintf(buffer, "%u", port); | ||
63 | ret = ip_nat_mangle_udp_packet(pskb, exp->master, ctinfo, | ||
64 | matchoff, matchlen, | ||
65 | buffer, strlen(buffer)); | ||
66 | if (ret != NF_ACCEPT) | ||
67 | ip_conntrack_unexpect_related(exp); | ||
68 | return ret; | ||
69 | } | ||
70 | |||
71 | static void __exit ip_nat_amanda_fini(void) | ||
72 | { | ||
73 | rcu_assign_pointer(ip_nat_amanda_hook, NULL); | ||
74 | synchronize_rcu(); | ||
75 | } | ||
76 | |||
77 | static int __init ip_nat_amanda_init(void) | ||
78 | { | ||
79 | BUG_ON(rcu_dereference(ip_nat_amanda_hook)); | ||
80 | rcu_assign_pointer(ip_nat_amanda_hook, help); | ||
81 | return 0; | ||
82 | } | ||
83 | |||
84 | module_init(ip_nat_amanda_init); | ||
85 | module_exit(ip_nat_amanda_fini); | ||
diff --git a/net/ipv4/netfilter/ip_nat_core.c b/net/ipv4/netfilter/ip_nat_core.c deleted file mode 100644 index cf46930606f2..000000000000 --- a/net/ipv4/netfilter/ip_nat_core.c +++ /dev/null | |||
@@ -1,633 +0,0 @@ | |||
1 | /* NAT for netfilter; shared with compatibility layer. */ | ||
2 | |||
3 | /* (C) 1999-2001 Paul `Rusty' Russell | ||
4 | * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | */ | ||
10 | |||
11 | #include <linux/module.h> | ||
12 | #include <linux/types.h> | ||
13 | #include <linux/timer.h> | ||
14 | #include <linux/skbuff.h> | ||
15 | #include <linux/netfilter_ipv4.h> | ||
16 | #include <linux/vmalloc.h> | ||
17 | #include <net/checksum.h> | ||
18 | #include <net/icmp.h> | ||
19 | #include <net/ip.h> | ||
20 | #include <net/tcp.h> /* For tcp_prot in getorigdst */ | ||
21 | #include <linux/icmp.h> | ||
22 | #include <linux/udp.h> | ||
23 | #include <linux/jhash.h> | ||
24 | |||
25 | #include <linux/netfilter_ipv4/ip_conntrack.h> | ||
26 | #include <linux/netfilter_ipv4/ip_conntrack_core.h> | ||
27 | #include <linux/netfilter_ipv4/ip_conntrack_protocol.h> | ||
28 | #include <linux/netfilter_ipv4/ip_nat.h> | ||
29 | #include <linux/netfilter_ipv4/ip_nat_protocol.h> | ||
30 | #include <linux/netfilter_ipv4/ip_nat_core.h> | ||
31 | #include <linux/netfilter_ipv4/ip_nat_helper.h> | ||
32 | #include <linux/netfilter_ipv4/ip_conntrack_helper.h> | ||
33 | |||
34 | #if 0 | ||
35 | #define DEBUGP printk | ||
36 | #else | ||
37 | #define DEBUGP(format, args...) | ||
38 | #endif | ||
39 | |||
40 | DEFINE_RWLOCK(ip_nat_lock); | ||
41 | |||
42 | /* Calculated at init based on memory size */ | ||
43 | static unsigned int ip_nat_htable_size; | ||
44 | |||
45 | static struct list_head *bysource; | ||
46 | |||
47 | #define MAX_IP_NAT_PROTO 256 | ||
48 | static struct ip_nat_protocol *ip_nat_protos[MAX_IP_NAT_PROTO]; | ||
49 | |||
50 | static inline struct ip_nat_protocol * | ||
51 | __ip_nat_proto_find(u_int8_t protonum) | ||
52 | { | ||
53 | return rcu_dereference(ip_nat_protos[protonum]); | ||
54 | } | ||
55 | |||
56 | struct ip_nat_protocol * | ||
57 | ip_nat_proto_find_get(u_int8_t protonum) | ||
58 | { | ||
59 | struct ip_nat_protocol *p; | ||
60 | |||
61 | rcu_read_lock(); | ||
62 | p = __ip_nat_proto_find(protonum); | ||
63 | if (!try_module_get(p->me)) | ||
64 | p = &ip_nat_unknown_protocol; | ||
65 | rcu_read_unlock(); | ||
66 | |||
67 | return p; | ||
68 | } | ||
69 | EXPORT_SYMBOL_GPL(ip_nat_proto_find_get); | ||
70 | |||
71 | void | ||
72 | ip_nat_proto_put(struct ip_nat_protocol *p) | ||
73 | { | ||
74 | module_put(p->me); | ||
75 | } | ||
76 | EXPORT_SYMBOL_GPL(ip_nat_proto_put); | ||
77 | |||
78 | /* We keep an extra hash for each conntrack, for fast searching. */ | ||
79 | static inline unsigned int | ||
80 | hash_by_src(const struct ip_conntrack_tuple *tuple) | ||
81 | { | ||
82 | /* Original src, to ensure we map it consistently if poss. */ | ||
83 | return jhash_3words((__force u32)tuple->src.ip, tuple->src.u.all, | ||
84 | tuple->dst.protonum, 0) % ip_nat_htable_size; | ||
85 | } | ||
86 | |||
87 | /* Noone using conntrack by the time this called. */ | ||
88 | static void ip_nat_cleanup_conntrack(struct ip_conntrack *conn) | ||
89 | { | ||
90 | if (!(conn->status & IPS_NAT_DONE_MASK)) | ||
91 | return; | ||
92 | |||
93 | write_lock_bh(&ip_nat_lock); | ||
94 | list_del(&conn->nat.info.bysource); | ||
95 | write_unlock_bh(&ip_nat_lock); | ||
96 | } | ||
97 | |||
98 | /* Is this tuple already taken? (not by us) */ | ||
99 | int | ||
100 | ip_nat_used_tuple(const struct ip_conntrack_tuple *tuple, | ||
101 | const struct ip_conntrack *ignored_conntrack) | ||
102 | { | ||
103 | /* Conntrack tracking doesn't keep track of outgoing tuples; only | ||
104 | incoming ones. NAT means they don't have a fixed mapping, | ||
105 | so we invert the tuple and look for the incoming reply. | ||
106 | |||
107 | We could keep a separate hash if this proves too slow. */ | ||
108 | struct ip_conntrack_tuple reply; | ||
109 | |||
110 | invert_tuplepr(&reply, tuple); | ||
111 | return ip_conntrack_tuple_taken(&reply, ignored_conntrack); | ||
112 | } | ||
113 | EXPORT_SYMBOL(ip_nat_used_tuple); | ||
114 | |||
115 | /* If we source map this tuple so reply looks like reply_tuple, will | ||
116 | * that meet the constraints of range. */ | ||
117 | static int | ||
118 | in_range(const struct ip_conntrack_tuple *tuple, | ||
119 | const struct ip_nat_range *range) | ||
120 | { | ||
121 | struct ip_nat_protocol *proto; | ||
122 | int ret = 0; | ||
123 | |||
124 | /* If we are supposed to map IPs, then we must be in the | ||
125 | range specified, otherwise let this drag us onto a new src IP. */ | ||
126 | if (range->flags & IP_NAT_RANGE_MAP_IPS) { | ||
127 | if (ntohl(tuple->src.ip) < ntohl(range->min_ip) | ||
128 | || ntohl(tuple->src.ip) > ntohl(range->max_ip)) | ||
129 | return 0; | ||
130 | } | ||
131 | |||
132 | rcu_read_lock(); | ||
133 | proto = __ip_nat_proto_find(tuple->dst.protonum); | ||
134 | if (!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED) | ||
135 | || proto->in_range(tuple, IP_NAT_MANIP_SRC, | ||
136 | &range->min, &range->max)) | ||
137 | ret = 1; | ||
138 | rcu_read_unlock(); | ||
139 | |||
140 | return ret; | ||
141 | } | ||
142 | |||
143 | static inline int | ||
144 | same_src(const struct ip_conntrack *ct, | ||
145 | const struct ip_conntrack_tuple *tuple) | ||
146 | { | ||
147 | return (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum | ||
148 | == tuple->dst.protonum | ||
149 | && ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip | ||
150 | == tuple->src.ip | ||
151 | && ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.all | ||
152 | == tuple->src.u.all); | ||
153 | } | ||
154 | |||
155 | /* Only called for SRC manip */ | ||
156 | static int | ||
157 | find_appropriate_src(const struct ip_conntrack_tuple *tuple, | ||
158 | struct ip_conntrack_tuple *result, | ||
159 | const struct ip_nat_range *range) | ||
160 | { | ||
161 | unsigned int h = hash_by_src(tuple); | ||
162 | struct ip_conntrack *ct; | ||
163 | |||
164 | read_lock_bh(&ip_nat_lock); | ||
165 | list_for_each_entry(ct, &bysource[h], nat.info.bysource) { | ||
166 | if (same_src(ct, tuple)) { | ||
167 | /* Copy source part from reply tuple. */ | ||
168 | invert_tuplepr(result, | ||
169 | &ct->tuplehash[IP_CT_DIR_REPLY].tuple); | ||
170 | result->dst = tuple->dst; | ||
171 | |||
172 | if (in_range(result, range)) { | ||
173 | read_unlock_bh(&ip_nat_lock); | ||
174 | return 1; | ||
175 | } | ||
176 | } | ||
177 | } | ||
178 | read_unlock_bh(&ip_nat_lock); | ||
179 | return 0; | ||
180 | } | ||
181 | |||
182 | /* For [FUTURE] fragmentation handling, we want the least-used | ||
183 | src-ip/dst-ip/proto triple. Fairness doesn't come into it. Thus | ||
184 | if the range specifies 1.2.3.4 ports 10000-10005 and 1.2.3.5 ports | ||
185 | 1-65535, we don't do pro-rata allocation based on ports; we choose | ||
186 | the ip with the lowest src-ip/dst-ip/proto usage. | ||
187 | */ | ||
188 | static void | ||
189 | find_best_ips_proto(struct ip_conntrack_tuple *tuple, | ||
190 | const struct ip_nat_range *range, | ||
191 | const struct ip_conntrack *conntrack, | ||
192 | enum ip_nat_manip_type maniptype) | ||
193 | { | ||
194 | __be32 *var_ipp; | ||
195 | /* Host order */ | ||
196 | u_int32_t minip, maxip, j; | ||
197 | |||
198 | /* No IP mapping? Do nothing. */ | ||
199 | if (!(range->flags & IP_NAT_RANGE_MAP_IPS)) | ||
200 | return; | ||
201 | |||
202 | if (maniptype == IP_NAT_MANIP_SRC) | ||
203 | var_ipp = &tuple->src.ip; | ||
204 | else | ||
205 | var_ipp = &tuple->dst.ip; | ||
206 | |||
207 | /* Fast path: only one choice. */ | ||
208 | if (range->min_ip == range->max_ip) { | ||
209 | *var_ipp = range->min_ip; | ||
210 | return; | ||
211 | } | ||
212 | |||
213 | /* Hashing source and destination IPs gives a fairly even | ||
214 | * spread in practice (if there are a small number of IPs | ||
215 | * involved, there usually aren't that many connections | ||
216 | * anyway). The consistency means that servers see the same | ||
217 | * client coming from the same IP (some Internet Banking sites | ||
218 | * like this), even across reboots. */ | ||
219 | minip = ntohl(range->min_ip); | ||
220 | maxip = ntohl(range->max_ip); | ||
221 | j = jhash_2words((__force u32)tuple->src.ip, (__force u32)tuple->dst.ip, 0); | ||
222 | *var_ipp = htonl(minip + j % (maxip - minip + 1)); | ||
223 | } | ||
224 | |||
225 | /* Manipulate the tuple into the range given. For NF_IP_POST_ROUTING, | ||
226 | * we change the source to map into the range. For NF_IP_PRE_ROUTING | ||
227 | * and NF_IP_LOCAL_OUT, we change the destination to map into the | ||
228 | * range. It might not be possible to get a unique tuple, but we try. | ||
229 | * At worst (or if we race), we will end up with a final duplicate in | ||
230 | * __ip_conntrack_confirm and drop the packet. */ | ||
231 | static void | ||
232 | get_unique_tuple(struct ip_conntrack_tuple *tuple, | ||
233 | const struct ip_conntrack_tuple *orig_tuple, | ||
234 | const struct ip_nat_range *range, | ||
235 | struct ip_conntrack *conntrack, | ||
236 | enum ip_nat_manip_type maniptype) | ||
237 | { | ||
238 | struct ip_nat_protocol *proto; | ||
239 | |||
240 | /* 1) If this srcip/proto/src-proto-part is currently mapped, | ||
241 | and that same mapping gives a unique tuple within the given | ||
242 | range, use that. | ||
243 | |||
244 | This is only required for source (ie. NAT/masq) mappings. | ||
245 | So far, we don't do local source mappings, so multiple | ||
246 | manips not an issue. */ | ||
247 | if (maniptype == IP_NAT_MANIP_SRC) { | ||
248 | if (find_appropriate_src(orig_tuple, tuple, range)) { | ||
249 | DEBUGP("get_unique_tuple: Found current src map\n"); | ||
250 | if (!(range->flags & IP_NAT_RANGE_PROTO_RANDOM)) | ||
251 | if (!ip_nat_used_tuple(tuple, conntrack)) | ||
252 | return; | ||
253 | } | ||
254 | } | ||
255 | |||
256 | /* 2) Select the least-used IP/proto combination in the given | ||
257 | range. */ | ||
258 | *tuple = *orig_tuple; | ||
259 | find_best_ips_proto(tuple, range, conntrack, maniptype); | ||
260 | |||
261 | /* 3) The per-protocol part of the manip is made to map into | ||
262 | the range to make a unique tuple. */ | ||
263 | |||
264 | rcu_read_lock(); | ||
265 | proto = __ip_nat_proto_find(orig_tuple->dst.protonum); | ||
266 | |||
267 | /* Change protocol info to have some randomization */ | ||
268 | if (range->flags & IP_NAT_RANGE_PROTO_RANDOM) { | ||
269 | proto->unique_tuple(tuple, range, maniptype, conntrack); | ||
270 | goto out; | ||
271 | } | ||
272 | |||
273 | /* Only bother mapping if it's not already in range and unique */ | ||
274 | if ((!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED) | ||
275 | || proto->in_range(tuple, maniptype, &range->min, &range->max)) | ||
276 | && !ip_nat_used_tuple(tuple, conntrack)) | ||
277 | goto out; | ||
278 | |||
279 | /* Last change: get protocol to try to obtain unique tuple. */ | ||
280 | proto->unique_tuple(tuple, range, maniptype, conntrack); | ||
281 | out: | ||
282 | rcu_read_unlock(); | ||
283 | } | ||
284 | |||
285 | unsigned int | ||
286 | ip_nat_setup_info(struct ip_conntrack *conntrack, | ||
287 | const struct ip_nat_range *range, | ||
288 | unsigned int hooknum) | ||
289 | { | ||
290 | struct ip_conntrack_tuple curr_tuple, new_tuple; | ||
291 | struct ip_nat_info *info = &conntrack->nat.info; | ||
292 | int have_to_hash = !(conntrack->status & IPS_NAT_DONE_MASK); | ||
293 | enum ip_nat_manip_type maniptype = HOOK2MANIP(hooknum); | ||
294 | |||
295 | IP_NF_ASSERT(hooknum == NF_IP_PRE_ROUTING | ||
296 | || hooknum == NF_IP_POST_ROUTING | ||
297 | || hooknum == NF_IP_LOCAL_IN | ||
298 | || hooknum == NF_IP_LOCAL_OUT); | ||
299 | BUG_ON(ip_nat_initialized(conntrack, maniptype)); | ||
300 | |||
301 | /* What we've got will look like inverse of reply. Normally | ||
302 | this is what is in the conntrack, except for prior | ||
303 | manipulations (future optimization: if num_manips == 0, | ||
304 | orig_tp = | ||
305 | conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple) */ | ||
306 | invert_tuplepr(&curr_tuple, | ||
307 | &conntrack->tuplehash[IP_CT_DIR_REPLY].tuple); | ||
308 | |||
309 | get_unique_tuple(&new_tuple, &curr_tuple, range, conntrack, maniptype); | ||
310 | |||
311 | if (!ip_ct_tuple_equal(&new_tuple, &curr_tuple)) { | ||
312 | struct ip_conntrack_tuple reply; | ||
313 | |||
314 | /* Alter conntrack table so will recognize replies. */ | ||
315 | invert_tuplepr(&reply, &new_tuple); | ||
316 | ip_conntrack_alter_reply(conntrack, &reply); | ||
317 | |||
318 | /* Non-atomic: we own this at the moment. */ | ||
319 | if (maniptype == IP_NAT_MANIP_SRC) | ||
320 | conntrack->status |= IPS_SRC_NAT; | ||
321 | else | ||
322 | conntrack->status |= IPS_DST_NAT; | ||
323 | } | ||
324 | |||
325 | /* Place in source hash if this is the first time. */ | ||
326 | if (have_to_hash) { | ||
327 | unsigned int srchash | ||
328 | = hash_by_src(&conntrack->tuplehash[IP_CT_DIR_ORIGINAL] | ||
329 | .tuple); | ||
330 | write_lock_bh(&ip_nat_lock); | ||
331 | list_add(&info->bysource, &bysource[srchash]); | ||
332 | write_unlock_bh(&ip_nat_lock); | ||
333 | } | ||
334 | |||
335 | /* It's done. */ | ||
336 | if (maniptype == IP_NAT_MANIP_DST) | ||
337 | set_bit(IPS_DST_NAT_DONE_BIT, &conntrack->status); | ||
338 | else | ||
339 | set_bit(IPS_SRC_NAT_DONE_BIT, &conntrack->status); | ||
340 | |||
341 | return NF_ACCEPT; | ||
342 | } | ||
343 | EXPORT_SYMBOL(ip_nat_setup_info); | ||
344 | |||
345 | /* Returns true if succeeded. */ | ||
346 | static int | ||
347 | manip_pkt(u_int16_t proto, | ||
348 | struct sk_buff **pskb, | ||
349 | unsigned int iphdroff, | ||
350 | const struct ip_conntrack_tuple *target, | ||
351 | enum ip_nat_manip_type maniptype) | ||
352 | { | ||
353 | struct iphdr *iph; | ||
354 | struct ip_nat_protocol *p; | ||
355 | |||
356 | if (!skb_make_writable(pskb, iphdroff + sizeof(*iph))) | ||
357 | return 0; | ||
358 | |||
359 | iph = (void *)(*pskb)->data + iphdroff; | ||
360 | |||
361 | /* Manipulate protcol part. */ | ||
362 | |||
363 | /* rcu_read_lock()ed by nf_hook_slow */ | ||
364 | p = __ip_nat_proto_find(proto); | ||
365 | if (!p->manip_pkt(pskb, iphdroff, target, maniptype)) | ||
366 | return 0; | ||
367 | |||
368 | iph = (void *)(*pskb)->data + iphdroff; | ||
369 | |||
370 | if (maniptype == IP_NAT_MANIP_SRC) { | ||
371 | nf_csum_replace4(&iph->check, iph->saddr, target->src.ip); | ||
372 | iph->saddr = target->src.ip; | ||
373 | } else { | ||
374 | nf_csum_replace4(&iph->check, iph->daddr, target->dst.ip); | ||
375 | iph->daddr = target->dst.ip; | ||
376 | } | ||
377 | return 1; | ||
378 | } | ||
379 | |||
380 | /* Do packet manipulations according to ip_nat_setup_info. */ | ||
381 | unsigned int ip_nat_packet(struct ip_conntrack *ct, | ||
382 | enum ip_conntrack_info ctinfo, | ||
383 | unsigned int hooknum, | ||
384 | struct sk_buff **pskb) | ||
385 | { | ||
386 | enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); | ||
387 | unsigned long statusbit; | ||
388 | enum ip_nat_manip_type mtype = HOOK2MANIP(hooknum); | ||
389 | |||
390 | if (mtype == IP_NAT_MANIP_SRC) | ||
391 | statusbit = IPS_SRC_NAT; | ||
392 | else | ||
393 | statusbit = IPS_DST_NAT; | ||
394 | |||
395 | /* Invert if this is reply dir. */ | ||
396 | if (dir == IP_CT_DIR_REPLY) | ||
397 | statusbit ^= IPS_NAT_MASK; | ||
398 | |||
399 | /* Non-atomic: these bits don't change. */ | ||
400 | if (ct->status & statusbit) { | ||
401 | struct ip_conntrack_tuple target; | ||
402 | |||
403 | /* We are aiming to look like inverse of other direction. */ | ||
404 | invert_tuplepr(&target, &ct->tuplehash[!dir].tuple); | ||
405 | |||
406 | if (!manip_pkt(target.dst.protonum, pskb, 0, &target, mtype)) | ||
407 | return NF_DROP; | ||
408 | } | ||
409 | return NF_ACCEPT; | ||
410 | } | ||
411 | EXPORT_SYMBOL_GPL(ip_nat_packet); | ||
412 | |||
413 | /* Dir is direction ICMP is coming from (opposite to packet it contains) */ | ||
414 | int ip_nat_icmp_reply_translation(struct ip_conntrack *ct, | ||
415 | enum ip_conntrack_info ctinfo, | ||
416 | unsigned int hooknum, | ||
417 | struct sk_buff **pskb) | ||
418 | { | ||
419 | struct { | ||
420 | struct icmphdr icmp; | ||
421 | struct iphdr ip; | ||
422 | } *inside; | ||
423 | struct ip_conntrack_protocol *proto; | ||
424 | struct ip_conntrack_tuple inner, target; | ||
425 | int hdrlen = ip_hdrlen(*pskb); | ||
426 | enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); | ||
427 | unsigned long statusbit; | ||
428 | enum ip_nat_manip_type manip = HOOK2MANIP(hooknum); | ||
429 | |||
430 | if (!skb_make_writable(pskb, hdrlen + sizeof(*inside))) | ||
431 | return 0; | ||
432 | |||
433 | inside = (void *)(*pskb)->data + ip_hdrlen(*pskb); | ||
434 | |||
435 | /* We're actually going to mangle it beyond trivial checksum | ||
436 | adjustment, so make sure the current checksum is correct. */ | ||
437 | if (nf_ip_checksum(*pskb, hooknum, hdrlen, 0)) | ||
438 | return 0; | ||
439 | |||
440 | /* Must be RELATED */ | ||
441 | IP_NF_ASSERT((*pskb)->nfctinfo == IP_CT_RELATED || | ||
442 | (*pskb)->nfctinfo == IP_CT_RELATED+IP_CT_IS_REPLY); | ||
443 | |||
444 | /* Redirects on non-null nats must be dropped, else they'll | ||
445 | start talking to each other without our translation, and be | ||
446 | confused... --RR */ | ||
447 | if (inside->icmp.type == ICMP_REDIRECT) { | ||
448 | /* If NAT isn't finished, assume it and drop. */ | ||
449 | if ((ct->status & IPS_NAT_DONE_MASK) != IPS_NAT_DONE_MASK) | ||
450 | return 0; | ||
451 | |||
452 | if (ct->status & IPS_NAT_MASK) | ||
453 | return 0; | ||
454 | } | ||
455 | |||
456 | DEBUGP("icmp_reply_translation: translating error %p manp %u dir %s\n", | ||
457 | *pskb, manip, dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY"); | ||
458 | |||
459 | /* rcu_read_lock()ed by nf_hook_slow */ | ||
460 | proto = __ip_conntrack_proto_find(inside->ip.protocol); | ||
461 | if (!ip_ct_get_tuple(&inside->ip, *pskb, ip_hdrlen(*pskb) + | ||
462 | sizeof(struct icmphdr) + inside->ip.ihl*4, | ||
463 | &inner, proto)) | ||
464 | return 0; | ||
465 | |||
466 | /* Change inner back to look like incoming packet. We do the | ||
467 | opposite manip on this hook to normal, because it might not | ||
468 | pass all hooks (locally-generated ICMP). Consider incoming | ||
469 | packet: PREROUTING (DST manip), routing produces ICMP, goes | ||
470 | through POSTROUTING (which must correct the DST manip). */ | ||
471 | if (!manip_pkt(inside->ip.protocol, pskb, | ||
472 | ip_hdrlen(*pskb) + sizeof(inside->icmp), | ||
473 | &ct->tuplehash[!dir].tuple, | ||
474 | !manip)) | ||
475 | return 0; | ||
476 | |||
477 | if ((*pskb)->ip_summed != CHECKSUM_PARTIAL) { | ||
478 | /* Reloading "inside" here since manip_pkt inner. */ | ||
479 | inside = (void *)(*pskb)->data + ip_hdrlen(*pskb); | ||
480 | inside->icmp.checksum = 0; | ||
481 | inside->icmp.checksum = csum_fold(skb_checksum(*pskb, hdrlen, | ||
482 | (*pskb)->len - hdrlen, | ||
483 | 0)); | ||
484 | } | ||
485 | |||
486 | /* Change outer to look the reply to an incoming packet | ||
487 | * (proto 0 means don't invert per-proto part). */ | ||
488 | if (manip == IP_NAT_MANIP_SRC) | ||
489 | statusbit = IPS_SRC_NAT; | ||
490 | else | ||
491 | statusbit = IPS_DST_NAT; | ||
492 | |||
493 | /* Invert if this is reply dir. */ | ||
494 | if (dir == IP_CT_DIR_REPLY) | ||
495 | statusbit ^= IPS_NAT_MASK; | ||
496 | |||
497 | if (ct->status & statusbit) { | ||
498 | invert_tuplepr(&target, &ct->tuplehash[!dir].tuple); | ||
499 | if (!manip_pkt(0, pskb, 0, &target, manip)) | ||
500 | return 0; | ||
501 | } | ||
502 | |||
503 | return 1; | ||
504 | } | ||
505 | EXPORT_SYMBOL_GPL(ip_nat_icmp_reply_translation); | ||
506 | |||
507 | /* Protocol registration. */ | ||
508 | int ip_nat_protocol_register(struct ip_nat_protocol *proto) | ||
509 | { | ||
510 | int ret = 0; | ||
511 | |||
512 | write_lock_bh(&ip_nat_lock); | ||
513 | if (ip_nat_protos[proto->protonum] != &ip_nat_unknown_protocol) { | ||
514 | ret = -EBUSY; | ||
515 | goto out; | ||
516 | } | ||
517 | rcu_assign_pointer(ip_nat_protos[proto->protonum], proto); | ||
518 | out: | ||
519 | write_unlock_bh(&ip_nat_lock); | ||
520 | return ret; | ||
521 | } | ||
522 | EXPORT_SYMBOL(ip_nat_protocol_register); | ||
523 | |||
524 | /* Noone stores the protocol anywhere; simply delete it. */ | ||
525 | void ip_nat_protocol_unregister(struct ip_nat_protocol *proto) | ||
526 | { | ||
527 | write_lock_bh(&ip_nat_lock); | ||
528 | rcu_assign_pointer(ip_nat_protos[proto->protonum], | ||
529 | &ip_nat_unknown_protocol); | ||
530 | write_unlock_bh(&ip_nat_lock); | ||
531 | synchronize_rcu(); | ||
532 | } | ||
533 | EXPORT_SYMBOL(ip_nat_protocol_unregister); | ||
534 | |||
535 | #if defined(CONFIG_IP_NF_CONNTRACK_NETLINK) || \ | ||
536 | defined(CONFIG_IP_NF_CONNTRACK_NETLINK_MODULE) | ||
537 | int | ||
538 | ip_nat_port_range_to_nfattr(struct sk_buff *skb, | ||
539 | const struct ip_nat_range *range) | ||
540 | { | ||
541 | NFA_PUT(skb, CTA_PROTONAT_PORT_MIN, sizeof(__be16), | ||
542 | &range->min.tcp.port); | ||
543 | NFA_PUT(skb, CTA_PROTONAT_PORT_MAX, sizeof(__be16), | ||
544 | &range->max.tcp.port); | ||
545 | |||
546 | return 0; | ||
547 | |||
548 | nfattr_failure: | ||
549 | return -1; | ||
550 | } | ||
551 | |||
552 | int | ||
553 | ip_nat_port_nfattr_to_range(struct nfattr *tb[], struct ip_nat_range *range) | ||
554 | { | ||
555 | int ret = 0; | ||
556 | |||
557 | /* we have to return whether we actually parsed something or not */ | ||
558 | |||
559 | if (tb[CTA_PROTONAT_PORT_MIN-1]) { | ||
560 | ret = 1; | ||
561 | range->min.tcp.port = | ||
562 | *(__be16 *)NFA_DATA(tb[CTA_PROTONAT_PORT_MIN-1]); | ||
563 | } | ||
564 | |||
565 | if (!tb[CTA_PROTONAT_PORT_MAX-1]) { | ||
566 | if (ret) | ||
567 | range->max.tcp.port = range->min.tcp.port; | ||
568 | } else { | ||
569 | ret = 1; | ||
570 | range->max.tcp.port = | ||
571 | *(__be16 *)NFA_DATA(tb[CTA_PROTONAT_PORT_MAX-1]); | ||
572 | } | ||
573 | |||
574 | return ret; | ||
575 | } | ||
576 | EXPORT_SYMBOL_GPL(ip_nat_port_nfattr_to_range); | ||
577 | EXPORT_SYMBOL_GPL(ip_nat_port_range_to_nfattr); | ||
578 | #endif | ||
579 | |||
580 | static int __init ip_nat_init(void) | ||
581 | { | ||
582 | size_t i; | ||
583 | |||
584 | /* Leave them the same for the moment. */ | ||
585 | ip_nat_htable_size = ip_conntrack_htable_size; | ||
586 | |||
587 | /* One vmalloc for both hash tables */ | ||
588 | bysource = vmalloc(sizeof(struct list_head) * ip_nat_htable_size); | ||
589 | if (!bysource) | ||
590 | return -ENOMEM; | ||
591 | |||
592 | /* Sew in builtin protocols. */ | ||
593 | write_lock_bh(&ip_nat_lock); | ||
594 | for (i = 0; i < MAX_IP_NAT_PROTO; i++) | ||
595 | rcu_assign_pointer(ip_nat_protos[i], &ip_nat_unknown_protocol); | ||
596 | rcu_assign_pointer(ip_nat_protos[IPPROTO_TCP], &ip_nat_protocol_tcp); | ||
597 | rcu_assign_pointer(ip_nat_protos[IPPROTO_UDP], &ip_nat_protocol_udp); | ||
598 | rcu_assign_pointer(ip_nat_protos[IPPROTO_ICMP], &ip_nat_protocol_icmp); | ||
599 | write_unlock_bh(&ip_nat_lock); | ||
600 | |||
601 | for (i = 0; i < ip_nat_htable_size; i++) { | ||
602 | INIT_LIST_HEAD(&bysource[i]); | ||
603 | } | ||
604 | |||
605 | /* FIXME: Man, this is a hack. <SIGH> */ | ||
606 | IP_NF_ASSERT(rcu_dereference(ip_conntrack_destroyed) == NULL); | ||
607 | rcu_assign_pointer(ip_conntrack_destroyed, ip_nat_cleanup_conntrack); | ||
608 | |||
609 | /* Initialize fake conntrack so that NAT will skip it */ | ||
610 | ip_conntrack_untracked.status |= IPS_NAT_DONE_MASK; | ||
611 | return 0; | ||
612 | } | ||
613 | |||
614 | /* Clear NAT section of all conntracks, in case we're loaded again. */ | ||
615 | static int clean_nat(struct ip_conntrack *i, void *data) | ||
616 | { | ||
617 | memset(&i->nat, 0, sizeof(i->nat)); | ||
618 | i->status &= ~(IPS_NAT_MASK | IPS_NAT_DONE_MASK | IPS_SEQ_ADJUST); | ||
619 | return 0; | ||
620 | } | ||
621 | |||
622 | static void __exit ip_nat_cleanup(void) | ||
623 | { | ||
624 | ip_ct_iterate_cleanup(&clean_nat, NULL); | ||
625 | rcu_assign_pointer(ip_conntrack_destroyed, NULL); | ||
626 | synchronize_rcu(); | ||
627 | vfree(bysource); | ||
628 | } | ||
629 | |||
630 | MODULE_LICENSE("GPL"); | ||
631 | |||
632 | module_init(ip_nat_init); | ||
633 | module_exit(ip_nat_cleanup); | ||
diff --git a/net/ipv4/netfilter/ip_nat_ftp.c b/net/ipv4/netfilter/ip_nat_ftp.c deleted file mode 100644 index 32e01d8dffcb..000000000000 --- a/net/ipv4/netfilter/ip_nat_ftp.c +++ /dev/null | |||
@@ -1,180 +0,0 @@ | |||
1 | /* FTP extension for TCP NAT alteration. */ | ||
2 | |||
3 | /* (C) 1999-2001 Paul `Rusty' Russell | ||
4 | * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | */ | ||
10 | |||
11 | #include <linux/module.h> | ||
12 | #include <linux/netfilter_ipv4.h> | ||
13 | #include <linux/ip.h> | ||
14 | #include <linux/tcp.h> | ||
15 | #include <linux/moduleparam.h> | ||
16 | #include <net/tcp.h> | ||
17 | #include <linux/netfilter_ipv4/ip_nat.h> | ||
18 | #include <linux/netfilter_ipv4/ip_nat_helper.h> | ||
19 | #include <linux/netfilter_ipv4/ip_nat_rule.h> | ||
20 | #include <linux/netfilter_ipv4/ip_conntrack_ftp.h> | ||
21 | #include <linux/netfilter_ipv4/ip_conntrack_helper.h> | ||
22 | |||
23 | MODULE_LICENSE("GPL"); | ||
24 | MODULE_AUTHOR("Rusty Russell <rusty@rustcorp.com.au>"); | ||
25 | MODULE_DESCRIPTION("ftp NAT helper"); | ||
26 | |||
27 | #if 0 | ||
28 | #define DEBUGP printk | ||
29 | #else | ||
30 | #define DEBUGP(format, args...) | ||
31 | #endif | ||
32 | |||
33 | /* FIXME: Time out? --RR */ | ||
34 | |||
35 | static int | ||
36 | mangle_rfc959_packet(struct sk_buff **pskb, | ||
37 | __be32 newip, | ||
38 | u_int16_t port, | ||
39 | unsigned int matchoff, | ||
40 | unsigned int matchlen, | ||
41 | struct ip_conntrack *ct, | ||
42 | enum ip_conntrack_info ctinfo, | ||
43 | u32 *seq) | ||
44 | { | ||
45 | char buffer[sizeof("nnn,nnn,nnn,nnn,nnn,nnn")]; | ||
46 | |||
47 | sprintf(buffer, "%u,%u,%u,%u,%u,%u", | ||
48 | NIPQUAD(newip), port>>8, port&0xFF); | ||
49 | |||
50 | DEBUGP("calling ip_nat_mangle_tcp_packet\n"); | ||
51 | |||
52 | *seq += strlen(buffer) - matchlen; | ||
53 | return ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, matchoff, | ||
54 | matchlen, buffer, strlen(buffer)); | ||
55 | } | ||
56 | |||
57 | /* |1|132.235.1.2|6275| */ | ||
58 | static int | ||
59 | mangle_eprt_packet(struct sk_buff **pskb, | ||
60 | __be32 newip, | ||
61 | u_int16_t port, | ||
62 | unsigned int matchoff, | ||
63 | unsigned int matchlen, | ||
64 | struct ip_conntrack *ct, | ||
65 | enum ip_conntrack_info ctinfo, | ||
66 | u32 *seq) | ||
67 | { | ||
68 | char buffer[sizeof("|1|255.255.255.255|65535|")]; | ||
69 | |||
70 | sprintf(buffer, "|1|%u.%u.%u.%u|%u|", NIPQUAD(newip), port); | ||
71 | |||
72 | DEBUGP("calling ip_nat_mangle_tcp_packet\n"); | ||
73 | |||
74 | *seq += strlen(buffer) - matchlen; | ||
75 | return ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, matchoff, | ||
76 | matchlen, buffer, strlen(buffer)); | ||
77 | } | ||
78 | |||
79 | /* |1|132.235.1.2|6275| */ | ||
80 | static int | ||
81 | mangle_epsv_packet(struct sk_buff **pskb, | ||
82 | __be32 newip, | ||
83 | u_int16_t port, | ||
84 | unsigned int matchoff, | ||
85 | unsigned int matchlen, | ||
86 | struct ip_conntrack *ct, | ||
87 | enum ip_conntrack_info ctinfo, | ||
88 | u32 *seq) | ||
89 | { | ||
90 | char buffer[sizeof("|||65535|")]; | ||
91 | |||
92 | sprintf(buffer, "|||%u|", port); | ||
93 | |||
94 | DEBUGP("calling ip_nat_mangle_tcp_packet\n"); | ||
95 | |||
96 | *seq += strlen(buffer) - matchlen; | ||
97 | return ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, matchoff, | ||
98 | matchlen, buffer, strlen(buffer)); | ||
99 | } | ||
100 | |||
101 | static int (*mangle[])(struct sk_buff **, __be32, u_int16_t, | ||
102 | unsigned int, | ||
103 | unsigned int, | ||
104 | struct ip_conntrack *, | ||
105 | enum ip_conntrack_info, | ||
106 | u32 *seq) | ||
107 | = { [IP_CT_FTP_PORT] = mangle_rfc959_packet, | ||
108 | [IP_CT_FTP_PASV] = mangle_rfc959_packet, | ||
109 | [IP_CT_FTP_EPRT] = mangle_eprt_packet, | ||
110 | [IP_CT_FTP_EPSV] = mangle_epsv_packet | ||
111 | }; | ||
112 | |||
113 | /* So, this packet has hit the connection tracking matching code. | ||
114 | Mangle it, and change the expectation to match the new version. */ | ||
115 | static unsigned int ip_nat_ftp(struct sk_buff **pskb, | ||
116 | enum ip_conntrack_info ctinfo, | ||
117 | enum ip_ct_ftp_type type, | ||
118 | unsigned int matchoff, | ||
119 | unsigned int matchlen, | ||
120 | struct ip_conntrack_expect *exp, | ||
121 | u32 *seq) | ||
122 | { | ||
123 | __be32 newip; | ||
124 | u_int16_t port; | ||
125 | int dir = CTINFO2DIR(ctinfo); | ||
126 | struct ip_conntrack *ct = exp->master; | ||
127 | |||
128 | DEBUGP("FTP_NAT: type %i, off %u len %u\n", type, matchoff, matchlen); | ||
129 | |||
130 | /* Connection will come from wherever this packet goes, hence !dir */ | ||
131 | newip = ct->tuplehash[!dir].tuple.dst.ip; | ||
132 | exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port; | ||
133 | exp->dir = !dir; | ||
134 | |||
135 | /* When you see the packet, we need to NAT it the same as the | ||
136 | * this one. */ | ||
137 | exp->expectfn = ip_nat_follow_master; | ||
138 | |||
139 | /* Try to get same port: if not, try to change it. */ | ||
140 | for (port = ntohs(exp->saved_proto.tcp.port); port != 0; port++) { | ||
141 | exp->tuple.dst.u.tcp.port = htons(port); | ||
142 | if (ip_conntrack_expect_related(exp) == 0) | ||
143 | break; | ||
144 | } | ||
145 | |||
146 | if (port == 0) | ||
147 | return NF_DROP; | ||
148 | |||
149 | if (!mangle[type](pskb, newip, port, matchoff, matchlen, ct, ctinfo, | ||
150 | seq)) { | ||
151 | ip_conntrack_unexpect_related(exp); | ||
152 | return NF_DROP; | ||
153 | } | ||
154 | return NF_ACCEPT; | ||
155 | } | ||
156 | |||
157 | static void __exit ip_nat_ftp_fini(void) | ||
158 | { | ||
159 | rcu_assign_pointer(ip_nat_ftp_hook, NULL); | ||
160 | synchronize_rcu(); | ||
161 | } | ||
162 | |||
163 | static int __init ip_nat_ftp_init(void) | ||
164 | { | ||
165 | BUG_ON(rcu_dereference(ip_nat_ftp_hook)); | ||
166 | rcu_assign_pointer(ip_nat_ftp_hook, ip_nat_ftp); | ||
167 | return 0; | ||
168 | } | ||
169 | |||
170 | /* Prior to 2.6.11, we had a ports param. No longer, but don't break users. */ | ||
171 | static int warn_set(const char *val, struct kernel_param *kp) | ||
172 | { | ||
173 | printk(KERN_INFO KBUILD_MODNAME | ||
174 | ": kernel >= 2.6.10 only uses 'ports' for conntrack modules\n"); | ||
175 | return 0; | ||
176 | } | ||
177 | module_param_call(ports, warn_set, NULL, NULL, 0); | ||
178 | |||
179 | module_init(ip_nat_ftp_init); | ||
180 | module_exit(ip_nat_ftp_fini); | ||
diff --git a/net/ipv4/netfilter/ip_nat_helper.c b/net/ipv4/netfilter/ip_nat_helper.c deleted file mode 100644 index 4cddc2951744..000000000000 --- a/net/ipv4/netfilter/ip_nat_helper.c +++ /dev/null | |||
@@ -1,436 +0,0 @@ | |||
1 | /* ip_nat_helper.c - generic support functions for NAT helpers | ||
2 | * | ||
3 | * (C) 2000-2002 Harald Welte <laforge@netfilter.org> | ||
4 | * (C) 2003-2004 Netfilter Core Team <coreteam@netfilter.org> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | * | ||
10 | * 14 Jan 2002 Harald Welte <laforge@gnumonks.org>: | ||
11 | * - add support for SACK adjustment | ||
12 | * 14 Mar 2002 Harald Welte <laforge@gnumonks.org>: | ||
13 | * - merge SACK support into newnat API | ||
14 | * 16 Aug 2002 Brian J. Murrell <netfilter@interlinx.bc.ca>: | ||
15 | * - make ip_nat_resize_packet more generic (TCP and UDP) | ||
16 | * - add ip_nat_mangle_udp_packet | ||
17 | */ | ||
18 | #include <linux/module.h> | ||
19 | #include <linux/kmod.h> | ||
20 | #include <linux/types.h> | ||
21 | #include <linux/timer.h> | ||
22 | #include <linux/skbuff.h> | ||
23 | #include <linux/netfilter_ipv4.h> | ||
24 | #include <net/checksum.h> | ||
25 | #include <net/icmp.h> | ||
26 | #include <net/ip.h> | ||
27 | #include <net/tcp.h> | ||
28 | #include <net/udp.h> | ||
29 | |||
30 | #include <linux/netfilter_ipv4/ip_conntrack.h> | ||
31 | #include <linux/netfilter_ipv4/ip_conntrack_helper.h> | ||
32 | #include <linux/netfilter_ipv4/ip_nat.h> | ||
33 | #include <linux/netfilter_ipv4/ip_nat_protocol.h> | ||
34 | #include <linux/netfilter_ipv4/ip_nat_core.h> | ||
35 | #include <linux/netfilter_ipv4/ip_nat_helper.h> | ||
36 | |||
37 | #if 0 | ||
38 | #define DEBUGP printk | ||
39 | #define DUMP_OFFSET(x) printk("offset_before=%d, offset_after=%d, correction_pos=%u\n", x->offset_before, x->offset_after, x->correction_pos); | ||
40 | #else | ||
41 | #define DEBUGP(format, args...) | ||
42 | #define DUMP_OFFSET(x) | ||
43 | #endif | ||
44 | |||
45 | static DEFINE_SPINLOCK(ip_nat_seqofs_lock); | ||
46 | |||
47 | /* Setup TCP sequence correction given this change at this sequence */ | ||
48 | static inline void | ||
49 | adjust_tcp_sequence(u32 seq, | ||
50 | int sizediff, | ||
51 | struct ip_conntrack *ct, | ||
52 | enum ip_conntrack_info ctinfo) | ||
53 | { | ||
54 | int dir; | ||
55 | struct ip_nat_seq *this_way, *other_way; | ||
56 | |||
57 | DEBUGP("ip_nat_resize_packet: old_size = %u, new_size = %u\n", | ||
58 | (*skb)->len, new_size); | ||
59 | |||
60 | dir = CTINFO2DIR(ctinfo); | ||
61 | |||
62 | this_way = &ct->nat.info.seq[dir]; | ||
63 | other_way = &ct->nat.info.seq[!dir]; | ||
64 | |||
65 | DEBUGP("ip_nat_resize_packet: Seq_offset before: "); | ||
66 | DUMP_OFFSET(this_way); | ||
67 | |||
68 | spin_lock_bh(&ip_nat_seqofs_lock); | ||
69 | |||
70 | /* SYN adjust. If it's uninitialized, or this is after last | ||
71 | * correction, record it: we don't handle more than one | ||
72 | * adjustment in the window, but do deal with common case of a | ||
73 | * retransmit */ | ||
74 | if (this_way->offset_before == this_way->offset_after | ||
75 | || before(this_way->correction_pos, seq)) { | ||
76 | this_way->correction_pos = seq; | ||
77 | this_way->offset_before = this_way->offset_after; | ||
78 | this_way->offset_after += sizediff; | ||
79 | } | ||
80 | spin_unlock_bh(&ip_nat_seqofs_lock); | ||
81 | |||
82 | DEBUGP("ip_nat_resize_packet: Seq_offset after: "); | ||
83 | DUMP_OFFSET(this_way); | ||
84 | } | ||
85 | |||
86 | /* Frobs data inside this packet, which is linear. */ | ||
87 | static void mangle_contents(struct sk_buff *skb, | ||
88 | unsigned int dataoff, | ||
89 | unsigned int match_offset, | ||
90 | unsigned int match_len, | ||
91 | const char *rep_buffer, | ||
92 | unsigned int rep_len) | ||
93 | { | ||
94 | unsigned char *data; | ||
95 | |||
96 | BUG_ON(skb_is_nonlinear(skb)); | ||
97 | data = skb_network_header(skb) + dataoff; | ||
98 | |||
99 | /* move post-replacement */ | ||
100 | memmove(data + match_offset + rep_len, | ||
101 | data + match_offset + match_len, | ||
102 | skb->tail - (data + match_offset + match_len)); | ||
103 | |||
104 | /* insert data from buffer */ | ||
105 | memcpy(data + match_offset, rep_buffer, rep_len); | ||
106 | |||
107 | /* update skb info */ | ||
108 | if (rep_len > match_len) { | ||
109 | DEBUGP("ip_nat_mangle_packet: Extending packet by " | ||
110 | "%u from %u bytes\n", rep_len - match_len, | ||
111 | skb->len); | ||
112 | skb_put(skb, rep_len - match_len); | ||
113 | } else { | ||
114 | DEBUGP("ip_nat_mangle_packet: Shrinking packet from " | ||
115 | "%u from %u bytes\n", match_len - rep_len, | ||
116 | skb->len); | ||
117 | __skb_trim(skb, skb->len + rep_len - match_len); | ||
118 | } | ||
119 | |||
120 | /* fix IP hdr checksum information */ | ||
121 | ip_hdr(skb)->tot_len = htons(skb->len); | ||
122 | ip_send_check(ip_hdr(skb)); | ||
123 | } | ||
124 | |||
125 | /* Unusual, but possible case. */ | ||
126 | static int enlarge_skb(struct sk_buff **pskb, unsigned int extra) | ||
127 | { | ||
128 | struct sk_buff *nskb; | ||
129 | |||
130 | if ((*pskb)->len + extra > 65535) | ||
131 | return 0; | ||
132 | |||
133 | nskb = skb_copy_expand(*pskb, skb_headroom(*pskb), extra, GFP_ATOMIC); | ||
134 | if (!nskb) | ||
135 | return 0; | ||
136 | |||
137 | /* Transfer socket to new skb. */ | ||
138 | if ((*pskb)->sk) | ||
139 | skb_set_owner_w(nskb, (*pskb)->sk); | ||
140 | kfree_skb(*pskb); | ||
141 | *pskb = nskb; | ||
142 | return 1; | ||
143 | } | ||
144 | |||
145 | /* Generic function for mangling variable-length address changes inside | ||
146 | * NATed TCP connections (like the PORT XXX,XXX,XXX,XXX,XXX,XXX | ||
147 | * command in FTP). | ||
148 | * | ||
149 | * Takes care about all the nasty sequence number changes, checksumming, | ||
150 | * skb enlargement, ... | ||
151 | * | ||
152 | * */ | ||
153 | int | ||
154 | ip_nat_mangle_tcp_packet(struct sk_buff **pskb, | ||
155 | struct ip_conntrack *ct, | ||
156 | enum ip_conntrack_info ctinfo, | ||
157 | unsigned int match_offset, | ||
158 | unsigned int match_len, | ||
159 | const char *rep_buffer, | ||
160 | unsigned int rep_len) | ||
161 | { | ||
162 | struct iphdr *iph; | ||
163 | struct tcphdr *tcph; | ||
164 | int oldlen, datalen; | ||
165 | |||
166 | if (!skb_make_writable(pskb, (*pskb)->len)) | ||
167 | return 0; | ||
168 | |||
169 | if (rep_len > match_len | ||
170 | && rep_len - match_len > skb_tailroom(*pskb) | ||
171 | && !enlarge_skb(pskb, rep_len - match_len)) | ||
172 | return 0; | ||
173 | |||
174 | SKB_LINEAR_ASSERT(*pskb); | ||
175 | |||
176 | iph = ip_hdr(*pskb); | ||
177 | tcph = (void *)iph + iph->ihl*4; | ||
178 | |||
179 | oldlen = (*pskb)->len - iph->ihl*4; | ||
180 | mangle_contents(*pskb, iph->ihl*4 + tcph->doff*4, | ||
181 | match_offset, match_len, rep_buffer, rep_len); | ||
182 | |||
183 | datalen = (*pskb)->len - iph->ihl*4; | ||
184 | if ((*pskb)->ip_summed != CHECKSUM_PARTIAL) { | ||
185 | tcph->check = 0; | ||
186 | tcph->check = tcp_v4_check(datalen, | ||
187 | iph->saddr, iph->daddr, | ||
188 | csum_partial((char *)tcph, | ||
189 | datalen, 0)); | ||
190 | } else | ||
191 | nf_proto_csum_replace2(&tcph->check, *pskb, | ||
192 | htons(oldlen), htons(datalen), 1); | ||
193 | |||
194 | if (rep_len != match_len) { | ||
195 | set_bit(IPS_SEQ_ADJUST_BIT, &ct->status); | ||
196 | adjust_tcp_sequence(ntohl(tcph->seq), | ||
197 | (int)rep_len - (int)match_len, | ||
198 | ct, ctinfo); | ||
199 | /* Tell TCP window tracking about seq change */ | ||
200 | ip_conntrack_tcp_update(*pskb, ct, CTINFO2DIR(ctinfo)); | ||
201 | } | ||
202 | return 1; | ||
203 | } | ||
204 | EXPORT_SYMBOL(ip_nat_mangle_tcp_packet); | ||
205 | |||
206 | /* Generic function for mangling variable-length address changes inside | ||
207 | * NATed UDP connections (like the CONNECT DATA XXXXX MESG XXXXX INDEX XXXXX | ||
208 | * command in the Amanda protocol) | ||
209 | * | ||
210 | * Takes care about all the nasty sequence number changes, checksumming, | ||
211 | * skb enlargement, ... | ||
212 | * | ||
213 | * XXX - This function could be merged with ip_nat_mangle_tcp_packet which | ||
214 | * should be fairly easy to do. | ||
215 | */ | ||
216 | int | ||
217 | ip_nat_mangle_udp_packet(struct sk_buff **pskb, | ||
218 | struct ip_conntrack *ct, | ||
219 | enum ip_conntrack_info ctinfo, | ||
220 | unsigned int match_offset, | ||
221 | unsigned int match_len, | ||
222 | const char *rep_buffer, | ||
223 | unsigned int rep_len) | ||
224 | { | ||
225 | struct iphdr *iph; | ||
226 | struct udphdr *udph; | ||
227 | int datalen, oldlen; | ||
228 | |||
229 | /* UDP helpers might accidentally mangle the wrong packet */ | ||
230 | iph = ip_hdr(*pskb); | ||
231 | if ((*pskb)->len < iph->ihl*4 + sizeof(*udph) + | ||
232 | match_offset + match_len) | ||
233 | return 0; | ||
234 | |||
235 | if (!skb_make_writable(pskb, (*pskb)->len)) | ||
236 | return 0; | ||
237 | |||
238 | if (rep_len > match_len | ||
239 | && rep_len - match_len > skb_tailroom(*pskb) | ||
240 | && !enlarge_skb(pskb, rep_len - match_len)) | ||
241 | return 0; | ||
242 | |||
243 | iph = ip_hdr(*pskb); | ||
244 | udph = (void *)iph + iph->ihl*4; | ||
245 | |||
246 | oldlen = (*pskb)->len - iph->ihl*4; | ||
247 | mangle_contents(*pskb, iph->ihl*4 + sizeof(*udph), | ||
248 | match_offset, match_len, rep_buffer, rep_len); | ||
249 | |||
250 | /* update the length of the UDP packet */ | ||
251 | datalen = (*pskb)->len - iph->ihl*4; | ||
252 | udph->len = htons(datalen); | ||
253 | |||
254 | /* fix udp checksum if udp checksum was previously calculated */ | ||
255 | if (!udph->check && (*pskb)->ip_summed != CHECKSUM_PARTIAL) | ||
256 | return 1; | ||
257 | |||
258 | if ((*pskb)->ip_summed != CHECKSUM_PARTIAL) { | ||
259 | udph->check = 0; | ||
260 | udph->check = csum_tcpudp_magic(iph->saddr, iph->daddr, | ||
261 | datalen, IPPROTO_UDP, | ||
262 | csum_partial((char *)udph, | ||
263 | datalen, 0)); | ||
264 | if (!udph->check) | ||
265 | udph->check = CSUM_MANGLED_0; | ||
266 | } else | ||
267 | nf_proto_csum_replace2(&udph->check, *pskb, | ||
268 | htons(oldlen), htons(datalen), 1); | ||
269 | return 1; | ||
270 | } | ||
271 | EXPORT_SYMBOL(ip_nat_mangle_udp_packet); | ||
272 | |||
273 | /* Adjust one found SACK option including checksum correction */ | ||
274 | static void | ||
275 | sack_adjust(struct sk_buff *skb, | ||
276 | struct tcphdr *tcph, | ||
277 | unsigned int sackoff, | ||
278 | unsigned int sackend, | ||
279 | struct ip_nat_seq *natseq) | ||
280 | { | ||
281 | while (sackoff < sackend) { | ||
282 | struct tcp_sack_block_wire *sack; | ||
283 | __be32 new_start_seq, new_end_seq; | ||
284 | |||
285 | sack = (void *)skb->data + sackoff; | ||
286 | if (after(ntohl(sack->start_seq) - natseq->offset_before, | ||
287 | natseq->correction_pos)) | ||
288 | new_start_seq = htonl(ntohl(sack->start_seq) | ||
289 | - natseq->offset_after); | ||
290 | else | ||
291 | new_start_seq = htonl(ntohl(sack->start_seq) | ||
292 | - natseq->offset_before); | ||
293 | |||
294 | if (after(ntohl(sack->end_seq) - natseq->offset_before, | ||
295 | natseq->correction_pos)) | ||
296 | new_end_seq = htonl(ntohl(sack->end_seq) | ||
297 | - natseq->offset_after); | ||
298 | else | ||
299 | new_end_seq = htonl(ntohl(sack->end_seq) | ||
300 | - natseq->offset_before); | ||
301 | |||
302 | DEBUGP("sack_adjust: start_seq: %d->%d, end_seq: %d->%d\n", | ||
303 | ntohl(sack->start_seq), new_start_seq, | ||
304 | ntohl(sack->end_seq), new_end_seq); | ||
305 | |||
306 | nf_proto_csum_replace4(&tcph->check, skb, | ||
307 | sack->start_seq, new_start_seq, 0); | ||
308 | nf_proto_csum_replace4(&tcph->check, skb, | ||
309 | sack->end_seq, new_end_seq, 0); | ||
310 | sack->start_seq = new_start_seq; | ||
311 | sack->end_seq = new_end_seq; | ||
312 | sackoff += sizeof(*sack); | ||
313 | } | ||
314 | } | ||
315 | |||
316 | /* TCP SACK sequence number adjustment */ | ||
317 | static inline unsigned int | ||
318 | ip_nat_sack_adjust(struct sk_buff **pskb, | ||
319 | struct tcphdr *tcph, | ||
320 | struct ip_conntrack *ct, | ||
321 | enum ip_conntrack_info ctinfo) | ||
322 | { | ||
323 | unsigned int dir, optoff, optend; | ||
324 | |||
325 | optoff = ip_hdrlen(*pskb) + sizeof(struct tcphdr); | ||
326 | optend = ip_hdrlen(*pskb) + tcph->doff * 4; | ||
327 | |||
328 | if (!skb_make_writable(pskb, optend)) | ||
329 | return 0; | ||
330 | |||
331 | dir = CTINFO2DIR(ctinfo); | ||
332 | |||
333 | while (optoff < optend) { | ||
334 | /* Usually: option, length. */ | ||
335 | unsigned char *op = (*pskb)->data + optoff; | ||
336 | |||
337 | switch (op[0]) { | ||
338 | case TCPOPT_EOL: | ||
339 | return 1; | ||
340 | case TCPOPT_NOP: | ||
341 | optoff++; | ||
342 | continue; | ||
343 | default: | ||
344 | /* no partial options */ | ||
345 | if (optoff + 1 == optend | ||
346 | || optoff + op[1] > optend | ||
347 | || op[1] < 2) | ||
348 | return 0; | ||
349 | if (op[0] == TCPOPT_SACK | ||
350 | && op[1] >= 2+TCPOLEN_SACK_PERBLOCK | ||
351 | && ((op[1] - 2) % TCPOLEN_SACK_PERBLOCK) == 0) | ||
352 | sack_adjust(*pskb, tcph, optoff+2, | ||
353 | optoff+op[1], | ||
354 | &ct->nat.info.seq[!dir]); | ||
355 | optoff += op[1]; | ||
356 | } | ||
357 | } | ||
358 | return 1; | ||
359 | } | ||
360 | |||
361 | /* TCP sequence number adjustment. Returns 1 on success, 0 on failure */ | ||
362 | int | ||
363 | ip_nat_seq_adjust(struct sk_buff **pskb, | ||
364 | struct ip_conntrack *ct, | ||
365 | enum ip_conntrack_info ctinfo) | ||
366 | { | ||
367 | struct tcphdr *tcph; | ||
368 | int dir; | ||
369 | __be32 newseq, newack; | ||
370 | struct ip_nat_seq *this_way, *other_way; | ||
371 | |||
372 | dir = CTINFO2DIR(ctinfo); | ||
373 | |||
374 | this_way = &ct->nat.info.seq[dir]; | ||
375 | other_way = &ct->nat.info.seq[!dir]; | ||
376 | |||
377 | if (!skb_make_writable(pskb, ip_hdrlen(*pskb) + sizeof(*tcph))) | ||
378 | return 0; | ||
379 | |||
380 | tcph = (void *)(*pskb)->data + ip_hdrlen(*pskb); | ||
381 | if (after(ntohl(tcph->seq), this_way->correction_pos)) | ||
382 | newseq = htonl(ntohl(tcph->seq) + this_way->offset_after); | ||
383 | else | ||
384 | newseq = htonl(ntohl(tcph->seq) + this_way->offset_before); | ||
385 | |||
386 | if (after(ntohl(tcph->ack_seq) - other_way->offset_before, | ||
387 | other_way->correction_pos)) | ||
388 | newack = htonl(ntohl(tcph->ack_seq) - other_way->offset_after); | ||
389 | else | ||
390 | newack = htonl(ntohl(tcph->ack_seq) - other_way->offset_before); | ||
391 | |||
392 | nf_proto_csum_replace4(&tcph->check, *pskb, tcph->seq, newseq, 0); | ||
393 | nf_proto_csum_replace4(&tcph->check, *pskb, tcph->ack_seq, newack, 0); | ||
394 | |||
395 | DEBUGP("Adjusting sequence number from %u->%u, ack from %u->%u\n", | ||
396 | ntohl(tcph->seq), ntohl(newseq), ntohl(tcph->ack_seq), | ||
397 | ntohl(newack)); | ||
398 | |||
399 | tcph->seq = newseq; | ||
400 | tcph->ack_seq = newack; | ||
401 | |||
402 | if (!ip_nat_sack_adjust(pskb, tcph, ct, ctinfo)) | ||
403 | return 0; | ||
404 | |||
405 | ip_conntrack_tcp_update(*pskb, ct, dir); | ||
406 | |||
407 | return 1; | ||
408 | } | ||
409 | EXPORT_SYMBOL(ip_nat_seq_adjust); | ||
410 | |||
411 | /* Setup NAT on this expected conntrack so it follows master. */ | ||
412 | /* If we fail to get a free NAT slot, we'll get dropped on confirm */ | ||
413 | void ip_nat_follow_master(struct ip_conntrack *ct, | ||
414 | struct ip_conntrack_expect *exp) | ||
415 | { | ||
416 | struct ip_nat_range range; | ||
417 | |||
418 | /* This must be a fresh one. */ | ||
419 | BUG_ON(ct->status & IPS_NAT_DONE_MASK); | ||
420 | |||
421 | /* Change src to where master sends to */ | ||
422 | range.flags = IP_NAT_RANGE_MAP_IPS; | ||
423 | range.min_ip = range.max_ip | ||
424 | = ct->master->tuplehash[!exp->dir].tuple.dst.ip; | ||
425 | /* hook doesn't matter, but it has to do source manip */ | ||
426 | ip_nat_setup_info(ct, &range, NF_IP_POST_ROUTING); | ||
427 | |||
428 | /* For DST manip, map port here to where it's expected. */ | ||
429 | range.flags = (IP_NAT_RANGE_MAP_IPS | IP_NAT_RANGE_PROTO_SPECIFIED); | ||
430 | range.min = range.max = exp->saved_proto; | ||
431 | range.min_ip = range.max_ip | ||
432 | = ct->master->tuplehash[!exp->dir].tuple.src.ip; | ||
433 | /* hook doesn't matter, but it has to do destination manip */ | ||
434 | ip_nat_setup_info(ct, &range, NF_IP_PRE_ROUTING); | ||
435 | } | ||
436 | EXPORT_SYMBOL(ip_nat_follow_master); | ||
diff --git a/net/ipv4/netfilter/ip_nat_helper_h323.c b/net/ipv4/netfilter/ip_nat_helper_h323.c deleted file mode 100644 index 0d9444f9236b..000000000000 --- a/net/ipv4/netfilter/ip_nat_helper_h323.c +++ /dev/null | |||
@@ -1,611 +0,0 @@ | |||
1 | /* | ||
2 | * H.323 extension for NAT alteration. | ||
3 | * | ||
4 | * Copyright (c) 2006 Jing Min Zhao <zhaojingmin@users.sourceforge.net> | ||
5 | * | ||
6 | * This source code is licensed under General Public License version 2. | ||
7 | * | ||
8 | * Based on the 'brute force' H.323 NAT module by | ||
9 | * Jozsef Kadlecsik <kadlec@blackhole.kfki.hu> | ||
10 | */ | ||
11 | |||
12 | #include <linux/module.h> | ||
13 | #include <linux/netfilter_ipv4.h> | ||
14 | #include <linux/netfilter.h> | ||
15 | #include <linux/ip.h> | ||
16 | #include <linux/tcp.h> | ||
17 | #include <linux/moduleparam.h> | ||
18 | #include <net/tcp.h> | ||
19 | #include <linux/netfilter_ipv4/ip_nat.h> | ||
20 | #include <linux/netfilter_ipv4/ip_nat_helper.h> | ||
21 | #include <linux/netfilter_ipv4/ip_nat_rule.h> | ||
22 | #include <linux/netfilter_ipv4/ip_conntrack_tuple.h> | ||
23 | #include <linux/netfilter_ipv4/ip_conntrack_h323.h> | ||
24 | #include <linux/netfilter_ipv4/ip_conntrack_helper.h> | ||
25 | |||
26 | #if 0 | ||
27 | #define DEBUGP printk | ||
28 | #else | ||
29 | #define DEBUGP(format, args...) | ||
30 | #endif | ||
31 | |||
32 | /****************************************************************************/ | ||
33 | static int set_addr(struct sk_buff **pskb, | ||
34 | unsigned char **data, int dataoff, | ||
35 | unsigned int addroff, __be32 ip, u_int16_t port) | ||
36 | { | ||
37 | enum ip_conntrack_info ctinfo; | ||
38 | struct ip_conntrack *ct = ip_conntrack_get(*pskb, &ctinfo); | ||
39 | struct { | ||
40 | __be32 ip; | ||
41 | __be16 port; | ||
42 | } __attribute__ ((__packed__)) buf; | ||
43 | struct tcphdr _tcph, *th; | ||
44 | |||
45 | buf.ip = ip; | ||
46 | buf.port = htons(port); | ||
47 | addroff += dataoff; | ||
48 | |||
49 | if (ip_hdr(*pskb)->protocol == IPPROTO_TCP) { | ||
50 | if (!ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, | ||
51 | addroff, sizeof(buf), | ||
52 | (char *) &buf, sizeof(buf))) { | ||
53 | if (net_ratelimit()) | ||
54 | printk("ip_nat_h323: ip_nat_mangle_tcp_packet" | ||
55 | " error\n"); | ||
56 | return -1; | ||
57 | } | ||
58 | |||
59 | /* Relocate data pointer */ | ||
60 | th = skb_header_pointer(*pskb, ip_hdrlen(*pskb), | ||
61 | sizeof(_tcph), &_tcph); | ||
62 | if (th == NULL) | ||
63 | return -1; | ||
64 | *data = (*pskb)->data + ip_hdrlen(*pskb) + | ||
65 | th->doff * 4 + dataoff; | ||
66 | } else { | ||
67 | if (!ip_nat_mangle_udp_packet(pskb, ct, ctinfo, | ||
68 | addroff, sizeof(buf), | ||
69 | (char *) &buf, sizeof(buf))) { | ||
70 | if (net_ratelimit()) | ||
71 | printk("ip_nat_h323: ip_nat_mangle_udp_packet" | ||
72 | " error\n"); | ||
73 | return -1; | ||
74 | } | ||
75 | /* ip_nat_mangle_udp_packet uses skb_make_writable() to copy | ||
76 | * or pull everything in a linear buffer, so we can safely | ||
77 | * use the skb pointers now */ | ||
78 | *data = ((*pskb)->data + ip_hdrlen(*pskb) + | ||
79 | sizeof(struct udphdr)); | ||
80 | } | ||
81 | |||
82 | return 0; | ||
83 | } | ||
84 | |||
85 | /****************************************************************************/ | ||
86 | static int set_h225_addr(struct sk_buff **pskb, | ||
87 | unsigned char **data, int dataoff, | ||
88 | TransportAddress * addr, | ||
89 | __be32 ip, u_int16_t port) | ||
90 | { | ||
91 | return set_addr(pskb, data, dataoff, addr->ipAddress.ip, ip, port); | ||
92 | } | ||
93 | |||
94 | /****************************************************************************/ | ||
95 | static int set_h245_addr(struct sk_buff **pskb, | ||
96 | unsigned char **data, int dataoff, | ||
97 | H245_TransportAddress * addr, | ||
98 | __be32 ip, u_int16_t port) | ||
99 | { | ||
100 | return set_addr(pskb, data, dataoff, | ||
101 | addr->unicastAddress.iPAddress.network, ip, port); | ||
102 | } | ||
103 | |||
104 | /****************************************************************************/ | ||
105 | static int set_sig_addr(struct sk_buff **pskb, struct ip_conntrack *ct, | ||
106 | enum ip_conntrack_info ctinfo, | ||
107 | unsigned char **data, | ||
108 | TransportAddress * addr, int count) | ||
109 | { | ||
110 | struct ip_ct_h323_master *info = &ct->help.ct_h323_info; | ||
111 | int dir = CTINFO2DIR(ctinfo); | ||
112 | int i; | ||
113 | __be32 ip; | ||
114 | u_int16_t port; | ||
115 | |||
116 | for (i = 0; i < count; i++) { | ||
117 | if (get_h225_addr(*data, &addr[i], &ip, &port)) { | ||
118 | if (ip == ct->tuplehash[dir].tuple.src.ip && | ||
119 | port == info->sig_port[dir]) { | ||
120 | /* GW->GK */ | ||
121 | |||
122 | /* Fix for Gnomemeeting */ | ||
123 | if (i > 0 && | ||
124 | get_h225_addr(*data, &addr[0], | ||
125 | &ip, &port) && | ||
126 | (ntohl(ip) & 0xff000000) == 0x7f000000) | ||
127 | i = 0; | ||
128 | |||
129 | DEBUGP | ||
130 | ("ip_nat_ras: set signal address " | ||
131 | "%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n", | ||
132 | NIPQUAD(ip), port, | ||
133 | NIPQUAD(ct->tuplehash[!dir].tuple.dst. | ||
134 | ip), info->sig_port[!dir]); | ||
135 | return set_h225_addr(pskb, data, 0, &addr[i], | ||
136 | ct->tuplehash[!dir]. | ||
137 | tuple.dst.ip, | ||
138 | info->sig_port[!dir]); | ||
139 | } else if (ip == ct->tuplehash[dir].tuple.dst.ip && | ||
140 | port == info->sig_port[dir]) { | ||
141 | /* GK->GW */ | ||
142 | DEBUGP | ||
143 | ("ip_nat_ras: set signal address " | ||
144 | "%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n", | ||
145 | NIPQUAD(ip), port, | ||
146 | NIPQUAD(ct->tuplehash[!dir].tuple.src. | ||
147 | ip), info->sig_port[!dir]); | ||
148 | return set_h225_addr(pskb, data, 0, &addr[i], | ||
149 | ct->tuplehash[!dir]. | ||
150 | tuple.src.ip, | ||
151 | info->sig_port[!dir]); | ||
152 | } | ||
153 | } | ||
154 | } | ||
155 | |||
156 | return 0; | ||
157 | } | ||
158 | |||
159 | /****************************************************************************/ | ||
160 | static int set_ras_addr(struct sk_buff **pskb, struct ip_conntrack *ct, | ||
161 | enum ip_conntrack_info ctinfo, | ||
162 | unsigned char **data, | ||
163 | TransportAddress * addr, int count) | ||
164 | { | ||
165 | int dir = CTINFO2DIR(ctinfo); | ||
166 | int i; | ||
167 | __be32 ip; | ||
168 | u_int16_t port; | ||
169 | |||
170 | for (i = 0; i < count; i++) { | ||
171 | if (get_h225_addr(*data, &addr[i], &ip, &port) && | ||
172 | ip == ct->tuplehash[dir].tuple.src.ip && | ||
173 | port == ntohs(ct->tuplehash[dir].tuple.src.u.udp.port)) { | ||
174 | DEBUGP("ip_nat_ras: set rasAddress " | ||
175 | "%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n", | ||
176 | NIPQUAD(ip), port, | ||
177 | NIPQUAD(ct->tuplehash[!dir].tuple.dst.ip), | ||
178 | ntohs(ct->tuplehash[!dir].tuple.dst.u.udp. | ||
179 | port)); | ||
180 | return set_h225_addr(pskb, data, 0, &addr[i], | ||
181 | ct->tuplehash[!dir].tuple.dst.ip, | ||
182 | ntohs(ct->tuplehash[!dir].tuple. | ||
183 | dst.u.udp.port)); | ||
184 | } | ||
185 | } | ||
186 | |||
187 | return 0; | ||
188 | } | ||
189 | |||
190 | /****************************************************************************/ | ||
191 | static int nat_rtp_rtcp(struct sk_buff **pskb, struct ip_conntrack *ct, | ||
192 | enum ip_conntrack_info ctinfo, | ||
193 | unsigned char **data, int dataoff, | ||
194 | H245_TransportAddress * addr, | ||
195 | u_int16_t port, u_int16_t rtp_port, | ||
196 | struct ip_conntrack_expect *rtp_exp, | ||
197 | struct ip_conntrack_expect *rtcp_exp) | ||
198 | { | ||
199 | struct ip_ct_h323_master *info = &ct->help.ct_h323_info; | ||
200 | int dir = CTINFO2DIR(ctinfo); | ||
201 | int i; | ||
202 | u_int16_t nated_port; | ||
203 | |||
204 | /* Set expectations for NAT */ | ||
205 | rtp_exp->saved_proto.udp.port = rtp_exp->tuple.dst.u.udp.port; | ||
206 | rtp_exp->expectfn = ip_nat_follow_master; | ||
207 | rtp_exp->dir = !dir; | ||
208 | rtcp_exp->saved_proto.udp.port = rtcp_exp->tuple.dst.u.udp.port; | ||
209 | rtcp_exp->expectfn = ip_nat_follow_master; | ||
210 | rtcp_exp->dir = !dir; | ||
211 | |||
212 | /* Lookup existing expects */ | ||
213 | for (i = 0; i < H323_RTP_CHANNEL_MAX; i++) { | ||
214 | if (info->rtp_port[i][dir] == rtp_port) { | ||
215 | /* Expected */ | ||
216 | |||
217 | /* Use allocated ports first. This will refresh | ||
218 | * the expects */ | ||
219 | rtp_exp->tuple.dst.u.udp.port = | ||
220 | htons(info->rtp_port[i][dir]); | ||
221 | rtcp_exp->tuple.dst.u.udp.port = | ||
222 | htons(info->rtp_port[i][dir] + 1); | ||
223 | break; | ||
224 | } else if (info->rtp_port[i][dir] == 0) { | ||
225 | /* Not expected */ | ||
226 | break; | ||
227 | } | ||
228 | } | ||
229 | |||
230 | /* Run out of expectations */ | ||
231 | if (i >= H323_RTP_CHANNEL_MAX) { | ||
232 | if (net_ratelimit()) | ||
233 | printk("ip_nat_h323: out of expectations\n"); | ||
234 | return 0; | ||
235 | } | ||
236 | |||
237 | /* Try to get a pair of ports. */ | ||
238 | for (nated_port = ntohs(rtp_exp->tuple.dst.u.udp.port); | ||
239 | nated_port != 0; nated_port += 2) { | ||
240 | rtp_exp->tuple.dst.u.udp.port = htons(nated_port); | ||
241 | if (ip_conntrack_expect_related(rtp_exp) == 0) { | ||
242 | rtcp_exp->tuple.dst.u.udp.port = | ||
243 | htons(nated_port + 1); | ||
244 | if (ip_conntrack_expect_related(rtcp_exp) == 0) | ||
245 | break; | ||
246 | ip_conntrack_unexpect_related(rtp_exp); | ||
247 | } | ||
248 | } | ||
249 | |||
250 | if (nated_port == 0) { /* No port available */ | ||
251 | if (net_ratelimit()) | ||
252 | printk("ip_nat_h323: out of RTP ports\n"); | ||
253 | return 0; | ||
254 | } | ||
255 | |||
256 | /* Modify signal */ | ||
257 | if (set_h245_addr(pskb, data, dataoff, addr, | ||
258 | ct->tuplehash[!dir].tuple.dst.ip, | ||
259 | (port & 1) ? nated_port + 1 : nated_port) == 0) { | ||
260 | /* Save ports */ | ||
261 | info->rtp_port[i][dir] = rtp_port; | ||
262 | info->rtp_port[i][!dir] = nated_port; | ||
263 | } else { | ||
264 | ip_conntrack_unexpect_related(rtp_exp); | ||
265 | ip_conntrack_unexpect_related(rtcp_exp); | ||
266 | return -1; | ||
267 | } | ||
268 | |||
269 | /* Success */ | ||
270 | DEBUGP("ip_nat_h323: expect RTP %u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n", | ||
271 | NIPQUAD(rtp_exp->tuple.src.ip), | ||
272 | ntohs(rtp_exp->tuple.src.u.udp.port), | ||
273 | NIPQUAD(rtp_exp->tuple.dst.ip), | ||
274 | ntohs(rtp_exp->tuple.dst.u.udp.port)); | ||
275 | DEBUGP("ip_nat_h323: expect RTCP %u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n", | ||
276 | NIPQUAD(rtcp_exp->tuple.src.ip), | ||
277 | ntohs(rtcp_exp->tuple.src.u.udp.port), | ||
278 | NIPQUAD(rtcp_exp->tuple.dst.ip), | ||
279 | ntohs(rtcp_exp->tuple.dst.u.udp.port)); | ||
280 | |||
281 | return 0; | ||
282 | } | ||
283 | |||
284 | /****************************************************************************/ | ||
285 | static int nat_t120(struct sk_buff **pskb, struct ip_conntrack *ct, | ||
286 | enum ip_conntrack_info ctinfo, | ||
287 | unsigned char **data, int dataoff, | ||
288 | H245_TransportAddress * addr, u_int16_t port, | ||
289 | struct ip_conntrack_expect *exp) | ||
290 | { | ||
291 | int dir = CTINFO2DIR(ctinfo); | ||
292 | u_int16_t nated_port = port; | ||
293 | |||
294 | /* Set expectations for NAT */ | ||
295 | exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port; | ||
296 | exp->expectfn = ip_nat_follow_master; | ||
297 | exp->dir = !dir; | ||
298 | |||
299 | /* Try to get same port: if not, try to change it. */ | ||
300 | for (; nated_port != 0; nated_port++) { | ||
301 | exp->tuple.dst.u.tcp.port = htons(nated_port); | ||
302 | if (ip_conntrack_expect_related(exp) == 0) | ||
303 | break; | ||
304 | } | ||
305 | |||
306 | if (nated_port == 0) { /* No port available */ | ||
307 | if (net_ratelimit()) | ||
308 | printk("ip_nat_h323: out of TCP ports\n"); | ||
309 | return 0; | ||
310 | } | ||
311 | |||
312 | /* Modify signal */ | ||
313 | if (set_h245_addr(pskb, data, dataoff, addr, | ||
314 | ct->tuplehash[!dir].tuple.dst.ip, nated_port) < 0) { | ||
315 | ip_conntrack_unexpect_related(exp); | ||
316 | return -1; | ||
317 | } | ||
318 | |||
319 | DEBUGP("ip_nat_h323: expect T.120 %u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n", | ||
320 | NIPQUAD(exp->tuple.src.ip), ntohs(exp->tuple.src.u.tcp.port), | ||
321 | NIPQUAD(exp->tuple.dst.ip), ntohs(exp->tuple.dst.u.tcp.port)); | ||
322 | |||
323 | return 0; | ||
324 | } | ||
325 | |||
326 | /**************************************************************************** | ||
327 | * This conntrack expect function replaces ip_conntrack_h245_expect() | ||
328 | * which was set by ip_conntrack_helper_h323.c. It calls both | ||
329 | * ip_nat_follow_master() and ip_conntrack_h245_expect() | ||
330 | ****************************************************************************/ | ||
331 | static void ip_nat_h245_expect(struct ip_conntrack *new, | ||
332 | struct ip_conntrack_expect *this) | ||
333 | { | ||
334 | ip_nat_follow_master(new, this); | ||
335 | ip_conntrack_h245_expect(new, this); | ||
336 | } | ||
337 | |||
338 | /****************************************************************************/ | ||
339 | static int nat_h245(struct sk_buff **pskb, struct ip_conntrack *ct, | ||
340 | enum ip_conntrack_info ctinfo, | ||
341 | unsigned char **data, int dataoff, | ||
342 | TransportAddress * addr, u_int16_t port, | ||
343 | struct ip_conntrack_expect *exp) | ||
344 | { | ||
345 | struct ip_ct_h323_master *info = &ct->help.ct_h323_info; | ||
346 | int dir = CTINFO2DIR(ctinfo); | ||
347 | u_int16_t nated_port = port; | ||
348 | |||
349 | /* Set expectations for NAT */ | ||
350 | exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port; | ||
351 | exp->expectfn = ip_nat_h245_expect; | ||
352 | exp->dir = !dir; | ||
353 | |||
354 | /* Check existing expects */ | ||
355 | if (info->sig_port[dir] == port) | ||
356 | nated_port = info->sig_port[!dir]; | ||
357 | |||
358 | /* Try to get same port: if not, try to change it. */ | ||
359 | for (; nated_port != 0; nated_port++) { | ||
360 | exp->tuple.dst.u.tcp.port = htons(nated_port); | ||
361 | if (ip_conntrack_expect_related(exp) == 0) | ||
362 | break; | ||
363 | } | ||
364 | |||
365 | if (nated_port == 0) { /* No port available */ | ||
366 | if (net_ratelimit()) | ||
367 | printk("ip_nat_q931: out of TCP ports\n"); | ||
368 | return 0; | ||
369 | } | ||
370 | |||
371 | /* Modify signal */ | ||
372 | if (set_h225_addr(pskb, data, dataoff, addr, | ||
373 | ct->tuplehash[!dir].tuple.dst.ip, | ||
374 | nated_port) == 0) { | ||
375 | /* Save ports */ | ||
376 | info->sig_port[dir] = port; | ||
377 | info->sig_port[!dir] = nated_port; | ||
378 | } else { | ||
379 | ip_conntrack_unexpect_related(exp); | ||
380 | return -1; | ||
381 | } | ||
382 | |||
383 | DEBUGP("ip_nat_q931: expect H.245 %u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n", | ||
384 | NIPQUAD(exp->tuple.src.ip), ntohs(exp->tuple.src.u.tcp.port), | ||
385 | NIPQUAD(exp->tuple.dst.ip), ntohs(exp->tuple.dst.u.tcp.port)); | ||
386 | |||
387 | return 0; | ||
388 | } | ||
389 | |||
390 | /**************************************************************************** | ||
391 | * This conntrack expect function replaces ip_conntrack_q931_expect() | ||
392 | * which was set by ip_conntrack_helper_h323.c. | ||
393 | ****************************************************************************/ | ||
394 | static void ip_nat_q931_expect(struct ip_conntrack *new, | ||
395 | struct ip_conntrack_expect *this) | ||
396 | { | ||
397 | struct ip_nat_range range; | ||
398 | |||
399 | if (this->tuple.src.ip != 0) { /* Only accept calls from GK */ | ||
400 | ip_nat_follow_master(new, this); | ||
401 | goto out; | ||
402 | } | ||
403 | |||
404 | /* This must be a fresh one. */ | ||
405 | BUG_ON(new->status & IPS_NAT_DONE_MASK); | ||
406 | |||
407 | /* Change src to where master sends to */ | ||
408 | range.flags = IP_NAT_RANGE_MAP_IPS; | ||
409 | range.min_ip = range.max_ip = new->tuplehash[!this->dir].tuple.src.ip; | ||
410 | |||
411 | /* hook doesn't matter, but it has to do source manip */ | ||
412 | ip_nat_setup_info(new, &range, NF_IP_POST_ROUTING); | ||
413 | |||
414 | /* For DST manip, map port here to where it's expected. */ | ||
415 | range.flags = (IP_NAT_RANGE_MAP_IPS | IP_NAT_RANGE_PROTO_SPECIFIED); | ||
416 | range.min = range.max = this->saved_proto; | ||
417 | range.min_ip = range.max_ip = | ||
418 | new->master->tuplehash[!this->dir].tuple.src.ip; | ||
419 | |||
420 | /* hook doesn't matter, but it has to do destination manip */ | ||
421 | ip_nat_setup_info(new, &range, NF_IP_PRE_ROUTING); | ||
422 | |||
423 | out: | ||
424 | ip_conntrack_q931_expect(new, this); | ||
425 | } | ||
426 | |||
427 | /****************************************************************************/ | ||
428 | static int nat_q931(struct sk_buff **pskb, struct ip_conntrack *ct, | ||
429 | enum ip_conntrack_info ctinfo, | ||
430 | unsigned char **data, TransportAddress * addr, int idx, | ||
431 | u_int16_t port, struct ip_conntrack_expect *exp) | ||
432 | { | ||
433 | struct ip_ct_h323_master *info = &ct->help.ct_h323_info; | ||
434 | int dir = CTINFO2DIR(ctinfo); | ||
435 | u_int16_t nated_port = port; | ||
436 | __be32 ip; | ||
437 | |||
438 | /* Set expectations for NAT */ | ||
439 | exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port; | ||
440 | exp->expectfn = ip_nat_q931_expect; | ||
441 | exp->dir = !dir; | ||
442 | |||
443 | /* Check existing expects */ | ||
444 | if (info->sig_port[dir] == port) | ||
445 | nated_port = info->sig_port[!dir]; | ||
446 | |||
447 | /* Try to get same port: if not, try to change it. */ | ||
448 | for (; nated_port != 0; nated_port++) { | ||
449 | exp->tuple.dst.u.tcp.port = htons(nated_port); | ||
450 | if (ip_conntrack_expect_related(exp) == 0) | ||
451 | break; | ||
452 | } | ||
453 | |||
454 | if (nated_port == 0) { /* No port available */ | ||
455 | if (net_ratelimit()) | ||
456 | printk("ip_nat_ras: out of TCP ports\n"); | ||
457 | return 0; | ||
458 | } | ||
459 | |||
460 | /* Modify signal */ | ||
461 | if (set_h225_addr(pskb, data, 0, &addr[idx], | ||
462 | ct->tuplehash[!dir].tuple.dst.ip, | ||
463 | nated_port) == 0) { | ||
464 | /* Save ports */ | ||
465 | info->sig_port[dir] = port; | ||
466 | info->sig_port[!dir] = nated_port; | ||
467 | |||
468 | /* Fix for Gnomemeeting */ | ||
469 | if (idx > 0 && | ||
470 | get_h225_addr(*data, &addr[0], &ip, &port) && | ||
471 | (ntohl(ip) & 0xff000000) == 0x7f000000) { | ||
472 | set_h225_addr_hook(pskb, data, 0, &addr[0], | ||
473 | ct->tuplehash[!dir].tuple.dst.ip, | ||
474 | info->sig_port[!dir]); | ||
475 | } | ||
476 | } else { | ||
477 | ip_conntrack_unexpect_related(exp); | ||
478 | return -1; | ||
479 | } | ||
480 | |||
481 | /* Success */ | ||
482 | DEBUGP("ip_nat_ras: expect Q.931 %u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n", | ||
483 | NIPQUAD(exp->tuple.src.ip), ntohs(exp->tuple.src.u.tcp.port), | ||
484 | NIPQUAD(exp->tuple.dst.ip), ntohs(exp->tuple.dst.u.tcp.port)); | ||
485 | |||
486 | return 0; | ||
487 | } | ||
488 | |||
489 | /****************************************************************************/ | ||
490 | static void ip_nat_callforwarding_expect(struct ip_conntrack *new, | ||
491 | struct ip_conntrack_expect *this) | ||
492 | { | ||
493 | struct ip_nat_range range; | ||
494 | |||
495 | /* This must be a fresh one. */ | ||
496 | BUG_ON(new->status & IPS_NAT_DONE_MASK); | ||
497 | |||
498 | /* Change src to where master sends to */ | ||
499 | range.flags = IP_NAT_RANGE_MAP_IPS; | ||
500 | range.min_ip = range.max_ip = new->tuplehash[!this->dir].tuple.src.ip; | ||
501 | |||
502 | /* hook doesn't matter, but it has to do source manip */ | ||
503 | ip_nat_setup_info(new, &range, NF_IP_POST_ROUTING); | ||
504 | |||
505 | /* For DST manip, map port here to where it's expected. */ | ||
506 | range.flags = (IP_NAT_RANGE_MAP_IPS | IP_NAT_RANGE_PROTO_SPECIFIED); | ||
507 | range.min = range.max = this->saved_proto; | ||
508 | range.min_ip = range.max_ip = this->saved_ip; | ||
509 | |||
510 | /* hook doesn't matter, but it has to do destination manip */ | ||
511 | ip_nat_setup_info(new, &range, NF_IP_PRE_ROUTING); | ||
512 | |||
513 | ip_conntrack_q931_expect(new, this); | ||
514 | } | ||
515 | |||
516 | /****************************************************************************/ | ||
517 | static int nat_callforwarding(struct sk_buff **pskb, struct ip_conntrack *ct, | ||
518 | enum ip_conntrack_info ctinfo, | ||
519 | unsigned char **data, int dataoff, | ||
520 | TransportAddress * addr, u_int16_t port, | ||
521 | struct ip_conntrack_expect *exp) | ||
522 | { | ||
523 | int dir = CTINFO2DIR(ctinfo); | ||
524 | u_int16_t nated_port; | ||
525 | |||
526 | /* Set expectations for NAT */ | ||
527 | exp->saved_ip = exp->tuple.dst.ip; | ||
528 | exp->tuple.dst.ip = ct->tuplehash[!dir].tuple.dst.ip; | ||
529 | exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port; | ||
530 | exp->expectfn = ip_nat_callforwarding_expect; | ||
531 | exp->dir = !dir; | ||
532 | |||
533 | /* Try to get same port: if not, try to change it. */ | ||
534 | for (nated_port = port; nated_port != 0; nated_port++) { | ||
535 | exp->tuple.dst.u.tcp.port = htons(nated_port); | ||
536 | if (ip_conntrack_expect_related(exp) == 0) | ||
537 | break; | ||
538 | } | ||
539 | |||
540 | if (nated_port == 0) { /* No port available */ | ||
541 | if (net_ratelimit()) | ||
542 | printk("ip_nat_q931: out of TCP ports\n"); | ||
543 | return 0; | ||
544 | } | ||
545 | |||
546 | /* Modify signal */ | ||
547 | if (!set_h225_addr(pskb, data, dataoff, addr, | ||
548 | ct->tuplehash[!dir].tuple.dst.ip, | ||
549 | nated_port) == 0) { | ||
550 | ip_conntrack_unexpect_related(exp); | ||
551 | return -1; | ||
552 | } | ||
553 | |||
554 | /* Success */ | ||
555 | DEBUGP("ip_nat_q931: expect Call Forwarding " | ||
556 | "%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n", | ||
557 | NIPQUAD(exp->tuple.src.ip), ntohs(exp->tuple.src.u.tcp.port), | ||
558 | NIPQUAD(exp->tuple.dst.ip), ntohs(exp->tuple.dst.u.tcp.port)); | ||
559 | |||
560 | return 0; | ||
561 | } | ||
562 | |||
563 | /****************************************************************************/ | ||
564 | static int __init init(void) | ||
565 | { | ||
566 | BUG_ON(rcu_dereference(set_h245_addr_hook) != NULL); | ||
567 | BUG_ON(rcu_dereference(set_h225_addr_hook) != NULL); | ||
568 | BUG_ON(rcu_dereference(set_sig_addr_hook) != NULL); | ||
569 | BUG_ON(rcu_dereference(set_ras_addr_hook) != NULL); | ||
570 | BUG_ON(rcu_dereference(nat_rtp_rtcp_hook) != NULL); | ||
571 | BUG_ON(rcu_dereference(nat_t120_hook) != NULL); | ||
572 | BUG_ON(rcu_dereference(nat_h245_hook) != NULL); | ||
573 | BUG_ON(rcu_dereference(nat_callforwarding_hook) != NULL); | ||
574 | BUG_ON(rcu_dereference(nat_q931_hook) != NULL); | ||
575 | |||
576 | rcu_assign_pointer(set_h245_addr_hook, set_h245_addr); | ||
577 | rcu_assign_pointer(set_h225_addr_hook, set_h225_addr); | ||
578 | rcu_assign_pointer(set_sig_addr_hook, set_sig_addr); | ||
579 | rcu_assign_pointer(set_ras_addr_hook, set_ras_addr); | ||
580 | rcu_assign_pointer(nat_rtp_rtcp_hook, nat_rtp_rtcp); | ||
581 | rcu_assign_pointer(nat_t120_hook, nat_t120); | ||
582 | rcu_assign_pointer(nat_h245_hook, nat_h245); | ||
583 | rcu_assign_pointer(nat_callforwarding_hook, nat_callforwarding); | ||
584 | rcu_assign_pointer(nat_q931_hook, nat_q931); | ||
585 | |||
586 | DEBUGP("ip_nat_h323: init success\n"); | ||
587 | return 0; | ||
588 | } | ||
589 | |||
590 | /****************************************************************************/ | ||
591 | static void __exit fini(void) | ||
592 | { | ||
593 | rcu_assign_pointer(set_h245_addr_hook, NULL); | ||
594 | rcu_assign_pointer(set_h225_addr_hook, NULL); | ||
595 | rcu_assign_pointer(set_sig_addr_hook, NULL); | ||
596 | rcu_assign_pointer(set_ras_addr_hook, NULL); | ||
597 | rcu_assign_pointer(nat_rtp_rtcp_hook, NULL); | ||
598 | rcu_assign_pointer(nat_t120_hook, NULL); | ||
599 | rcu_assign_pointer(nat_h245_hook, NULL); | ||
600 | rcu_assign_pointer(nat_callforwarding_hook, NULL); | ||
601 | rcu_assign_pointer(nat_q931_hook, NULL); | ||
602 | synchronize_rcu(); | ||
603 | } | ||
604 | |||
605 | /****************************************************************************/ | ||
606 | module_init(init); | ||
607 | module_exit(fini); | ||
608 | |||
609 | MODULE_AUTHOR("Jing Min Zhao <zhaojingmin@users.sourceforge.net>"); | ||
610 | MODULE_DESCRIPTION("H.323 NAT helper"); | ||
611 | MODULE_LICENSE("GPL"); | ||
diff --git a/net/ipv4/netfilter/ip_nat_helper_pptp.c b/net/ipv4/netfilter/ip_nat_helper_pptp.c deleted file mode 100644 index 24ce4a5023d7..000000000000 --- a/net/ipv4/netfilter/ip_nat_helper_pptp.c +++ /dev/null | |||
@@ -1,350 +0,0 @@ | |||
1 | /* | ||
2 | * ip_nat_pptp.c - Version 3.0 | ||
3 | * | ||
4 | * NAT support for PPTP (Point to Point Tunneling Protocol). | ||
5 | * PPTP is a a protocol for creating virtual private networks. | ||
6 | * It is a specification defined by Microsoft and some vendors | ||
7 | * working with Microsoft. PPTP is built on top of a modified | ||
8 | * version of the Internet Generic Routing Encapsulation Protocol. | ||
9 | * GRE is defined in RFC 1701 and RFC 1702. Documentation of | ||
10 | * PPTP can be found in RFC 2637 | ||
11 | * | ||
12 | * (C) 2000-2005 by Harald Welte <laforge@gnumonks.org> | ||
13 | * | ||
14 | * Development of this code funded by Astaro AG (http://www.astaro.com/) | ||
15 | * | ||
16 | * TODO: - NAT to a unique tuple, not to TCP source port | ||
17 | * (needs netfilter tuple reservation) | ||
18 | * | ||
19 | * Changes: | ||
20 | * 2002-02-10 - Version 1.3 | ||
21 | * - Use ip_nat_mangle_tcp_packet() because of cloned skb's | ||
22 | * in local connections (Philip Craig <philipc@snapgear.com>) | ||
23 | * - add checks for magicCookie and pptp version | ||
24 | * - make argument list of pptp_{out,in}bound_packet() shorter | ||
25 | * - move to C99 style initializers | ||
26 | * - print version number at module loadtime | ||
27 | * 2003-09-22 - Version 1.5 | ||
28 | * - use SNATed tcp sourceport as callid, since we get called before | ||
29 | * TCP header is mangled (Philip Craig <philipc@snapgear.com>) | ||
30 | * 2004-10-22 - Version 2.0 | ||
31 | * - kernel 2.6.x version | ||
32 | * 2005-06-10 - Version 3.0 | ||
33 | * - kernel >= 2.6.11 version, | ||
34 | * funded by Oxcoda NetBox Blue (http://www.netboxblue.com/) | ||
35 | * | ||
36 | */ | ||
37 | |||
38 | #include <linux/module.h> | ||
39 | #include <linux/ip.h> | ||
40 | #include <linux/tcp.h> | ||
41 | #include <net/tcp.h> | ||
42 | |||
43 | #include <linux/netfilter_ipv4/ip_nat.h> | ||
44 | #include <linux/netfilter_ipv4/ip_nat_rule.h> | ||
45 | #include <linux/netfilter_ipv4/ip_nat_helper.h> | ||
46 | #include <linux/netfilter_ipv4/ip_nat_pptp.h> | ||
47 | #include <linux/netfilter_ipv4/ip_conntrack_core.h> | ||
48 | #include <linux/netfilter_ipv4/ip_conntrack_helper.h> | ||
49 | #include <linux/netfilter_ipv4/ip_conntrack_proto_gre.h> | ||
50 | #include <linux/netfilter_ipv4/ip_conntrack_pptp.h> | ||
51 | |||
52 | #define IP_NAT_PPTP_VERSION "3.0" | ||
53 | |||
54 | #define REQ_CID(req, off) (*(__be16 *)((char *)(req) + (off))) | ||
55 | |||
56 | MODULE_LICENSE("GPL"); | ||
57 | MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>"); | ||
58 | MODULE_DESCRIPTION("Netfilter NAT helper module for PPTP"); | ||
59 | |||
60 | |||
61 | #if 0 | ||
62 | extern const char *pptp_msg_name[]; | ||
63 | #define DEBUGP(format, args...) printk(KERN_DEBUG "%s:%s: " format, __FILE__, \ | ||
64 | __FUNCTION__, ## args) | ||
65 | #else | ||
66 | #define DEBUGP(format, args...) | ||
67 | #endif | ||
68 | |||
69 | static void pptp_nat_expected(struct ip_conntrack *ct, | ||
70 | struct ip_conntrack_expect *exp) | ||
71 | { | ||
72 | struct ip_conntrack *master = ct->master; | ||
73 | struct ip_conntrack_expect *other_exp; | ||
74 | struct ip_conntrack_tuple t; | ||
75 | struct ip_ct_pptp_master *ct_pptp_info; | ||
76 | struct ip_nat_pptp *nat_pptp_info; | ||
77 | struct ip_nat_range range; | ||
78 | |||
79 | ct_pptp_info = &master->help.ct_pptp_info; | ||
80 | nat_pptp_info = &master->nat.help.nat_pptp_info; | ||
81 | |||
82 | /* And here goes the grand finale of corrosion... */ | ||
83 | |||
84 | if (exp->dir == IP_CT_DIR_ORIGINAL) { | ||
85 | DEBUGP("we are PNS->PAC\n"); | ||
86 | /* therefore, build tuple for PAC->PNS */ | ||
87 | t.src.ip = master->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip; | ||
88 | t.src.u.gre.key = master->help.ct_pptp_info.pac_call_id; | ||
89 | t.dst.ip = master->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip; | ||
90 | t.dst.u.gre.key = master->help.ct_pptp_info.pns_call_id; | ||
91 | t.dst.protonum = IPPROTO_GRE; | ||
92 | } else { | ||
93 | DEBUGP("we are PAC->PNS\n"); | ||
94 | /* build tuple for PNS->PAC */ | ||
95 | t.src.ip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip; | ||
96 | t.src.u.gre.key = master->nat.help.nat_pptp_info.pns_call_id; | ||
97 | t.dst.ip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip; | ||
98 | t.dst.u.gre.key = master->nat.help.nat_pptp_info.pac_call_id; | ||
99 | t.dst.protonum = IPPROTO_GRE; | ||
100 | } | ||
101 | |||
102 | DEBUGP("trying to unexpect other dir: "); | ||
103 | DUMP_TUPLE(&t); | ||
104 | other_exp = ip_conntrack_expect_find_get(&t); | ||
105 | if (other_exp) { | ||
106 | ip_conntrack_unexpect_related(other_exp); | ||
107 | ip_conntrack_expect_put(other_exp); | ||
108 | DEBUGP("success\n"); | ||
109 | } else { | ||
110 | DEBUGP("not found!\n"); | ||
111 | } | ||
112 | |||
113 | /* This must be a fresh one. */ | ||
114 | BUG_ON(ct->status & IPS_NAT_DONE_MASK); | ||
115 | |||
116 | /* Change src to where master sends to */ | ||
117 | range.flags = IP_NAT_RANGE_MAP_IPS; | ||
118 | range.min_ip = range.max_ip | ||
119 | = ct->master->tuplehash[!exp->dir].tuple.dst.ip; | ||
120 | if (exp->dir == IP_CT_DIR_ORIGINAL) { | ||
121 | range.flags |= IP_NAT_RANGE_PROTO_SPECIFIED; | ||
122 | range.min = range.max = exp->saved_proto; | ||
123 | } | ||
124 | /* hook doesn't matter, but it has to do source manip */ | ||
125 | ip_nat_setup_info(ct, &range, NF_IP_POST_ROUTING); | ||
126 | |||
127 | /* For DST manip, map port here to where it's expected. */ | ||
128 | range.flags = IP_NAT_RANGE_MAP_IPS; | ||
129 | range.min_ip = range.max_ip | ||
130 | = ct->master->tuplehash[!exp->dir].tuple.src.ip; | ||
131 | if (exp->dir == IP_CT_DIR_REPLY) { | ||
132 | range.flags |= IP_NAT_RANGE_PROTO_SPECIFIED; | ||
133 | range.min = range.max = exp->saved_proto; | ||
134 | } | ||
135 | /* hook doesn't matter, but it has to do destination manip */ | ||
136 | ip_nat_setup_info(ct, &range, NF_IP_PRE_ROUTING); | ||
137 | } | ||
138 | |||
139 | /* outbound packets == from PNS to PAC */ | ||
140 | static int | ||
141 | pptp_outbound_pkt(struct sk_buff **pskb, | ||
142 | struct ip_conntrack *ct, | ||
143 | enum ip_conntrack_info ctinfo, | ||
144 | struct PptpControlHeader *ctlh, | ||
145 | union pptp_ctrl_union *pptpReq) | ||
146 | |||
147 | { | ||
148 | struct ip_ct_pptp_master *ct_pptp_info = &ct->help.ct_pptp_info; | ||
149 | struct ip_nat_pptp *nat_pptp_info = &ct->nat.help.nat_pptp_info; | ||
150 | u_int16_t msg; | ||
151 | __be16 new_callid; | ||
152 | unsigned int cid_off; | ||
153 | |||
154 | new_callid = ct_pptp_info->pns_call_id; | ||
155 | |||
156 | switch (msg = ntohs(ctlh->messageType)) { | ||
157 | case PPTP_OUT_CALL_REQUEST: | ||
158 | cid_off = offsetof(union pptp_ctrl_union, ocreq.callID); | ||
159 | /* FIXME: ideally we would want to reserve a call ID | ||
160 | * here. current netfilter NAT core is not able to do | ||
161 | * this :( For now we use TCP source port. This breaks | ||
162 | * multiple calls within one control session */ | ||
163 | |||
164 | /* save original call ID in nat_info */ | ||
165 | nat_pptp_info->pns_call_id = ct_pptp_info->pns_call_id; | ||
166 | |||
167 | /* don't use tcph->source since we are at a DSTmanip | ||
168 | * hook (e.g. PREROUTING) and pkt is not mangled yet */ | ||
169 | new_callid = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.tcp.port; | ||
170 | |||
171 | /* save new call ID in ct info */ | ||
172 | ct_pptp_info->pns_call_id = new_callid; | ||
173 | break; | ||
174 | case PPTP_IN_CALL_REPLY: | ||
175 | cid_off = offsetof(union pptp_ctrl_union, icack.callID); | ||
176 | break; | ||
177 | case PPTP_CALL_CLEAR_REQUEST: | ||
178 | cid_off = offsetof(union pptp_ctrl_union, clrreq.callID); | ||
179 | break; | ||
180 | default: | ||
181 | DEBUGP("unknown outbound packet 0x%04x:%s\n", msg, | ||
182 | (msg <= PPTP_MSG_MAX)? | ||
183 | pptp_msg_name[msg]:pptp_msg_name[0]); | ||
184 | /* fall through */ | ||
185 | |||
186 | case PPTP_SET_LINK_INFO: | ||
187 | /* only need to NAT in case PAC is behind NAT box */ | ||
188 | case PPTP_START_SESSION_REQUEST: | ||
189 | case PPTP_START_SESSION_REPLY: | ||
190 | case PPTP_STOP_SESSION_REQUEST: | ||
191 | case PPTP_STOP_SESSION_REPLY: | ||
192 | case PPTP_ECHO_REQUEST: | ||
193 | case PPTP_ECHO_REPLY: | ||
194 | /* no need to alter packet */ | ||
195 | return NF_ACCEPT; | ||
196 | } | ||
197 | |||
198 | /* only OUT_CALL_REQUEST, IN_CALL_REPLY, CALL_CLEAR_REQUEST pass | ||
199 | * down to here */ | ||
200 | DEBUGP("altering call id from 0x%04x to 0x%04x\n", | ||
201 | ntohs(REQ_CID(pptpReq, cid_off)), ntohs(new_callid)); | ||
202 | |||
203 | /* mangle packet */ | ||
204 | if (ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, | ||
205 | cid_off + sizeof(struct pptp_pkt_hdr) + | ||
206 | sizeof(struct PptpControlHeader), | ||
207 | sizeof(new_callid), (char *)&new_callid, | ||
208 | sizeof(new_callid)) == 0) | ||
209 | return NF_DROP; | ||
210 | |||
211 | return NF_ACCEPT; | ||
212 | } | ||
213 | |||
214 | static void | ||
215 | pptp_exp_gre(struct ip_conntrack_expect *expect_orig, | ||
216 | struct ip_conntrack_expect *expect_reply) | ||
217 | { | ||
218 | struct ip_conntrack *ct = expect_orig->master; | ||
219 | struct ip_ct_pptp_master *ct_pptp_info = &ct->help.ct_pptp_info; | ||
220 | struct ip_nat_pptp *nat_pptp_info = &ct->nat.help.nat_pptp_info; | ||
221 | |||
222 | /* save original PAC call ID in nat_info */ | ||
223 | nat_pptp_info->pac_call_id = ct_pptp_info->pac_call_id; | ||
224 | |||
225 | /* alter expectation for PNS->PAC direction */ | ||
226 | expect_orig->saved_proto.gre.key = ct_pptp_info->pns_call_id; | ||
227 | expect_orig->tuple.src.u.gre.key = nat_pptp_info->pns_call_id; | ||
228 | expect_orig->tuple.dst.u.gre.key = ct_pptp_info->pac_call_id; | ||
229 | expect_orig->dir = IP_CT_DIR_ORIGINAL; | ||
230 | |||
231 | /* alter expectation for PAC->PNS direction */ | ||
232 | expect_reply->saved_proto.gre.key = nat_pptp_info->pns_call_id; | ||
233 | expect_reply->tuple.src.u.gre.key = nat_pptp_info->pac_call_id; | ||
234 | expect_reply->tuple.dst.u.gre.key = ct_pptp_info->pns_call_id; | ||
235 | expect_reply->dir = IP_CT_DIR_REPLY; | ||
236 | } | ||
237 | |||
238 | /* inbound packets == from PAC to PNS */ | ||
239 | static int | ||
240 | pptp_inbound_pkt(struct sk_buff **pskb, | ||
241 | struct ip_conntrack *ct, | ||
242 | enum ip_conntrack_info ctinfo, | ||
243 | struct PptpControlHeader *ctlh, | ||
244 | union pptp_ctrl_union *pptpReq) | ||
245 | { | ||
246 | struct ip_nat_pptp *nat_pptp_info = &ct->nat.help.nat_pptp_info; | ||
247 | u_int16_t msg; | ||
248 | __be16 new_pcid; | ||
249 | unsigned int pcid_off; | ||
250 | |||
251 | new_pcid = nat_pptp_info->pns_call_id; | ||
252 | |||
253 | switch (msg = ntohs(ctlh->messageType)) { | ||
254 | case PPTP_OUT_CALL_REPLY: | ||
255 | pcid_off = offsetof(union pptp_ctrl_union, ocack.peersCallID); | ||
256 | break; | ||
257 | case PPTP_IN_CALL_CONNECT: | ||
258 | pcid_off = offsetof(union pptp_ctrl_union, iccon.peersCallID); | ||
259 | break; | ||
260 | case PPTP_IN_CALL_REQUEST: | ||
261 | /* only need to nat in case PAC is behind NAT box */ | ||
262 | return NF_ACCEPT; | ||
263 | case PPTP_WAN_ERROR_NOTIFY: | ||
264 | pcid_off = offsetof(union pptp_ctrl_union, wanerr.peersCallID); | ||
265 | break; | ||
266 | case PPTP_CALL_DISCONNECT_NOTIFY: | ||
267 | pcid_off = offsetof(union pptp_ctrl_union, disc.callID); | ||
268 | break; | ||
269 | case PPTP_SET_LINK_INFO: | ||
270 | pcid_off = offsetof(union pptp_ctrl_union, setlink.peersCallID); | ||
271 | break; | ||
272 | |||
273 | default: | ||
274 | DEBUGP("unknown inbound packet %s\n", (msg <= PPTP_MSG_MAX)? | ||
275 | pptp_msg_name[msg]:pptp_msg_name[0]); | ||
276 | /* fall through */ | ||
277 | |||
278 | case PPTP_START_SESSION_REQUEST: | ||
279 | case PPTP_START_SESSION_REPLY: | ||
280 | case PPTP_STOP_SESSION_REQUEST: | ||
281 | case PPTP_STOP_SESSION_REPLY: | ||
282 | case PPTP_ECHO_REQUEST: | ||
283 | case PPTP_ECHO_REPLY: | ||
284 | /* no need to alter packet */ | ||
285 | return NF_ACCEPT; | ||
286 | } | ||
287 | |||
288 | /* only OUT_CALL_REPLY, IN_CALL_CONNECT, IN_CALL_REQUEST, | ||
289 | * WAN_ERROR_NOTIFY, CALL_DISCONNECT_NOTIFY pass down here */ | ||
290 | |||
291 | /* mangle packet */ | ||
292 | DEBUGP("altering peer call id from 0x%04x to 0x%04x\n", | ||
293 | ntohs(REQ_CID(pptpReq, pcid_off)), ntohs(new_pcid)); | ||
294 | |||
295 | if (ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, | ||
296 | pcid_off + sizeof(struct pptp_pkt_hdr) + | ||
297 | sizeof(struct PptpControlHeader), | ||
298 | sizeof(new_pcid), (char *)&new_pcid, | ||
299 | sizeof(new_pcid)) == 0) | ||
300 | return NF_DROP; | ||
301 | return NF_ACCEPT; | ||
302 | } | ||
303 | |||
304 | |||
305 | extern int __init ip_nat_proto_gre_init(void); | ||
306 | extern void __exit ip_nat_proto_gre_fini(void); | ||
307 | |||
308 | static int __init ip_nat_helper_pptp_init(void) | ||
309 | { | ||
310 | int ret; | ||
311 | |||
312 | DEBUGP("%s: registering NAT helper\n", __FILE__); | ||
313 | |||
314 | ret = ip_nat_proto_gre_init(); | ||
315 | if (ret < 0) | ||
316 | return ret; | ||
317 | |||
318 | BUG_ON(rcu_dereference(ip_nat_pptp_hook_outbound)); | ||
319 | rcu_assign_pointer(ip_nat_pptp_hook_outbound, pptp_outbound_pkt); | ||
320 | |||
321 | BUG_ON(rcu_dereference(ip_nat_pptp_hook_inbound)); | ||
322 | rcu_assign_pointer(ip_nat_pptp_hook_inbound, pptp_inbound_pkt); | ||
323 | |||
324 | BUG_ON(rcu_dereference(ip_nat_pptp_hook_exp_gre)); | ||
325 | rcu_assign_pointer(ip_nat_pptp_hook_exp_gre, pptp_exp_gre); | ||
326 | |||
327 | BUG_ON(rcu_dereference(ip_nat_pptp_hook_expectfn)); | ||
328 | rcu_assign_pointer(ip_nat_pptp_hook_expectfn, pptp_nat_expected); | ||
329 | |||
330 | printk("ip_nat_pptp version %s loaded\n", IP_NAT_PPTP_VERSION); | ||
331 | return 0; | ||
332 | } | ||
333 | |||
334 | static void __exit ip_nat_helper_pptp_fini(void) | ||
335 | { | ||
336 | DEBUGP("cleanup_module\n" ); | ||
337 | |||
338 | rcu_assign_pointer(ip_nat_pptp_hook_expectfn, NULL); | ||
339 | rcu_assign_pointer(ip_nat_pptp_hook_exp_gre, NULL); | ||
340 | rcu_assign_pointer(ip_nat_pptp_hook_inbound, NULL); | ||
341 | rcu_assign_pointer(ip_nat_pptp_hook_outbound, NULL); | ||
342 | synchronize_rcu(); | ||
343 | |||
344 | ip_nat_proto_gre_fini(); | ||
345 | |||
346 | printk("ip_nat_pptp version %s unloaded\n", IP_NAT_PPTP_VERSION); | ||
347 | } | ||
348 | |||
349 | module_init(ip_nat_helper_pptp_init); | ||
350 | module_exit(ip_nat_helper_pptp_fini); | ||
diff --git a/net/ipv4/netfilter/ip_nat_irc.c b/net/ipv4/netfilter/ip_nat_irc.c deleted file mode 100644 index cfaeea38314f..000000000000 --- a/net/ipv4/netfilter/ip_nat_irc.c +++ /dev/null | |||
@@ -1,122 +0,0 @@ | |||
1 | /* IRC extension for TCP NAT alteration. | ||
2 | * (C) 2000-2001 by Harald Welte <laforge@gnumonks.org> | ||
3 | * (C) 2004 Rusty Russell <rusty@rustcorp.com.au> IBM Corporation | ||
4 | * based on a copy of RR's ip_nat_ftp.c | ||
5 | * | ||
6 | * ip_nat_irc.c,v 1.16 2001/12/06 07:42:10 laforge Exp | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License | ||
10 | * as published by the Free Software Foundation; either version | ||
11 | * 2 of the License, or (at your option) any later version. | ||
12 | */ | ||
13 | |||
14 | #include <linux/module.h> | ||
15 | #include <linux/netfilter_ipv4.h> | ||
16 | #include <linux/ip.h> | ||
17 | #include <linux/tcp.h> | ||
18 | #include <linux/kernel.h> | ||
19 | #include <net/tcp.h> | ||
20 | #include <linux/netfilter_ipv4/ip_nat.h> | ||
21 | #include <linux/netfilter_ipv4/ip_nat_helper.h> | ||
22 | #include <linux/netfilter_ipv4/ip_nat_rule.h> | ||
23 | #include <linux/netfilter_ipv4/ip_conntrack_irc.h> | ||
24 | #include <linux/netfilter_ipv4/ip_conntrack_helper.h> | ||
25 | #include <linux/moduleparam.h> | ||
26 | |||
27 | #if 0 | ||
28 | #define DEBUGP printk | ||
29 | #else | ||
30 | #define DEBUGP(format, args...) | ||
31 | #endif | ||
32 | |||
33 | MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>"); | ||
34 | MODULE_DESCRIPTION("IRC (DCC) NAT helper"); | ||
35 | MODULE_LICENSE("GPL"); | ||
36 | |||
37 | static unsigned int help(struct sk_buff **pskb, | ||
38 | enum ip_conntrack_info ctinfo, | ||
39 | unsigned int matchoff, | ||
40 | unsigned int matchlen, | ||
41 | struct ip_conntrack_expect *exp) | ||
42 | { | ||
43 | u_int16_t port; | ||
44 | unsigned int ret; | ||
45 | |||
46 | /* "4294967296 65635 " */ | ||
47 | char buffer[18]; | ||
48 | |||
49 | DEBUGP("IRC_NAT: info (seq %u + %u) in %u\n", | ||
50 | expect->seq, exp_irc_info->len, | ||
51 | ntohl(tcph->seq)); | ||
52 | |||
53 | /* Reply comes from server. */ | ||
54 | exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port; | ||
55 | exp->dir = IP_CT_DIR_REPLY; | ||
56 | |||
57 | /* When you see the packet, we need to NAT it the same as the | ||
58 | * this one. */ | ||
59 | exp->expectfn = ip_nat_follow_master; | ||
60 | |||
61 | /* Try to get same port: if not, try to change it. */ | ||
62 | for (port = ntohs(exp->saved_proto.tcp.port); port != 0; port++) { | ||
63 | exp->tuple.dst.u.tcp.port = htons(port); | ||
64 | if (ip_conntrack_expect_related(exp) == 0) | ||
65 | break; | ||
66 | } | ||
67 | |||
68 | if (port == 0) | ||
69 | return NF_DROP; | ||
70 | |||
71 | /* strlen("\1DCC CHAT chat AAAAAAAA P\1\n")=27 | ||
72 | * strlen("\1DCC SCHAT chat AAAAAAAA P\1\n")=28 | ||
73 | * strlen("\1DCC SEND F AAAAAAAA P S\1\n")=26 | ||
74 | * strlen("\1DCC MOVE F AAAAAAAA P S\1\n")=26 | ||
75 | * strlen("\1DCC TSEND F AAAAAAAA P S\1\n")=27 | ||
76 | * AAAAAAAAA: bound addr (1.0.0.0==16777216, min 8 digits, | ||
77 | * 255.255.255.255==4294967296, 10 digits) | ||
78 | * P: bound port (min 1 d, max 5d (65635)) | ||
79 | * F: filename (min 1 d ) | ||
80 | * S: size (min 1 d ) | ||
81 | * 0x01, \n: terminators | ||
82 | */ | ||
83 | |||
84 | /* AAA = "us", ie. where server normally talks to. */ | ||
85 | sprintf(buffer, "%u %u", | ||
86 | ntohl(exp->master->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip), | ||
87 | port); | ||
88 | DEBUGP("ip_nat_irc: Inserting '%s' == %u.%u.%u.%u, port %u\n", | ||
89 | buffer, NIPQUAD(exp->tuple.src.ip), port); | ||
90 | |||
91 | ret = ip_nat_mangle_tcp_packet(pskb, exp->master, ctinfo, | ||
92 | matchoff, matchlen, buffer, | ||
93 | strlen(buffer)); | ||
94 | if (ret != NF_ACCEPT) | ||
95 | ip_conntrack_unexpect_related(exp); | ||
96 | return ret; | ||
97 | } | ||
98 | |||
99 | static void __exit ip_nat_irc_fini(void) | ||
100 | { | ||
101 | rcu_assign_pointer(ip_nat_irc_hook, NULL); | ||
102 | synchronize_rcu(); | ||
103 | } | ||
104 | |||
105 | static int __init ip_nat_irc_init(void) | ||
106 | { | ||
107 | BUG_ON(rcu_dereference(ip_nat_irc_hook)); | ||
108 | rcu_assign_pointer(ip_nat_irc_hook, help); | ||
109 | return 0; | ||
110 | } | ||
111 | |||
112 | /* Prior to 2.6.11, we had a ports param. No longer, but don't break users. */ | ||
113 | static int warn_set(const char *val, struct kernel_param *kp) | ||
114 | { | ||
115 | printk(KERN_INFO KBUILD_MODNAME | ||
116 | ": kernel >= 2.6.10 only uses 'ports' for conntrack modules\n"); | ||
117 | return 0; | ||
118 | } | ||
119 | module_param_call(ports, warn_set, NULL, NULL, 0); | ||
120 | |||
121 | module_init(ip_nat_irc_init); | ||
122 | module_exit(ip_nat_irc_fini); | ||
diff --git a/net/ipv4/netfilter/ip_nat_proto_gre.c b/net/ipv4/netfilter/ip_nat_proto_gre.c deleted file mode 100644 index 95810202d849..000000000000 --- a/net/ipv4/netfilter/ip_nat_proto_gre.c +++ /dev/null | |||
@@ -1,174 +0,0 @@ | |||
1 | /* | ||
2 | * ip_nat_proto_gre.c - Version 2.0 | ||
3 | * | ||
4 | * NAT protocol helper module for GRE. | ||
5 | * | ||
6 | * GRE is a generic encapsulation protocol, which is generally not very | ||
7 | * suited for NAT, as it has no protocol-specific part as port numbers. | ||
8 | * | ||
9 | * It has an optional key field, which may help us distinguishing two | ||
10 | * connections between the same two hosts. | ||
11 | * | ||
12 | * GRE is defined in RFC 1701 and RFC 1702, as well as RFC 2784 | ||
13 | * | ||
14 | * PPTP is built on top of a modified version of GRE, and has a mandatory | ||
15 | * field called "CallID", which serves us for the same purpose as the key | ||
16 | * field in plain GRE. | ||
17 | * | ||
18 | * Documentation about PPTP can be found in RFC 2637 | ||
19 | * | ||
20 | * (C) 2000-2005 by Harald Welte <laforge@gnumonks.org> | ||
21 | * | ||
22 | * Development of this code funded by Astaro AG (http://www.astaro.com/) | ||
23 | * | ||
24 | */ | ||
25 | |||
26 | #include <linux/module.h> | ||
27 | #include <linux/ip.h> | ||
28 | #include <linux/netfilter_ipv4/ip_nat.h> | ||
29 | #include <linux/netfilter_ipv4/ip_nat_rule.h> | ||
30 | #include <linux/netfilter_ipv4/ip_nat_protocol.h> | ||
31 | #include <linux/netfilter_ipv4/ip_conntrack_proto_gre.h> | ||
32 | |||
33 | MODULE_LICENSE("GPL"); | ||
34 | MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>"); | ||
35 | MODULE_DESCRIPTION("Netfilter NAT protocol helper module for GRE"); | ||
36 | |||
37 | #if 0 | ||
38 | #define DEBUGP(format, args...) printk(KERN_DEBUG "%s:%s: " format, __FILE__, \ | ||
39 | __FUNCTION__, ## args) | ||
40 | #else | ||
41 | #define DEBUGP(x, args...) | ||
42 | #endif | ||
43 | |||
44 | /* is key in given range between min and max */ | ||
45 | static int | ||
46 | gre_in_range(const struct ip_conntrack_tuple *tuple, | ||
47 | enum ip_nat_manip_type maniptype, | ||
48 | const union ip_conntrack_manip_proto *min, | ||
49 | const union ip_conntrack_manip_proto *max) | ||
50 | { | ||
51 | __be16 key; | ||
52 | |||
53 | if (maniptype == IP_NAT_MANIP_SRC) | ||
54 | key = tuple->src.u.gre.key; | ||
55 | else | ||
56 | key = tuple->dst.u.gre.key; | ||
57 | |||
58 | return ntohs(key) >= ntohs(min->gre.key) | ||
59 | && ntohs(key) <= ntohs(max->gre.key); | ||
60 | } | ||
61 | |||
62 | /* generate unique tuple ... */ | ||
63 | static int | ||
64 | gre_unique_tuple(struct ip_conntrack_tuple *tuple, | ||
65 | const struct ip_nat_range *range, | ||
66 | enum ip_nat_manip_type maniptype, | ||
67 | const struct ip_conntrack *conntrack) | ||
68 | { | ||
69 | static u_int16_t key; | ||
70 | __be16 *keyptr; | ||
71 | unsigned int min, i, range_size; | ||
72 | |||
73 | if (maniptype == IP_NAT_MANIP_SRC) | ||
74 | keyptr = &tuple->src.u.gre.key; | ||
75 | else | ||
76 | keyptr = &tuple->dst.u.gre.key; | ||
77 | |||
78 | if (!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED)) { | ||
79 | DEBUGP("%p: NATing GRE PPTP\n", conntrack); | ||
80 | min = 1; | ||
81 | range_size = 0xffff; | ||
82 | } else { | ||
83 | min = ntohs(range->min.gre.key); | ||
84 | range_size = ntohs(range->max.gre.key) - min + 1; | ||
85 | } | ||
86 | |||
87 | DEBUGP("min = %u, range_size = %u\n", min, range_size); | ||
88 | |||
89 | for (i = 0; i < range_size; i++, key++) { | ||
90 | *keyptr = htons(min + key % range_size); | ||
91 | if (!ip_nat_used_tuple(tuple, conntrack)) | ||
92 | return 1; | ||
93 | } | ||
94 | |||
95 | DEBUGP("%p: no NAT mapping\n", conntrack); | ||
96 | |||
97 | return 0; | ||
98 | } | ||
99 | |||
100 | /* manipulate a GRE packet according to maniptype */ | ||
101 | static int | ||
102 | gre_manip_pkt(struct sk_buff **pskb, | ||
103 | unsigned int iphdroff, | ||
104 | const struct ip_conntrack_tuple *tuple, | ||
105 | enum ip_nat_manip_type maniptype) | ||
106 | { | ||
107 | struct gre_hdr *greh; | ||
108 | struct gre_hdr_pptp *pgreh; | ||
109 | struct iphdr *iph = (struct iphdr *)((*pskb)->data + iphdroff); | ||
110 | unsigned int hdroff = iphdroff + iph->ihl*4; | ||
111 | |||
112 | /* pgreh includes two optional 32bit fields which are not required | ||
113 | * to be there. That's where the magic '8' comes from */ | ||
114 | if (!skb_make_writable(pskb, hdroff + sizeof(*pgreh)-8)) | ||
115 | return 0; | ||
116 | |||
117 | greh = (void *)(*pskb)->data + hdroff; | ||
118 | pgreh = (struct gre_hdr_pptp *) greh; | ||
119 | |||
120 | /* we only have destination manip of a packet, since 'source key' | ||
121 | * is not present in the packet itself */ | ||
122 | if (maniptype == IP_NAT_MANIP_DST) { | ||
123 | /* key manipulation is always dest */ | ||
124 | switch (greh->version) { | ||
125 | case 0: | ||
126 | if (!greh->key) { | ||
127 | DEBUGP("can't nat GRE w/o key\n"); | ||
128 | break; | ||
129 | } | ||
130 | if (greh->csum) { | ||
131 | /* FIXME: Never tested this code... */ | ||
132 | nf_proto_csum_replace4(gre_csum(greh), *pskb, | ||
133 | *(gre_key(greh)), | ||
134 | tuple->dst.u.gre.key, 0); | ||
135 | } | ||
136 | *(gre_key(greh)) = tuple->dst.u.gre.key; | ||
137 | break; | ||
138 | case GRE_VERSION_PPTP: | ||
139 | DEBUGP("call_id -> 0x%04x\n", | ||
140 | ntohs(tuple->dst.u.gre.key)); | ||
141 | pgreh->call_id = tuple->dst.u.gre.key; | ||
142 | break; | ||
143 | default: | ||
144 | DEBUGP("can't nat unknown GRE version\n"); | ||
145 | return 0; | ||
146 | break; | ||
147 | } | ||
148 | } | ||
149 | return 1; | ||
150 | } | ||
151 | |||
152 | /* nat helper struct */ | ||
153 | static struct ip_nat_protocol gre = { | ||
154 | .name = "GRE", | ||
155 | .protonum = IPPROTO_GRE, | ||
156 | .manip_pkt = gre_manip_pkt, | ||
157 | .in_range = gre_in_range, | ||
158 | .unique_tuple = gre_unique_tuple, | ||
159 | #if defined(CONFIG_IP_NF_CONNTRACK_NETLINK) || \ | ||
160 | defined(CONFIG_IP_NF_CONNTRACK_NETLINK_MODULE) | ||
161 | .range_to_nfattr = ip_nat_port_range_to_nfattr, | ||
162 | .nfattr_to_range = ip_nat_port_nfattr_to_range, | ||
163 | #endif | ||
164 | }; | ||
165 | |||
166 | int __init ip_nat_proto_gre_init(void) | ||
167 | { | ||
168 | return ip_nat_protocol_register(&gre); | ||
169 | } | ||
170 | |||
171 | void __exit ip_nat_proto_gre_fini(void) | ||
172 | { | ||
173 | ip_nat_protocol_unregister(&gre); | ||
174 | } | ||
diff --git a/net/ipv4/netfilter/ip_nat_proto_icmp.c b/net/ipv4/netfilter/ip_nat_proto_icmp.c deleted file mode 100644 index 22a528ae0380..000000000000 --- a/net/ipv4/netfilter/ip_nat_proto_icmp.c +++ /dev/null | |||
@@ -1,87 +0,0 @@ | |||
1 | /* (C) 1999-2001 Paul `Rusty' Russell | ||
2 | * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | */ | ||
8 | |||
9 | #include <linux/types.h> | ||
10 | #include <linux/init.h> | ||
11 | #include <linux/netfilter.h> | ||
12 | #include <linux/ip.h> | ||
13 | #include <linux/icmp.h> | ||
14 | #include <linux/if.h> | ||
15 | |||
16 | #include <linux/netfilter_ipv4/ip_nat.h> | ||
17 | #include <linux/netfilter_ipv4/ip_nat_core.h> | ||
18 | #include <linux/netfilter_ipv4/ip_nat_rule.h> | ||
19 | #include <linux/netfilter_ipv4/ip_nat_protocol.h> | ||
20 | |||
21 | static int | ||
22 | icmp_in_range(const struct ip_conntrack_tuple *tuple, | ||
23 | enum ip_nat_manip_type maniptype, | ||
24 | const union ip_conntrack_manip_proto *min, | ||
25 | const union ip_conntrack_manip_proto *max) | ||
26 | { | ||
27 | return ntohs(tuple->src.u.icmp.id) >= ntohs(min->icmp.id) && | ||
28 | ntohs(tuple->src.u.icmp.id) <= ntohs(max->icmp.id); | ||
29 | } | ||
30 | |||
31 | static int | ||
32 | icmp_unique_tuple(struct ip_conntrack_tuple *tuple, | ||
33 | const struct ip_nat_range *range, | ||
34 | enum ip_nat_manip_type maniptype, | ||
35 | const struct ip_conntrack *conntrack) | ||
36 | { | ||
37 | static u_int16_t id; | ||
38 | unsigned int range_size; | ||
39 | unsigned int i; | ||
40 | |||
41 | range_size = ntohs(range->max.icmp.id) - ntohs(range->min.icmp.id) + 1; | ||
42 | /* If no range specified... */ | ||
43 | if (!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED)) | ||
44 | range_size = 0xFFFF; | ||
45 | |||
46 | for (i = 0; i < range_size; i++, id++) { | ||
47 | tuple->src.u.icmp.id = htons(ntohs(range->min.icmp.id) + | ||
48 | (id % range_size)); | ||
49 | if (!ip_nat_used_tuple(tuple, conntrack)) | ||
50 | return 1; | ||
51 | } | ||
52 | return 0; | ||
53 | } | ||
54 | |||
55 | static int | ||
56 | icmp_manip_pkt(struct sk_buff **pskb, | ||
57 | unsigned int iphdroff, | ||
58 | const struct ip_conntrack_tuple *tuple, | ||
59 | enum ip_nat_manip_type maniptype) | ||
60 | { | ||
61 | struct iphdr *iph = (struct iphdr *)((*pskb)->data + iphdroff); | ||
62 | struct icmphdr *hdr; | ||
63 | unsigned int hdroff = iphdroff + iph->ihl*4; | ||
64 | |||
65 | if (!skb_make_writable(pskb, hdroff + sizeof(*hdr))) | ||
66 | return 0; | ||
67 | |||
68 | hdr = (struct icmphdr *)((*pskb)->data + hdroff); | ||
69 | nf_proto_csum_replace2(&hdr->checksum, *pskb, | ||
70 | hdr->un.echo.id, tuple->src.u.icmp.id, 0); | ||
71 | hdr->un.echo.id = tuple->src.u.icmp.id; | ||
72 | return 1; | ||
73 | } | ||
74 | |||
75 | struct ip_nat_protocol ip_nat_protocol_icmp = { | ||
76 | .name = "ICMP", | ||
77 | .protonum = IPPROTO_ICMP, | ||
78 | .me = THIS_MODULE, | ||
79 | .manip_pkt = icmp_manip_pkt, | ||
80 | .in_range = icmp_in_range, | ||
81 | .unique_tuple = icmp_unique_tuple, | ||
82 | #if defined(CONFIG_IP_NF_CONNTRACK_NETLINK) || \ | ||
83 | defined(CONFIG_IP_NF_CONNTRACK_NETLINK_MODULE) | ||
84 | .range_to_nfattr = ip_nat_port_range_to_nfattr, | ||
85 | .nfattr_to_range = ip_nat_port_nfattr_to_range, | ||
86 | #endif | ||
87 | }; | ||
diff --git a/net/ipv4/netfilter/ip_nat_proto_tcp.c b/net/ipv4/netfilter/ip_nat_proto_tcp.c deleted file mode 100644 index 14ff24f53a7a..000000000000 --- a/net/ipv4/netfilter/ip_nat_proto_tcp.c +++ /dev/null | |||
@@ -1,154 +0,0 @@ | |||
1 | /* (C) 1999-2001 Paul `Rusty' Russell | ||
2 | * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | */ | ||
8 | |||
9 | #include <linux/types.h> | ||
10 | #include <linux/init.h> | ||
11 | #include <linux/random.h> | ||
12 | #include <linux/netfilter.h> | ||
13 | #include <linux/ip.h> | ||
14 | #include <linux/tcp.h> | ||
15 | #include <linux/if.h> | ||
16 | #include <linux/netfilter/nfnetlink_conntrack.h> | ||
17 | #include <linux/netfilter_ipv4/ip_nat.h> | ||
18 | #include <linux/netfilter_ipv4/ip_nat_rule.h> | ||
19 | #include <linux/netfilter_ipv4/ip_nat_protocol.h> | ||
20 | #include <linux/netfilter_ipv4/ip_nat_core.h> | ||
21 | |||
22 | static int | ||
23 | tcp_in_range(const struct ip_conntrack_tuple *tuple, | ||
24 | enum ip_nat_manip_type maniptype, | ||
25 | const union ip_conntrack_manip_proto *min, | ||
26 | const union ip_conntrack_manip_proto *max) | ||
27 | { | ||
28 | __be16 port; | ||
29 | |||
30 | if (maniptype == IP_NAT_MANIP_SRC) | ||
31 | port = tuple->src.u.tcp.port; | ||
32 | else | ||
33 | port = tuple->dst.u.tcp.port; | ||
34 | |||
35 | return ntohs(port) >= ntohs(min->tcp.port) | ||
36 | && ntohs(port) <= ntohs(max->tcp.port); | ||
37 | } | ||
38 | |||
39 | static int | ||
40 | tcp_unique_tuple(struct ip_conntrack_tuple *tuple, | ||
41 | const struct ip_nat_range *range, | ||
42 | enum ip_nat_manip_type maniptype, | ||
43 | const struct ip_conntrack *conntrack) | ||
44 | { | ||
45 | static u_int16_t port; | ||
46 | __be16 *portptr; | ||
47 | unsigned int range_size, min, i; | ||
48 | |||
49 | if (maniptype == IP_NAT_MANIP_SRC) | ||
50 | portptr = &tuple->src.u.tcp.port; | ||
51 | else | ||
52 | portptr = &tuple->dst.u.tcp.port; | ||
53 | |||
54 | /* If no range specified... */ | ||
55 | if (!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED)) { | ||
56 | /* If it's dst rewrite, can't change port */ | ||
57 | if (maniptype == IP_NAT_MANIP_DST) | ||
58 | return 0; | ||
59 | |||
60 | /* Map privileged onto privileged. */ | ||
61 | if (ntohs(*portptr) < 1024) { | ||
62 | /* Loose convention: >> 512 is credential passing */ | ||
63 | if (ntohs(*portptr)<512) { | ||
64 | min = 1; | ||
65 | range_size = 511 - min + 1; | ||
66 | } else { | ||
67 | min = 600; | ||
68 | range_size = 1023 - min + 1; | ||
69 | } | ||
70 | } else { | ||
71 | min = 1024; | ||
72 | range_size = 65535 - 1024 + 1; | ||
73 | } | ||
74 | } else { | ||
75 | min = ntohs(range->min.tcp.port); | ||
76 | range_size = ntohs(range->max.tcp.port) - min + 1; | ||
77 | } | ||
78 | |||
79 | /* Start from random port to avoid prediction */ | ||
80 | if (range->flags & IP_NAT_RANGE_PROTO_RANDOM) | ||
81 | port = net_random(); | ||
82 | |||
83 | for (i = 0; i < range_size; i++, port++) { | ||
84 | *portptr = htons(min + port % range_size); | ||
85 | if (!ip_nat_used_tuple(tuple, conntrack)) { | ||
86 | return 1; | ||
87 | } | ||
88 | } | ||
89 | return 0; | ||
90 | } | ||
91 | |||
92 | static int | ||
93 | tcp_manip_pkt(struct sk_buff **pskb, | ||
94 | unsigned int iphdroff, | ||
95 | const struct ip_conntrack_tuple *tuple, | ||
96 | enum ip_nat_manip_type maniptype) | ||
97 | { | ||
98 | struct iphdr *iph = (struct iphdr *)((*pskb)->data + iphdroff); | ||
99 | struct tcphdr *hdr; | ||
100 | unsigned int hdroff = iphdroff + iph->ihl*4; | ||
101 | __be32 oldip, newip; | ||
102 | __be16 *portptr, newport, oldport; | ||
103 | int hdrsize = 8; /* TCP connection tracking guarantees this much */ | ||
104 | |||
105 | /* this could be a inner header returned in icmp packet; in such | ||
106 | cases we cannot update the checksum field since it is outside of | ||
107 | the 8 bytes of transport layer headers we are guaranteed */ | ||
108 | if ((*pskb)->len >= hdroff + sizeof(struct tcphdr)) | ||
109 | hdrsize = sizeof(struct tcphdr); | ||
110 | |||
111 | if (!skb_make_writable(pskb, hdroff + hdrsize)) | ||
112 | return 0; | ||
113 | |||
114 | iph = (struct iphdr *)((*pskb)->data + iphdroff); | ||
115 | hdr = (struct tcphdr *)((*pskb)->data + hdroff); | ||
116 | |||
117 | if (maniptype == IP_NAT_MANIP_SRC) { | ||
118 | /* Get rid of src ip and src pt */ | ||
119 | oldip = iph->saddr; | ||
120 | newip = tuple->src.ip; | ||
121 | newport = tuple->src.u.tcp.port; | ||
122 | portptr = &hdr->source; | ||
123 | } else { | ||
124 | /* Get rid of dst ip and dst pt */ | ||
125 | oldip = iph->daddr; | ||
126 | newip = tuple->dst.ip; | ||
127 | newport = tuple->dst.u.tcp.port; | ||
128 | portptr = &hdr->dest; | ||
129 | } | ||
130 | |||
131 | oldport = *portptr; | ||
132 | *portptr = newport; | ||
133 | |||
134 | if (hdrsize < sizeof(*hdr)) | ||
135 | return 1; | ||
136 | |||
137 | nf_proto_csum_replace4(&hdr->check, *pskb, oldip, newip, 1); | ||
138 | nf_proto_csum_replace2(&hdr->check, *pskb, oldport, newport, 0); | ||
139 | return 1; | ||
140 | } | ||
141 | |||
142 | struct ip_nat_protocol ip_nat_protocol_tcp = { | ||
143 | .name = "TCP", | ||
144 | .protonum = IPPROTO_TCP, | ||
145 | .me = THIS_MODULE, | ||
146 | .manip_pkt = tcp_manip_pkt, | ||
147 | .in_range = tcp_in_range, | ||
148 | .unique_tuple = tcp_unique_tuple, | ||
149 | #if defined(CONFIG_IP_NF_CONNTRACK_NETLINK) || \ | ||
150 | defined(CONFIG_IP_NF_CONNTRACK_NETLINK_MODULE) | ||
151 | .range_to_nfattr = ip_nat_port_range_to_nfattr, | ||
152 | .nfattr_to_range = ip_nat_port_nfattr_to_range, | ||
153 | #endif | ||
154 | }; | ||
diff --git a/net/ipv4/netfilter/ip_nat_proto_udp.c b/net/ipv4/netfilter/ip_nat_proto_udp.c deleted file mode 100644 index dfd521672891..000000000000 --- a/net/ipv4/netfilter/ip_nat_proto_udp.c +++ /dev/null | |||
@@ -1,144 +0,0 @@ | |||
1 | /* (C) 1999-2001 Paul `Rusty' Russell | ||
2 | * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | */ | ||
8 | |||
9 | #include <linux/types.h> | ||
10 | #include <linux/init.h> | ||
11 | #include <linux/random.h> | ||
12 | #include <linux/netfilter.h> | ||
13 | #include <linux/ip.h> | ||
14 | #include <linux/udp.h> | ||
15 | #include <linux/if.h> | ||
16 | |||
17 | #include <linux/netfilter_ipv4/ip_nat.h> | ||
18 | #include <linux/netfilter_ipv4/ip_nat_core.h> | ||
19 | #include <linux/netfilter_ipv4/ip_nat_rule.h> | ||
20 | #include <linux/netfilter_ipv4/ip_nat_protocol.h> | ||
21 | |||
22 | static int | ||
23 | udp_in_range(const struct ip_conntrack_tuple *tuple, | ||
24 | enum ip_nat_manip_type maniptype, | ||
25 | const union ip_conntrack_manip_proto *min, | ||
26 | const union ip_conntrack_manip_proto *max) | ||
27 | { | ||
28 | __be16 port; | ||
29 | |||
30 | if (maniptype == IP_NAT_MANIP_SRC) | ||
31 | port = tuple->src.u.udp.port; | ||
32 | else | ||
33 | port = tuple->dst.u.udp.port; | ||
34 | |||
35 | return ntohs(port) >= ntohs(min->udp.port) | ||
36 | && ntohs(port) <= ntohs(max->udp.port); | ||
37 | } | ||
38 | |||
39 | static int | ||
40 | udp_unique_tuple(struct ip_conntrack_tuple *tuple, | ||
41 | const struct ip_nat_range *range, | ||
42 | enum ip_nat_manip_type maniptype, | ||
43 | const struct ip_conntrack *conntrack) | ||
44 | { | ||
45 | static u_int16_t port; | ||
46 | __be16 *portptr; | ||
47 | unsigned int range_size, min, i; | ||
48 | |||
49 | if (maniptype == IP_NAT_MANIP_SRC) | ||
50 | portptr = &tuple->src.u.udp.port; | ||
51 | else | ||
52 | portptr = &tuple->dst.u.udp.port; | ||
53 | |||
54 | /* If no range specified... */ | ||
55 | if (!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED)) { | ||
56 | /* If it's dst rewrite, can't change port */ | ||
57 | if (maniptype == IP_NAT_MANIP_DST) | ||
58 | return 0; | ||
59 | |||
60 | if (ntohs(*portptr) < 1024) { | ||
61 | /* Loose convention: >> 512 is credential passing */ | ||
62 | if (ntohs(*portptr)<512) { | ||
63 | min = 1; | ||
64 | range_size = 511 - min + 1; | ||
65 | } else { | ||
66 | min = 600; | ||
67 | range_size = 1023 - min + 1; | ||
68 | } | ||
69 | } else { | ||
70 | min = 1024; | ||
71 | range_size = 65535 - 1024 + 1; | ||
72 | } | ||
73 | } else { | ||
74 | min = ntohs(range->min.udp.port); | ||
75 | range_size = ntohs(range->max.udp.port) - min + 1; | ||
76 | } | ||
77 | |||
78 | /* Start from random port to avoid prediction */ | ||
79 | if (range->flags & IP_NAT_RANGE_PROTO_RANDOM) | ||
80 | port = net_random(); | ||
81 | |||
82 | for (i = 0; i < range_size; i++, port++) { | ||
83 | *portptr = htons(min + port % range_size); | ||
84 | if (!ip_nat_used_tuple(tuple, conntrack)) | ||
85 | return 1; | ||
86 | } | ||
87 | return 0; | ||
88 | } | ||
89 | |||
90 | static int | ||
91 | udp_manip_pkt(struct sk_buff **pskb, | ||
92 | unsigned int iphdroff, | ||
93 | const struct ip_conntrack_tuple *tuple, | ||
94 | enum ip_nat_manip_type maniptype) | ||
95 | { | ||
96 | struct iphdr *iph = (struct iphdr *)((*pskb)->data + iphdroff); | ||
97 | struct udphdr *hdr; | ||
98 | unsigned int hdroff = iphdroff + iph->ihl*4; | ||
99 | __be32 oldip, newip; | ||
100 | __be16 *portptr, newport; | ||
101 | |||
102 | if (!skb_make_writable(pskb, hdroff + sizeof(*hdr))) | ||
103 | return 0; | ||
104 | |||
105 | iph = (struct iphdr *)((*pskb)->data + iphdroff); | ||
106 | hdr = (struct udphdr *)((*pskb)->data + hdroff); | ||
107 | |||
108 | if (maniptype == IP_NAT_MANIP_SRC) { | ||
109 | /* Get rid of src ip and src pt */ | ||
110 | oldip = iph->saddr; | ||
111 | newip = tuple->src.ip; | ||
112 | newport = tuple->src.u.udp.port; | ||
113 | portptr = &hdr->source; | ||
114 | } else { | ||
115 | /* Get rid of dst ip and dst pt */ | ||
116 | oldip = iph->daddr; | ||
117 | newip = tuple->dst.ip; | ||
118 | newport = tuple->dst.u.udp.port; | ||
119 | portptr = &hdr->dest; | ||
120 | } | ||
121 | |||
122 | if (hdr->check || (*pskb)->ip_summed == CHECKSUM_PARTIAL) { | ||
123 | nf_proto_csum_replace4(&hdr->check, *pskb, oldip, newip, 1); | ||
124 | nf_proto_csum_replace2(&hdr->check, *pskb, *portptr, newport, 0); | ||
125 | if (!hdr->check) | ||
126 | hdr->check = CSUM_MANGLED_0; | ||
127 | } | ||
128 | *portptr = newport; | ||
129 | return 1; | ||
130 | } | ||
131 | |||
132 | struct ip_nat_protocol ip_nat_protocol_udp = { | ||
133 | .name = "UDP", | ||
134 | .protonum = IPPROTO_UDP, | ||
135 | .me = THIS_MODULE, | ||
136 | .manip_pkt = udp_manip_pkt, | ||
137 | .in_range = udp_in_range, | ||
138 | .unique_tuple = udp_unique_tuple, | ||
139 | #if defined(CONFIG_IP_NF_CONNTRACK_NETLINK) || \ | ||
140 | defined(CONFIG_IP_NF_CONNTRACK_NETLINK_MODULE) | ||
141 | .range_to_nfattr = ip_nat_port_range_to_nfattr, | ||
142 | .nfattr_to_range = ip_nat_port_nfattr_to_range, | ||
143 | #endif | ||
144 | }; | ||
diff --git a/net/ipv4/netfilter/ip_nat_proto_unknown.c b/net/ipv4/netfilter/ip_nat_proto_unknown.c deleted file mode 100644 index 3bf049517246..000000000000 --- a/net/ipv4/netfilter/ip_nat_proto_unknown.c +++ /dev/null | |||
@@ -1,55 +0,0 @@ | |||
1 | /* The "unknown" protocol. This is what is used for protocols we | ||
2 | * don't understand. It's returned by ip_ct_find_proto(). | ||
3 | */ | ||
4 | |||
5 | /* (C) 1999-2001 Paul `Rusty' Russell | ||
6 | * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | |||
13 | #include <linux/types.h> | ||
14 | #include <linux/init.h> | ||
15 | #include <linux/netfilter.h> | ||
16 | #include <linux/if.h> | ||
17 | |||
18 | #include <linux/netfilter_ipv4/ip_nat.h> | ||
19 | #include <linux/netfilter_ipv4/ip_nat_rule.h> | ||
20 | #include <linux/netfilter_ipv4/ip_nat_protocol.h> | ||
21 | |||
22 | static int unknown_in_range(const struct ip_conntrack_tuple *tuple, | ||
23 | enum ip_nat_manip_type manip_type, | ||
24 | const union ip_conntrack_manip_proto *min, | ||
25 | const union ip_conntrack_manip_proto *max) | ||
26 | { | ||
27 | return 1; | ||
28 | } | ||
29 | |||
30 | static int unknown_unique_tuple(struct ip_conntrack_tuple *tuple, | ||
31 | const struct ip_nat_range *range, | ||
32 | enum ip_nat_manip_type maniptype, | ||
33 | const struct ip_conntrack *conntrack) | ||
34 | { | ||
35 | /* Sorry: we can't help you; if it's not unique, we can't frob | ||
36 | anything. */ | ||
37 | return 0; | ||
38 | } | ||
39 | |||
40 | static int | ||
41 | unknown_manip_pkt(struct sk_buff **pskb, | ||
42 | unsigned int iphdroff, | ||
43 | const struct ip_conntrack_tuple *tuple, | ||
44 | enum ip_nat_manip_type maniptype) | ||
45 | { | ||
46 | return 1; | ||
47 | } | ||
48 | |||
49 | struct ip_nat_protocol ip_nat_unknown_protocol = { | ||
50 | .name = "unknown", | ||
51 | /* .me isn't set: getting a ref to this cannot fail. */ | ||
52 | .manip_pkt = unknown_manip_pkt, | ||
53 | .in_range = unknown_in_range, | ||
54 | .unique_tuple = unknown_unique_tuple, | ||
55 | }; | ||
diff --git a/net/ipv4/netfilter/ip_nat_rule.c b/net/ipv4/netfilter/ip_nat_rule.c deleted file mode 100644 index 25415a91e023..000000000000 --- a/net/ipv4/netfilter/ip_nat_rule.c +++ /dev/null | |||
@@ -1,314 +0,0 @@ | |||
1 | /* (C) 1999-2001 Paul `Rusty' Russell | ||
2 | * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | */ | ||
8 | |||
9 | /* Everything about the rules for NAT. */ | ||
10 | #include <linux/types.h> | ||
11 | #include <linux/ip.h> | ||
12 | #include <linux/netfilter.h> | ||
13 | #include <linux/netfilter_ipv4.h> | ||
14 | #include <linux/module.h> | ||
15 | #include <linux/kmod.h> | ||
16 | #include <linux/skbuff.h> | ||
17 | #include <linux/proc_fs.h> | ||
18 | #include <net/checksum.h> | ||
19 | #include <net/route.h> | ||
20 | #include <linux/bitops.h> | ||
21 | |||
22 | #include <linux/netfilter_ipv4/ip_tables.h> | ||
23 | #include <linux/netfilter_ipv4/ip_nat.h> | ||
24 | #include <linux/netfilter_ipv4/ip_nat_core.h> | ||
25 | #include <linux/netfilter_ipv4/ip_nat_rule.h> | ||
26 | |||
27 | #if 0 | ||
28 | #define DEBUGP printk | ||
29 | #else | ||
30 | #define DEBUGP(format, args...) | ||
31 | #endif | ||
32 | |||
33 | #define NAT_VALID_HOOKS ((1<<NF_IP_PRE_ROUTING) | (1<<NF_IP_POST_ROUTING) | (1<<NF_IP_LOCAL_OUT)) | ||
34 | |||
35 | static struct | ||
36 | { | ||
37 | struct ipt_replace repl; | ||
38 | struct ipt_standard entries[3]; | ||
39 | struct ipt_error term; | ||
40 | } nat_initial_table __initdata | ||
41 | = { { "nat", NAT_VALID_HOOKS, 4, | ||
42 | sizeof(struct ipt_standard) * 3 + sizeof(struct ipt_error), | ||
43 | { [NF_IP_PRE_ROUTING] = 0, | ||
44 | [NF_IP_POST_ROUTING] = sizeof(struct ipt_standard), | ||
45 | [NF_IP_LOCAL_OUT] = sizeof(struct ipt_standard) * 2 }, | ||
46 | { [NF_IP_PRE_ROUTING] = 0, | ||
47 | [NF_IP_POST_ROUTING] = sizeof(struct ipt_standard), | ||
48 | [NF_IP_LOCAL_OUT] = sizeof(struct ipt_standard) * 2 }, | ||
49 | 0, NULL, { } }, | ||
50 | { | ||
51 | /* PRE_ROUTING */ | ||
52 | { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 }, | ||
53 | 0, | ||
54 | sizeof(struct ipt_entry), | ||
55 | sizeof(struct ipt_standard), | ||
56 | 0, { 0, 0 }, { } }, | ||
57 | { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } }, | ||
58 | -NF_ACCEPT - 1 } }, | ||
59 | /* POST_ROUTING */ | ||
60 | { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 }, | ||
61 | 0, | ||
62 | sizeof(struct ipt_entry), | ||
63 | sizeof(struct ipt_standard), | ||
64 | 0, { 0, 0 }, { } }, | ||
65 | { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } }, | ||
66 | -NF_ACCEPT - 1 } }, | ||
67 | /* LOCAL_OUT */ | ||
68 | { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 }, | ||
69 | 0, | ||
70 | sizeof(struct ipt_entry), | ||
71 | sizeof(struct ipt_standard), | ||
72 | 0, { 0, 0 }, { } }, | ||
73 | { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } }, | ||
74 | -NF_ACCEPT - 1 } } | ||
75 | }, | ||
76 | /* ERROR */ | ||
77 | { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 }, | ||
78 | 0, | ||
79 | sizeof(struct ipt_entry), | ||
80 | sizeof(struct ipt_error), | ||
81 | 0, { 0, 0 }, { } }, | ||
82 | { { { { IPT_ALIGN(sizeof(struct ipt_error_target)), IPT_ERROR_TARGET } }, | ||
83 | { } }, | ||
84 | "ERROR" | ||
85 | } | ||
86 | } | ||
87 | }; | ||
88 | |||
89 | static struct xt_table nat_table = { | ||
90 | .name = "nat", | ||
91 | .valid_hooks = NAT_VALID_HOOKS, | ||
92 | .lock = RW_LOCK_UNLOCKED, | ||
93 | .me = THIS_MODULE, | ||
94 | .af = AF_INET, | ||
95 | }; | ||
96 | |||
97 | /* Source NAT */ | ||
98 | static unsigned int ipt_snat_target(struct sk_buff **pskb, | ||
99 | const struct net_device *in, | ||
100 | const struct net_device *out, | ||
101 | unsigned int hooknum, | ||
102 | const struct xt_target *target, | ||
103 | const void *targinfo) | ||
104 | { | ||
105 | struct ip_conntrack *ct; | ||
106 | enum ip_conntrack_info ctinfo; | ||
107 | const struct ip_nat_multi_range_compat *mr = targinfo; | ||
108 | |||
109 | IP_NF_ASSERT(hooknum == NF_IP_POST_ROUTING); | ||
110 | |||
111 | ct = ip_conntrack_get(*pskb, &ctinfo); | ||
112 | |||
113 | /* Connection must be valid and new. */ | ||
114 | IP_NF_ASSERT(ct && (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED | ||
115 | || ctinfo == IP_CT_RELATED + IP_CT_IS_REPLY)); | ||
116 | IP_NF_ASSERT(out); | ||
117 | |||
118 | return ip_nat_setup_info(ct, &mr->range[0], hooknum); | ||
119 | } | ||
120 | |||
121 | /* Before 2.6.11 we did implicit source NAT if required. Warn about change. */ | ||
122 | static void warn_if_extra_mangle(__be32 dstip, __be32 srcip) | ||
123 | { | ||
124 | static int warned = 0; | ||
125 | struct flowi fl = { .nl_u = { .ip4_u = { .daddr = dstip } } }; | ||
126 | struct rtable *rt; | ||
127 | |||
128 | if (ip_route_output_key(&rt, &fl) != 0) | ||
129 | return; | ||
130 | |||
131 | if (rt->rt_src != srcip && !warned) { | ||
132 | printk("NAT: no longer support implicit source local NAT\n"); | ||
133 | printk("NAT: packet src %u.%u.%u.%u -> dst %u.%u.%u.%u\n", | ||
134 | NIPQUAD(srcip), NIPQUAD(dstip)); | ||
135 | warned = 1; | ||
136 | } | ||
137 | ip_rt_put(rt); | ||
138 | } | ||
139 | |||
140 | static unsigned int ipt_dnat_target(struct sk_buff **pskb, | ||
141 | const struct net_device *in, | ||
142 | const struct net_device *out, | ||
143 | unsigned int hooknum, | ||
144 | const struct xt_target *target, | ||
145 | const void *targinfo) | ||
146 | { | ||
147 | struct ip_conntrack *ct; | ||
148 | enum ip_conntrack_info ctinfo; | ||
149 | const struct ip_nat_multi_range_compat *mr = targinfo; | ||
150 | |||
151 | IP_NF_ASSERT(hooknum == NF_IP_PRE_ROUTING | ||
152 | || hooknum == NF_IP_LOCAL_OUT); | ||
153 | |||
154 | ct = ip_conntrack_get(*pskb, &ctinfo); | ||
155 | |||
156 | /* Connection must be valid and new. */ | ||
157 | IP_NF_ASSERT(ct && (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED)); | ||
158 | |||
159 | if (hooknum == NF_IP_LOCAL_OUT | ||
160 | && mr->range[0].flags & IP_NAT_RANGE_MAP_IPS) | ||
161 | warn_if_extra_mangle(ip_hdr(*pskb)->daddr, | ||
162 | mr->range[0].min_ip); | ||
163 | |||
164 | return ip_nat_setup_info(ct, &mr->range[0], hooknum); | ||
165 | } | ||
166 | |||
167 | static int ipt_snat_checkentry(const char *tablename, | ||
168 | const void *entry, | ||
169 | const struct xt_target *target, | ||
170 | void *targinfo, | ||
171 | unsigned int hook_mask) | ||
172 | { | ||
173 | struct ip_nat_multi_range_compat *mr = targinfo; | ||
174 | |||
175 | /* Must be a valid range */ | ||
176 | if (mr->rangesize != 1) { | ||
177 | printk("SNAT: multiple ranges no longer supported\n"); | ||
178 | return 0; | ||
179 | } | ||
180 | return 1; | ||
181 | } | ||
182 | |||
183 | static int ipt_dnat_checkentry(const char *tablename, | ||
184 | const void *entry, | ||
185 | const struct xt_target *target, | ||
186 | void *targinfo, | ||
187 | unsigned int hook_mask) | ||
188 | { | ||
189 | struct ip_nat_multi_range_compat *mr = targinfo; | ||
190 | |||
191 | /* Must be a valid range */ | ||
192 | if (mr->rangesize != 1) { | ||
193 | printk("DNAT: multiple ranges no longer supported\n"); | ||
194 | return 0; | ||
195 | } | ||
196 | if (mr->range[0].flags & IP_NAT_RANGE_PROTO_RANDOM) { | ||
197 | printk("DNAT: port randomization not supported\n"); | ||
198 | return 0; | ||
199 | } | ||
200 | return 1; | ||
201 | } | ||
202 | |||
203 | inline unsigned int | ||
204 | alloc_null_binding(struct ip_conntrack *conntrack, | ||
205 | struct ip_nat_info *info, | ||
206 | unsigned int hooknum) | ||
207 | { | ||
208 | /* Force range to this IP; let proto decide mapping for | ||
209 | per-proto parts (hence not IP_NAT_RANGE_PROTO_SPECIFIED). | ||
210 | Use reply in case it's already been mangled (eg local packet). | ||
211 | */ | ||
212 | __be32 ip | ||
213 | = (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC | ||
214 | ? conntrack->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip | ||
215 | : conntrack->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip); | ||
216 | struct ip_nat_range range | ||
217 | = { IP_NAT_RANGE_MAP_IPS, ip, ip, { 0 }, { 0 } }; | ||
218 | |||
219 | DEBUGP("Allocating NULL binding for %p (%u.%u.%u.%u)\n", conntrack, | ||
220 | NIPQUAD(ip)); | ||
221 | return ip_nat_setup_info(conntrack, &range, hooknum); | ||
222 | } | ||
223 | |||
224 | unsigned int | ||
225 | alloc_null_binding_confirmed(struct ip_conntrack *conntrack, | ||
226 | struct ip_nat_info *info, | ||
227 | unsigned int hooknum) | ||
228 | { | ||
229 | __be32 ip | ||
230 | = (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC | ||
231 | ? conntrack->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip | ||
232 | : conntrack->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip); | ||
233 | u_int16_t all | ||
234 | = (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC | ||
235 | ? conntrack->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.all | ||
236 | : conntrack->tuplehash[IP_CT_DIR_REPLY].tuple.src.u.all); | ||
237 | struct ip_nat_range range | ||
238 | = { IP_NAT_RANGE_MAP_IPS, ip, ip, { all }, { all } }; | ||
239 | |||
240 | DEBUGP("Allocating NULL binding for confirmed %p (%u.%u.%u.%u)\n", | ||
241 | conntrack, NIPQUAD(ip)); | ||
242 | return ip_nat_setup_info(conntrack, &range, hooknum); | ||
243 | } | ||
244 | |||
245 | int ip_nat_rule_find(struct sk_buff **pskb, | ||
246 | unsigned int hooknum, | ||
247 | const struct net_device *in, | ||
248 | const struct net_device *out, | ||
249 | struct ip_conntrack *ct, | ||
250 | struct ip_nat_info *info) | ||
251 | { | ||
252 | int ret; | ||
253 | |||
254 | ret = ipt_do_table(pskb, hooknum, in, out, &nat_table); | ||
255 | |||
256 | if (ret == NF_ACCEPT) { | ||
257 | if (!ip_nat_initialized(ct, HOOK2MANIP(hooknum))) | ||
258 | /* NUL mapping */ | ||
259 | ret = alloc_null_binding(ct, info, hooknum); | ||
260 | } | ||
261 | return ret; | ||
262 | } | ||
263 | |||
264 | static struct xt_target ipt_snat_reg = { | ||
265 | .name = "SNAT", | ||
266 | .family = AF_INET, | ||
267 | .target = ipt_snat_target, | ||
268 | .targetsize = sizeof(struct ip_nat_multi_range_compat), | ||
269 | .table = "nat", | ||
270 | .hooks = 1 << NF_IP_POST_ROUTING, | ||
271 | .checkentry = ipt_snat_checkentry, | ||
272 | }; | ||
273 | |||
274 | static struct xt_target ipt_dnat_reg = { | ||
275 | .name = "DNAT", | ||
276 | .family = AF_INET, | ||
277 | .target = ipt_dnat_target, | ||
278 | .targetsize = sizeof(struct ip_nat_multi_range_compat), | ||
279 | .table = "nat", | ||
280 | .hooks = (1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_LOCAL_OUT), | ||
281 | .checkentry = ipt_dnat_checkentry, | ||
282 | }; | ||
283 | |||
284 | int __init ip_nat_rule_init(void) | ||
285 | { | ||
286 | int ret; | ||
287 | |||
288 | ret = ipt_register_table(&nat_table, &nat_initial_table.repl); | ||
289 | if (ret != 0) | ||
290 | return ret; | ||
291 | ret = xt_register_target(&ipt_snat_reg); | ||
292 | if (ret != 0) | ||
293 | goto unregister_table; | ||
294 | |||
295 | ret = xt_register_target(&ipt_dnat_reg); | ||
296 | if (ret != 0) | ||
297 | goto unregister_snat; | ||
298 | |||
299 | return ret; | ||
300 | |||
301 | unregister_snat: | ||
302 | xt_unregister_target(&ipt_snat_reg); | ||
303 | unregister_table: | ||
304 | xt_unregister_table(&nat_table); | ||
305 | |||
306 | return ret; | ||
307 | } | ||
308 | |||
309 | void ip_nat_rule_cleanup(void) | ||
310 | { | ||
311 | xt_unregister_target(&ipt_dnat_reg); | ||
312 | xt_unregister_target(&ipt_snat_reg); | ||
313 | ipt_unregister_table(&nat_table); | ||
314 | } | ||
diff --git a/net/ipv4/netfilter/ip_nat_sip.c b/net/ipv4/netfilter/ip_nat_sip.c deleted file mode 100644 index 84953601762d..000000000000 --- a/net/ipv4/netfilter/ip_nat_sip.c +++ /dev/null | |||
@@ -1,282 +0,0 @@ | |||
1 | /* SIP extension for UDP NAT alteration. | ||
2 | * | ||
3 | * (C) 2005 by Christian Hentschel <chentschel@arnet.com.ar> | ||
4 | * based on RR's ip_nat_ftp.c and other modules. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | */ | ||
10 | |||
11 | #include <linux/module.h> | ||
12 | #include <linux/skbuff.h> | ||
13 | #include <linux/ip.h> | ||
14 | #include <linux/udp.h> | ||
15 | |||
16 | #include <linux/netfilter_ipv4.h> | ||
17 | #include <linux/netfilter_ipv4/ip_nat.h> | ||
18 | #include <linux/netfilter_ipv4/ip_nat_helper.h> | ||
19 | #include <linux/netfilter_ipv4/ip_conntrack_helper.h> | ||
20 | #include <linux/netfilter_ipv4/ip_conntrack_sip.h> | ||
21 | |||
22 | MODULE_LICENSE("GPL"); | ||
23 | MODULE_AUTHOR("Christian Hentschel <chentschel@arnet.com.ar>"); | ||
24 | MODULE_DESCRIPTION("SIP NAT helper"); | ||
25 | |||
26 | #if 0 | ||
27 | #define DEBUGP printk | ||
28 | #else | ||
29 | #define DEBUGP(format, args...) | ||
30 | #endif | ||
31 | |||
32 | struct addr_map { | ||
33 | struct { | ||
34 | char src[sizeof("nnn.nnn.nnn.nnn:nnnnn")]; | ||
35 | char dst[sizeof("nnn.nnn.nnn.nnn:nnnnn")]; | ||
36 | unsigned int srclen, srciplen; | ||
37 | unsigned int dstlen, dstiplen; | ||
38 | } addr[IP_CT_DIR_MAX]; | ||
39 | }; | ||
40 | |||
41 | static void addr_map_init(struct ip_conntrack *ct, struct addr_map *map) | ||
42 | { | ||
43 | struct ip_conntrack_tuple *t; | ||
44 | enum ip_conntrack_dir dir; | ||
45 | unsigned int n; | ||
46 | |||
47 | for (dir = 0; dir < IP_CT_DIR_MAX; dir++) { | ||
48 | t = &ct->tuplehash[dir].tuple; | ||
49 | |||
50 | n = sprintf(map->addr[dir].src, "%u.%u.%u.%u", | ||
51 | NIPQUAD(t->src.ip)); | ||
52 | map->addr[dir].srciplen = n; | ||
53 | n += sprintf(map->addr[dir].src + n, ":%u", | ||
54 | ntohs(t->src.u.udp.port)); | ||
55 | map->addr[dir].srclen = n; | ||
56 | |||
57 | n = sprintf(map->addr[dir].dst, "%u.%u.%u.%u", | ||
58 | NIPQUAD(t->dst.ip)); | ||
59 | map->addr[dir].dstiplen = n; | ||
60 | n += sprintf(map->addr[dir].dst + n, ":%u", | ||
61 | ntohs(t->dst.u.udp.port)); | ||
62 | map->addr[dir].dstlen = n; | ||
63 | } | ||
64 | } | ||
65 | |||
66 | static int map_sip_addr(struct sk_buff **pskb, enum ip_conntrack_info ctinfo, | ||
67 | struct ip_conntrack *ct, const char **dptr, size_t dlen, | ||
68 | enum sip_header_pos pos, struct addr_map *map) | ||
69 | { | ||
70 | enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); | ||
71 | unsigned int matchlen, matchoff, addrlen; | ||
72 | char *addr; | ||
73 | |||
74 | if (ct_sip_get_info(*dptr, dlen, &matchoff, &matchlen, pos) <= 0) | ||
75 | return 1; | ||
76 | |||
77 | if ((matchlen == map->addr[dir].srciplen || | ||
78 | matchlen == map->addr[dir].srclen) && | ||
79 | memcmp(*dptr + matchoff, map->addr[dir].src, matchlen) == 0) { | ||
80 | addr = map->addr[!dir].dst; | ||
81 | addrlen = map->addr[!dir].dstlen; | ||
82 | } else if ((matchlen == map->addr[dir].dstiplen || | ||
83 | matchlen == map->addr[dir].dstlen) && | ||
84 | memcmp(*dptr + matchoff, map->addr[dir].dst, matchlen) == 0) { | ||
85 | addr = map->addr[!dir].src; | ||
86 | addrlen = map->addr[!dir].srclen; | ||
87 | } else | ||
88 | return 1; | ||
89 | |||
90 | if (!ip_nat_mangle_udp_packet(pskb, ct, ctinfo, | ||
91 | matchoff, matchlen, addr, addrlen)) | ||
92 | return 0; | ||
93 | *dptr = (*pskb)->data + ip_hdrlen(*pskb) + sizeof(struct udphdr); | ||
94 | return 1; | ||
95 | |||
96 | } | ||
97 | |||
98 | static unsigned int ip_nat_sip(struct sk_buff **pskb, | ||
99 | enum ip_conntrack_info ctinfo, | ||
100 | struct ip_conntrack *ct, | ||
101 | const char **dptr) | ||
102 | { | ||
103 | enum sip_header_pos pos; | ||
104 | struct addr_map map; | ||
105 | int dataoff, datalen; | ||
106 | |||
107 | dataoff = ip_hdrlen(*pskb) + sizeof(struct udphdr); | ||
108 | datalen = (*pskb)->len - dataoff; | ||
109 | if (datalen < sizeof("SIP/2.0") - 1) | ||
110 | return NF_DROP; | ||
111 | |||
112 | addr_map_init(ct, &map); | ||
113 | |||
114 | /* Basic rules: requests and responses. */ | ||
115 | if (strncmp(*dptr, "SIP/2.0", sizeof("SIP/2.0") - 1) != 0) { | ||
116 | /* 10.2: Constructing the REGISTER Request: | ||
117 | * | ||
118 | * The "userinfo" and "@" components of the SIP URI MUST NOT | ||
119 | * be present. | ||
120 | */ | ||
121 | if (datalen >= sizeof("REGISTER") - 1 && | ||
122 | strncmp(*dptr, "REGISTER", sizeof("REGISTER") - 1) == 0) | ||
123 | pos = POS_REG_REQ_URI; | ||
124 | else | ||
125 | pos = POS_REQ_URI; | ||
126 | |||
127 | if (!map_sip_addr(pskb, ctinfo, ct, dptr, datalen, pos, &map)) | ||
128 | return NF_DROP; | ||
129 | } | ||
130 | |||
131 | if (!map_sip_addr(pskb, ctinfo, ct, dptr, datalen, POS_FROM, &map) || | ||
132 | !map_sip_addr(pskb, ctinfo, ct, dptr, datalen, POS_TO, &map) || | ||
133 | !map_sip_addr(pskb, ctinfo, ct, dptr, datalen, POS_VIA, &map) || | ||
134 | !map_sip_addr(pskb, ctinfo, ct, dptr, datalen, POS_CONTACT, &map)) | ||
135 | return NF_DROP; | ||
136 | return NF_ACCEPT; | ||
137 | } | ||
138 | |||
139 | static unsigned int mangle_sip_packet(struct sk_buff **pskb, | ||
140 | enum ip_conntrack_info ctinfo, | ||
141 | struct ip_conntrack *ct, | ||
142 | const char **dptr, size_t dlen, | ||
143 | char *buffer, int bufflen, | ||
144 | enum sip_header_pos pos) | ||
145 | { | ||
146 | unsigned int matchlen, matchoff; | ||
147 | |||
148 | if (ct_sip_get_info(*dptr, dlen, &matchoff, &matchlen, pos) <= 0) | ||
149 | return 0; | ||
150 | |||
151 | if (!ip_nat_mangle_udp_packet(pskb, ct, ctinfo, | ||
152 | matchoff, matchlen, buffer, bufflen)) | ||
153 | return 0; | ||
154 | |||
155 | /* We need to reload this. Thanks Patrick. */ | ||
156 | *dptr = (*pskb)->data + ip_hdrlen(*pskb) + sizeof(struct udphdr); | ||
157 | return 1; | ||
158 | } | ||
159 | |||
160 | static int mangle_content_len(struct sk_buff **pskb, | ||
161 | enum ip_conntrack_info ctinfo, | ||
162 | struct ip_conntrack *ct, | ||
163 | const char *dptr) | ||
164 | { | ||
165 | unsigned int dataoff, matchoff, matchlen; | ||
166 | char buffer[sizeof("65536")]; | ||
167 | int bufflen; | ||
168 | |||
169 | dataoff = ip_hdrlen(*pskb) + sizeof(struct udphdr); | ||
170 | |||
171 | /* Get actual SDP lenght */ | ||
172 | if (ct_sip_get_info(dptr, (*pskb)->len - dataoff, &matchoff, | ||
173 | &matchlen, POS_SDP_HEADER) > 0) { | ||
174 | |||
175 | /* since ct_sip_get_info() give us a pointer passing 'v=' | ||
176 | we need to add 2 bytes in this count. */ | ||
177 | int c_len = (*pskb)->len - dataoff - matchoff + 2; | ||
178 | |||
179 | /* Now, update SDP lenght */ | ||
180 | if (ct_sip_get_info(dptr, (*pskb)->len - dataoff, &matchoff, | ||
181 | &matchlen, POS_CONTENT) > 0) { | ||
182 | |||
183 | bufflen = sprintf(buffer, "%u", c_len); | ||
184 | |||
185 | return ip_nat_mangle_udp_packet(pskb, ct, ctinfo, | ||
186 | matchoff, matchlen, | ||
187 | buffer, bufflen); | ||
188 | } | ||
189 | } | ||
190 | return 0; | ||
191 | } | ||
192 | |||
193 | static unsigned int mangle_sdp(struct sk_buff **pskb, | ||
194 | enum ip_conntrack_info ctinfo, | ||
195 | struct ip_conntrack *ct, | ||
196 | __be32 newip, u_int16_t port, | ||
197 | const char *dptr) | ||
198 | { | ||
199 | char buffer[sizeof("nnn.nnn.nnn.nnn")]; | ||
200 | unsigned int dataoff, bufflen; | ||
201 | |||
202 | dataoff = ip_hdrlen(*pskb) + sizeof(struct udphdr); | ||
203 | |||
204 | /* Mangle owner and contact info. */ | ||
205 | bufflen = sprintf(buffer, "%u.%u.%u.%u", NIPQUAD(newip)); | ||
206 | if (!mangle_sip_packet(pskb, ctinfo, ct, &dptr, (*pskb)->len - dataoff, | ||
207 | buffer, bufflen, POS_OWNER)) | ||
208 | return 0; | ||
209 | |||
210 | if (!mangle_sip_packet(pskb, ctinfo, ct, &dptr, (*pskb)->len - dataoff, | ||
211 | buffer, bufflen, POS_CONNECTION)) | ||
212 | return 0; | ||
213 | |||
214 | /* Mangle media port. */ | ||
215 | bufflen = sprintf(buffer, "%u", port); | ||
216 | if (!mangle_sip_packet(pskb, ctinfo, ct, &dptr, (*pskb)->len - dataoff, | ||
217 | buffer, bufflen, POS_MEDIA)) | ||
218 | return 0; | ||
219 | |||
220 | return mangle_content_len(pskb, ctinfo, ct, dptr); | ||
221 | } | ||
222 | |||
223 | /* So, this packet has hit the connection tracking matching code. | ||
224 | Mangle it, and change the expectation to match the new version. */ | ||
225 | static unsigned int ip_nat_sdp(struct sk_buff **pskb, | ||
226 | enum ip_conntrack_info ctinfo, | ||
227 | struct ip_conntrack_expect *exp, | ||
228 | const char *dptr) | ||
229 | { | ||
230 | struct ip_conntrack *ct = exp->master; | ||
231 | enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); | ||
232 | __be32 newip; | ||
233 | u_int16_t port; | ||
234 | |||
235 | DEBUGP("ip_nat_sdp():\n"); | ||
236 | |||
237 | /* Connection will come from reply */ | ||
238 | newip = ct->tuplehash[!dir].tuple.dst.ip; | ||
239 | |||
240 | exp->tuple.dst.ip = newip; | ||
241 | exp->saved_proto.udp.port = exp->tuple.dst.u.udp.port; | ||
242 | exp->dir = !dir; | ||
243 | |||
244 | /* When you see the packet, we need to NAT it the same as the | ||
245 | this one. */ | ||
246 | exp->expectfn = ip_nat_follow_master; | ||
247 | |||
248 | /* Try to get same port: if not, try to change it. */ | ||
249 | for (port = ntohs(exp->saved_proto.udp.port); port != 0; port++) { | ||
250 | exp->tuple.dst.u.udp.port = htons(port); | ||
251 | if (ip_conntrack_expect_related(exp) == 0) | ||
252 | break; | ||
253 | } | ||
254 | |||
255 | if (port == 0) | ||
256 | return NF_DROP; | ||
257 | |||
258 | if (!mangle_sdp(pskb, ctinfo, ct, newip, port, dptr)) { | ||
259 | ip_conntrack_unexpect_related(exp); | ||
260 | return NF_DROP; | ||
261 | } | ||
262 | return NF_ACCEPT; | ||
263 | } | ||
264 | |||
265 | static void __exit fini(void) | ||
266 | { | ||
267 | rcu_assign_pointer(ip_nat_sip_hook, NULL); | ||
268 | rcu_assign_pointer(ip_nat_sdp_hook, NULL); | ||
269 | synchronize_rcu(); | ||
270 | } | ||
271 | |||
272 | static int __init init(void) | ||
273 | { | ||
274 | BUG_ON(rcu_dereference(ip_nat_sip_hook)); | ||
275 | BUG_ON(rcu_dereference(ip_nat_sdp_hook)); | ||
276 | rcu_assign_pointer(ip_nat_sip_hook, ip_nat_sip); | ||
277 | rcu_assign_pointer(ip_nat_sdp_hook, ip_nat_sdp); | ||
278 | return 0; | ||
279 | } | ||
280 | |||
281 | module_init(init); | ||
282 | module_exit(fini); | ||
diff --git a/net/ipv4/netfilter/ip_nat_snmp_basic.c b/net/ipv4/netfilter/ip_nat_snmp_basic.c deleted file mode 100644 index 025e04587789..000000000000 --- a/net/ipv4/netfilter/ip_nat_snmp_basic.c +++ /dev/null | |||
@@ -1,1333 +0,0 @@ | |||
1 | /* | ||
2 | * ip_nat_snmp_basic.c | ||
3 | * | ||
4 | * Basic SNMP Application Layer Gateway | ||
5 | * | ||
6 | * This IP NAT module is intended for use with SNMP network | ||
7 | * discovery and monitoring applications where target networks use | ||
8 | * conflicting private address realms. | ||
9 | * | ||
10 | * Static NAT is used to remap the networks from the view of the network | ||
11 | * management system at the IP layer, and this module remaps some application | ||
12 | * layer addresses to match. | ||
13 | * | ||
14 | * The simplest form of ALG is performed, where only tagged IP addresses | ||
15 | * are modified. The module does not need to be MIB aware and only scans | ||
16 | * messages at the ASN.1/BER level. | ||
17 | * | ||
18 | * Currently, only SNMPv1 and SNMPv2 are supported. | ||
19 | * | ||
20 | * More information on ALG and associated issues can be found in | ||
21 | * RFC 2962 | ||
22 | * | ||
23 | * The ASB.1/BER parsing code is derived from the gxsnmp package by Gregory | ||
24 | * McLean & Jochen Friedrich, stripped down for use in the kernel. | ||
25 | * | ||
26 | * Copyright (c) 2000 RP Internet (www.rpi.net.au). | ||
27 | * | ||
28 | * This program is free software; you can redistribute it and/or modify | ||
29 | * it under the terms of the GNU General Public License as published by | ||
30 | * the Free Software Foundation; either version 2 of the License, or | ||
31 | * (at your option) any later version. | ||
32 | * This program is distributed in the hope that it will be useful, | ||
33 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
34 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
35 | * GNU General Public License for more details. | ||
36 | * You should have received a copy of the GNU General Public License | ||
37 | * along with this program; if not, write to the Free Software | ||
38 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
39 | * | ||
40 | * Author: James Morris <jmorris@intercode.com.au> | ||
41 | * | ||
42 | * Updates: | ||
43 | * 2000-08-06: Convert to new helper API (Harald Welte). | ||
44 | * | ||
45 | */ | ||
46 | #include <linux/in.h> | ||
47 | #include <linux/module.h> | ||
48 | #include <linux/types.h> | ||
49 | #include <linux/kernel.h> | ||
50 | #include <linux/moduleparam.h> | ||
51 | #include <linux/netfilter_ipv4.h> | ||
52 | #include <linux/netfilter_ipv4/ip_nat.h> | ||
53 | #include <linux/netfilter_ipv4/ip_conntrack_helper.h> | ||
54 | #include <linux/netfilter_ipv4/ip_nat_helper.h> | ||
55 | #include <linux/ip.h> | ||
56 | #include <linux/udp.h> | ||
57 | #include <net/checksum.h> | ||
58 | #include <net/udp.h> | ||
59 | #include <asm/uaccess.h> | ||
60 | |||
61 | MODULE_LICENSE("GPL"); | ||
62 | MODULE_AUTHOR("James Morris <jmorris@intercode.com.au>"); | ||
63 | MODULE_DESCRIPTION("Basic SNMP Application Layer Gateway"); | ||
64 | |||
65 | #define SNMP_PORT 161 | ||
66 | #define SNMP_TRAP_PORT 162 | ||
67 | #define NOCT1(n) (*(u8 *)n) | ||
68 | |||
69 | static int debug; | ||
70 | static DEFINE_SPINLOCK(snmp_lock); | ||
71 | |||
72 | /* | ||
73 | * Application layer address mapping mimics the NAT mapping, but | ||
74 | * only for the first octet in this case (a more flexible system | ||
75 | * can be implemented if needed). | ||
76 | */ | ||
77 | struct oct1_map | ||
78 | { | ||
79 | u_int8_t from; | ||
80 | u_int8_t to; | ||
81 | }; | ||
82 | |||
83 | |||
84 | /***************************************************************************** | ||
85 | * | ||
86 | * Basic ASN.1 decoding routines (gxsnmp author Dirk Wisse) | ||
87 | * | ||
88 | *****************************************************************************/ | ||
89 | |||
90 | /* Class */ | ||
91 | #define ASN1_UNI 0 /* Universal */ | ||
92 | #define ASN1_APL 1 /* Application */ | ||
93 | #define ASN1_CTX 2 /* Context */ | ||
94 | #define ASN1_PRV 3 /* Private */ | ||
95 | |||
96 | /* Tag */ | ||
97 | #define ASN1_EOC 0 /* End Of Contents */ | ||
98 | #define ASN1_BOL 1 /* Boolean */ | ||
99 | #define ASN1_INT 2 /* Integer */ | ||
100 | #define ASN1_BTS 3 /* Bit String */ | ||
101 | #define ASN1_OTS 4 /* Octet String */ | ||
102 | #define ASN1_NUL 5 /* Null */ | ||
103 | #define ASN1_OJI 6 /* Object Identifier */ | ||
104 | #define ASN1_OJD 7 /* Object Description */ | ||
105 | #define ASN1_EXT 8 /* External */ | ||
106 | #define ASN1_SEQ 16 /* Sequence */ | ||
107 | #define ASN1_SET 17 /* Set */ | ||
108 | #define ASN1_NUMSTR 18 /* Numerical String */ | ||
109 | #define ASN1_PRNSTR 19 /* Printable String */ | ||
110 | #define ASN1_TEXSTR 20 /* Teletext String */ | ||
111 | #define ASN1_VIDSTR 21 /* Video String */ | ||
112 | #define ASN1_IA5STR 22 /* IA5 String */ | ||
113 | #define ASN1_UNITIM 23 /* Universal Time */ | ||
114 | #define ASN1_GENTIM 24 /* General Time */ | ||
115 | #define ASN1_GRASTR 25 /* Graphical String */ | ||
116 | #define ASN1_VISSTR 26 /* Visible String */ | ||
117 | #define ASN1_GENSTR 27 /* General String */ | ||
118 | |||
119 | /* Primitive / Constructed methods*/ | ||
120 | #define ASN1_PRI 0 /* Primitive */ | ||
121 | #define ASN1_CON 1 /* Constructed */ | ||
122 | |||
123 | /* | ||
124 | * Error codes. | ||
125 | */ | ||
126 | #define ASN1_ERR_NOERROR 0 | ||
127 | #define ASN1_ERR_DEC_EMPTY 2 | ||
128 | #define ASN1_ERR_DEC_EOC_MISMATCH 3 | ||
129 | #define ASN1_ERR_DEC_LENGTH_MISMATCH 4 | ||
130 | #define ASN1_ERR_DEC_BADVALUE 5 | ||
131 | |||
132 | /* | ||
133 | * ASN.1 context. | ||
134 | */ | ||
135 | struct asn1_ctx | ||
136 | { | ||
137 | int error; /* Error condition */ | ||
138 | unsigned char *pointer; /* Octet just to be decoded */ | ||
139 | unsigned char *begin; /* First octet */ | ||
140 | unsigned char *end; /* Octet after last octet */ | ||
141 | }; | ||
142 | |||
143 | /* | ||
144 | * Octet string (not null terminated) | ||
145 | */ | ||
146 | struct asn1_octstr | ||
147 | { | ||
148 | unsigned char *data; | ||
149 | unsigned int len; | ||
150 | }; | ||
151 | |||
152 | static void asn1_open(struct asn1_ctx *ctx, | ||
153 | unsigned char *buf, | ||
154 | unsigned int len) | ||
155 | { | ||
156 | ctx->begin = buf; | ||
157 | ctx->end = buf + len; | ||
158 | ctx->pointer = buf; | ||
159 | ctx->error = ASN1_ERR_NOERROR; | ||
160 | } | ||
161 | |||
162 | static unsigned char asn1_octet_decode(struct asn1_ctx *ctx, unsigned char *ch) | ||
163 | { | ||
164 | if (ctx->pointer >= ctx->end) { | ||
165 | ctx->error = ASN1_ERR_DEC_EMPTY; | ||
166 | return 0; | ||
167 | } | ||
168 | *ch = *(ctx->pointer)++; | ||
169 | return 1; | ||
170 | } | ||
171 | |||
172 | static unsigned char asn1_tag_decode(struct asn1_ctx *ctx, unsigned int *tag) | ||
173 | { | ||
174 | unsigned char ch; | ||
175 | |||
176 | *tag = 0; | ||
177 | |||
178 | do | ||
179 | { | ||
180 | if (!asn1_octet_decode(ctx, &ch)) | ||
181 | return 0; | ||
182 | *tag <<= 7; | ||
183 | *tag |= ch & 0x7F; | ||
184 | } while ((ch & 0x80) == 0x80); | ||
185 | return 1; | ||
186 | } | ||
187 | |||
188 | static unsigned char asn1_id_decode(struct asn1_ctx *ctx, | ||
189 | unsigned int *cls, | ||
190 | unsigned int *con, | ||
191 | unsigned int *tag) | ||
192 | { | ||
193 | unsigned char ch; | ||
194 | |||
195 | if (!asn1_octet_decode(ctx, &ch)) | ||
196 | return 0; | ||
197 | |||
198 | *cls = (ch & 0xC0) >> 6; | ||
199 | *con = (ch & 0x20) >> 5; | ||
200 | *tag = (ch & 0x1F); | ||
201 | |||
202 | if (*tag == 0x1F) { | ||
203 | if (!asn1_tag_decode(ctx, tag)) | ||
204 | return 0; | ||
205 | } | ||
206 | return 1; | ||
207 | } | ||
208 | |||
209 | static unsigned char asn1_length_decode(struct asn1_ctx *ctx, | ||
210 | unsigned int *def, | ||
211 | unsigned int *len) | ||
212 | { | ||
213 | unsigned char ch, cnt; | ||
214 | |||
215 | if (!asn1_octet_decode(ctx, &ch)) | ||
216 | return 0; | ||
217 | |||
218 | if (ch == 0x80) | ||
219 | *def = 0; | ||
220 | else { | ||
221 | *def = 1; | ||
222 | |||
223 | if (ch < 0x80) | ||
224 | *len = ch; | ||
225 | else { | ||
226 | cnt = (unsigned char) (ch & 0x7F); | ||
227 | *len = 0; | ||
228 | |||
229 | while (cnt > 0) { | ||
230 | if (!asn1_octet_decode(ctx, &ch)) | ||
231 | return 0; | ||
232 | *len <<= 8; | ||
233 | *len |= ch; | ||
234 | cnt--; | ||
235 | } | ||
236 | } | ||
237 | } | ||
238 | return 1; | ||
239 | } | ||
240 | |||
241 | static unsigned char asn1_header_decode(struct asn1_ctx *ctx, | ||
242 | unsigned char **eoc, | ||
243 | unsigned int *cls, | ||
244 | unsigned int *con, | ||
245 | unsigned int *tag) | ||
246 | { | ||
247 | unsigned int def, len; | ||
248 | |||
249 | if (!asn1_id_decode(ctx, cls, con, tag)) | ||
250 | return 0; | ||
251 | |||
252 | def = len = 0; | ||
253 | if (!asn1_length_decode(ctx, &def, &len)) | ||
254 | return 0; | ||
255 | |||
256 | if (def) | ||
257 | *eoc = ctx->pointer + len; | ||
258 | else | ||
259 | *eoc = NULL; | ||
260 | return 1; | ||
261 | } | ||
262 | |||
263 | static unsigned char asn1_eoc_decode(struct asn1_ctx *ctx, unsigned char *eoc) | ||
264 | { | ||
265 | unsigned char ch; | ||
266 | |||
267 | if (eoc == 0) { | ||
268 | if (!asn1_octet_decode(ctx, &ch)) | ||
269 | return 0; | ||
270 | |||
271 | if (ch != 0x00) { | ||
272 | ctx->error = ASN1_ERR_DEC_EOC_MISMATCH; | ||
273 | return 0; | ||
274 | } | ||
275 | |||
276 | if (!asn1_octet_decode(ctx, &ch)) | ||
277 | return 0; | ||
278 | |||
279 | if (ch != 0x00) { | ||
280 | ctx->error = ASN1_ERR_DEC_EOC_MISMATCH; | ||
281 | return 0; | ||
282 | } | ||
283 | return 1; | ||
284 | } else { | ||
285 | if (ctx->pointer != eoc) { | ||
286 | ctx->error = ASN1_ERR_DEC_LENGTH_MISMATCH; | ||
287 | return 0; | ||
288 | } | ||
289 | return 1; | ||
290 | } | ||
291 | } | ||
292 | |||
293 | static unsigned char asn1_null_decode(struct asn1_ctx *ctx, unsigned char *eoc) | ||
294 | { | ||
295 | ctx->pointer = eoc; | ||
296 | return 1; | ||
297 | } | ||
298 | |||
299 | static unsigned char asn1_long_decode(struct asn1_ctx *ctx, | ||
300 | unsigned char *eoc, | ||
301 | long *integer) | ||
302 | { | ||
303 | unsigned char ch; | ||
304 | unsigned int len; | ||
305 | |||
306 | if (!asn1_octet_decode(ctx, &ch)) | ||
307 | return 0; | ||
308 | |||
309 | *integer = (signed char) ch; | ||
310 | len = 1; | ||
311 | |||
312 | while (ctx->pointer < eoc) { | ||
313 | if (++len > sizeof (long)) { | ||
314 | ctx->error = ASN1_ERR_DEC_BADVALUE; | ||
315 | return 0; | ||
316 | } | ||
317 | |||
318 | if (!asn1_octet_decode(ctx, &ch)) | ||
319 | return 0; | ||
320 | |||
321 | *integer <<= 8; | ||
322 | *integer |= ch; | ||
323 | } | ||
324 | return 1; | ||
325 | } | ||
326 | |||
327 | static unsigned char asn1_uint_decode(struct asn1_ctx *ctx, | ||
328 | unsigned char *eoc, | ||
329 | unsigned int *integer) | ||
330 | { | ||
331 | unsigned char ch; | ||
332 | unsigned int len; | ||
333 | |||
334 | if (!asn1_octet_decode(ctx, &ch)) | ||
335 | return 0; | ||
336 | |||
337 | *integer = ch; | ||
338 | if (ch == 0) len = 0; | ||
339 | else len = 1; | ||
340 | |||
341 | while (ctx->pointer < eoc) { | ||
342 | if (++len > sizeof (unsigned int)) { | ||
343 | ctx->error = ASN1_ERR_DEC_BADVALUE; | ||
344 | return 0; | ||
345 | } | ||
346 | |||
347 | if (!asn1_octet_decode(ctx, &ch)) | ||
348 | return 0; | ||
349 | |||
350 | *integer <<= 8; | ||
351 | *integer |= ch; | ||
352 | } | ||
353 | return 1; | ||
354 | } | ||
355 | |||
356 | static unsigned char asn1_ulong_decode(struct asn1_ctx *ctx, | ||
357 | unsigned char *eoc, | ||
358 | unsigned long *integer) | ||
359 | { | ||
360 | unsigned char ch; | ||
361 | unsigned int len; | ||
362 | |||
363 | if (!asn1_octet_decode(ctx, &ch)) | ||
364 | return 0; | ||
365 | |||
366 | *integer = ch; | ||
367 | if (ch == 0) len = 0; | ||
368 | else len = 1; | ||
369 | |||
370 | while (ctx->pointer < eoc) { | ||
371 | if (++len > sizeof (unsigned long)) { | ||
372 | ctx->error = ASN1_ERR_DEC_BADVALUE; | ||
373 | return 0; | ||
374 | } | ||
375 | |||
376 | if (!asn1_octet_decode(ctx, &ch)) | ||
377 | return 0; | ||
378 | |||
379 | *integer <<= 8; | ||
380 | *integer |= ch; | ||
381 | } | ||
382 | return 1; | ||
383 | } | ||
384 | |||
385 | static unsigned char asn1_octets_decode(struct asn1_ctx *ctx, | ||
386 | unsigned char *eoc, | ||
387 | unsigned char **octets, | ||
388 | unsigned int *len) | ||
389 | { | ||
390 | unsigned char *ptr; | ||
391 | |||
392 | *len = 0; | ||
393 | |||
394 | *octets = kmalloc(eoc - ctx->pointer, GFP_ATOMIC); | ||
395 | if (*octets == NULL) { | ||
396 | if (net_ratelimit()) | ||
397 | printk("OOM in bsalg (%d)\n", __LINE__); | ||
398 | return 0; | ||
399 | } | ||
400 | |||
401 | ptr = *octets; | ||
402 | while (ctx->pointer < eoc) { | ||
403 | if (!asn1_octet_decode(ctx, (unsigned char *)ptr++)) { | ||
404 | kfree(*octets); | ||
405 | *octets = NULL; | ||
406 | return 0; | ||
407 | } | ||
408 | (*len)++; | ||
409 | } | ||
410 | return 1; | ||
411 | } | ||
412 | |||
413 | static unsigned char asn1_subid_decode(struct asn1_ctx *ctx, | ||
414 | unsigned long *subid) | ||
415 | { | ||
416 | unsigned char ch; | ||
417 | |||
418 | *subid = 0; | ||
419 | |||
420 | do { | ||
421 | if (!asn1_octet_decode(ctx, &ch)) | ||
422 | return 0; | ||
423 | |||
424 | *subid <<= 7; | ||
425 | *subid |= ch & 0x7F; | ||
426 | } while ((ch & 0x80) == 0x80); | ||
427 | return 1; | ||
428 | } | ||
429 | |||
430 | static unsigned char asn1_oid_decode(struct asn1_ctx *ctx, | ||
431 | unsigned char *eoc, | ||
432 | unsigned long **oid, | ||
433 | unsigned int *len) | ||
434 | { | ||
435 | unsigned long subid; | ||
436 | unsigned int size; | ||
437 | unsigned long *optr; | ||
438 | |||
439 | size = eoc - ctx->pointer + 1; | ||
440 | *oid = kmalloc(size * sizeof(unsigned long), GFP_ATOMIC); | ||
441 | if (*oid == NULL) { | ||
442 | if (net_ratelimit()) | ||
443 | printk("OOM in bsalg (%d)\n", __LINE__); | ||
444 | return 0; | ||
445 | } | ||
446 | |||
447 | optr = *oid; | ||
448 | |||
449 | if (!asn1_subid_decode(ctx, &subid)) { | ||
450 | kfree(*oid); | ||
451 | *oid = NULL; | ||
452 | return 0; | ||
453 | } | ||
454 | |||
455 | if (subid < 40) { | ||
456 | optr [0] = 0; | ||
457 | optr [1] = subid; | ||
458 | } else if (subid < 80) { | ||
459 | optr [0] = 1; | ||
460 | optr [1] = subid - 40; | ||
461 | } else { | ||
462 | optr [0] = 2; | ||
463 | optr [1] = subid - 80; | ||
464 | } | ||
465 | |||
466 | *len = 2; | ||
467 | optr += 2; | ||
468 | |||
469 | while (ctx->pointer < eoc) { | ||
470 | if (++(*len) > size) { | ||
471 | ctx->error = ASN1_ERR_DEC_BADVALUE; | ||
472 | kfree(*oid); | ||
473 | *oid = NULL; | ||
474 | return 0; | ||
475 | } | ||
476 | |||
477 | if (!asn1_subid_decode(ctx, optr++)) { | ||
478 | kfree(*oid); | ||
479 | *oid = NULL; | ||
480 | return 0; | ||
481 | } | ||
482 | } | ||
483 | return 1; | ||
484 | } | ||
485 | |||
486 | /***************************************************************************** | ||
487 | * | ||
488 | * SNMP decoding routines (gxsnmp author Dirk Wisse) | ||
489 | * | ||
490 | *****************************************************************************/ | ||
491 | |||
492 | /* SNMP Versions */ | ||
493 | #define SNMP_V1 0 | ||
494 | #define SNMP_V2C 1 | ||
495 | #define SNMP_V2 2 | ||
496 | #define SNMP_V3 3 | ||
497 | |||
498 | /* Default Sizes */ | ||
499 | #define SNMP_SIZE_COMM 256 | ||
500 | #define SNMP_SIZE_OBJECTID 128 | ||
501 | #define SNMP_SIZE_BUFCHR 256 | ||
502 | #define SNMP_SIZE_BUFINT 128 | ||
503 | #define SNMP_SIZE_SMALLOBJECTID 16 | ||
504 | |||
505 | /* Requests */ | ||
506 | #define SNMP_PDU_GET 0 | ||
507 | #define SNMP_PDU_NEXT 1 | ||
508 | #define SNMP_PDU_RESPONSE 2 | ||
509 | #define SNMP_PDU_SET 3 | ||
510 | #define SNMP_PDU_TRAP1 4 | ||
511 | #define SNMP_PDU_BULK 5 | ||
512 | #define SNMP_PDU_INFORM 6 | ||
513 | #define SNMP_PDU_TRAP2 7 | ||
514 | |||
515 | /* Errors */ | ||
516 | #define SNMP_NOERROR 0 | ||
517 | #define SNMP_TOOBIG 1 | ||
518 | #define SNMP_NOSUCHNAME 2 | ||
519 | #define SNMP_BADVALUE 3 | ||
520 | #define SNMP_READONLY 4 | ||
521 | #define SNMP_GENERROR 5 | ||
522 | #define SNMP_NOACCESS 6 | ||
523 | #define SNMP_WRONGTYPE 7 | ||
524 | #define SNMP_WRONGLENGTH 8 | ||
525 | #define SNMP_WRONGENCODING 9 | ||
526 | #define SNMP_WRONGVALUE 10 | ||
527 | #define SNMP_NOCREATION 11 | ||
528 | #define SNMP_INCONSISTENTVALUE 12 | ||
529 | #define SNMP_RESOURCEUNAVAILABLE 13 | ||
530 | #define SNMP_COMMITFAILED 14 | ||
531 | #define SNMP_UNDOFAILED 15 | ||
532 | #define SNMP_AUTHORIZATIONERROR 16 | ||
533 | #define SNMP_NOTWRITABLE 17 | ||
534 | #define SNMP_INCONSISTENTNAME 18 | ||
535 | |||
536 | /* General SNMP V1 Traps */ | ||
537 | #define SNMP_TRAP_COLDSTART 0 | ||
538 | #define SNMP_TRAP_WARMSTART 1 | ||
539 | #define SNMP_TRAP_LINKDOWN 2 | ||
540 | #define SNMP_TRAP_LINKUP 3 | ||
541 | #define SNMP_TRAP_AUTFAILURE 4 | ||
542 | #define SNMP_TRAP_EQPNEIGHBORLOSS 5 | ||
543 | #define SNMP_TRAP_ENTSPECIFIC 6 | ||
544 | |||
545 | /* SNMPv1 Types */ | ||
546 | #define SNMP_NULL 0 | ||
547 | #define SNMP_INTEGER 1 /* l */ | ||
548 | #define SNMP_OCTETSTR 2 /* c */ | ||
549 | #define SNMP_DISPLAYSTR 2 /* c */ | ||
550 | #define SNMP_OBJECTID 3 /* ul */ | ||
551 | #define SNMP_IPADDR 4 /* uc */ | ||
552 | #define SNMP_COUNTER 5 /* ul */ | ||
553 | #define SNMP_GAUGE 6 /* ul */ | ||
554 | #define SNMP_TIMETICKS 7 /* ul */ | ||
555 | #define SNMP_OPAQUE 8 /* c */ | ||
556 | |||
557 | /* Additional SNMPv2 Types */ | ||
558 | #define SNMP_UINTEGER 5 /* ul */ | ||
559 | #define SNMP_BITSTR 9 /* uc */ | ||
560 | #define SNMP_NSAP 10 /* uc */ | ||
561 | #define SNMP_COUNTER64 11 /* ul */ | ||
562 | #define SNMP_NOSUCHOBJECT 12 | ||
563 | #define SNMP_NOSUCHINSTANCE 13 | ||
564 | #define SNMP_ENDOFMIBVIEW 14 | ||
565 | |||
566 | union snmp_syntax | ||
567 | { | ||
568 | unsigned char uc[0]; /* 8 bit unsigned */ | ||
569 | char c[0]; /* 8 bit signed */ | ||
570 | unsigned long ul[0]; /* 32 bit unsigned */ | ||
571 | long l[0]; /* 32 bit signed */ | ||
572 | }; | ||
573 | |||
574 | struct snmp_object | ||
575 | { | ||
576 | unsigned long *id; | ||
577 | unsigned int id_len; | ||
578 | unsigned short type; | ||
579 | unsigned int syntax_len; | ||
580 | union snmp_syntax syntax; | ||
581 | }; | ||
582 | |||
583 | struct snmp_request | ||
584 | { | ||
585 | unsigned long id; | ||
586 | unsigned int error_status; | ||
587 | unsigned int error_index; | ||
588 | }; | ||
589 | |||
590 | struct snmp_v1_trap | ||
591 | { | ||
592 | unsigned long *id; | ||
593 | unsigned int id_len; | ||
594 | unsigned long ip_address; /* pointer */ | ||
595 | unsigned int general; | ||
596 | unsigned int specific; | ||
597 | unsigned long time; | ||
598 | }; | ||
599 | |||
600 | /* SNMP types */ | ||
601 | #define SNMP_IPA 0 | ||
602 | #define SNMP_CNT 1 | ||
603 | #define SNMP_GGE 2 | ||
604 | #define SNMP_TIT 3 | ||
605 | #define SNMP_OPQ 4 | ||
606 | #define SNMP_C64 6 | ||
607 | |||
608 | /* SNMP errors */ | ||
609 | #define SERR_NSO 0 | ||
610 | #define SERR_NSI 1 | ||
611 | #define SERR_EOM 2 | ||
612 | |||
613 | static inline void mangle_address(unsigned char *begin, | ||
614 | unsigned char *addr, | ||
615 | const struct oct1_map *map, | ||
616 | __sum16 *check); | ||
617 | struct snmp_cnv | ||
618 | { | ||
619 | unsigned int class; | ||
620 | unsigned int tag; | ||
621 | int syntax; | ||
622 | }; | ||
623 | |||
624 | static struct snmp_cnv snmp_conv [] = | ||
625 | { | ||
626 | {ASN1_UNI, ASN1_NUL, SNMP_NULL}, | ||
627 | {ASN1_UNI, ASN1_INT, SNMP_INTEGER}, | ||
628 | {ASN1_UNI, ASN1_OTS, SNMP_OCTETSTR}, | ||
629 | {ASN1_UNI, ASN1_OTS, SNMP_DISPLAYSTR}, | ||
630 | {ASN1_UNI, ASN1_OJI, SNMP_OBJECTID}, | ||
631 | {ASN1_APL, SNMP_IPA, SNMP_IPADDR}, | ||
632 | {ASN1_APL, SNMP_CNT, SNMP_COUNTER}, /* Counter32 */ | ||
633 | {ASN1_APL, SNMP_GGE, SNMP_GAUGE}, /* Gauge32 == Unsigned32 */ | ||
634 | {ASN1_APL, SNMP_TIT, SNMP_TIMETICKS}, | ||
635 | {ASN1_APL, SNMP_OPQ, SNMP_OPAQUE}, | ||
636 | |||
637 | /* SNMPv2 data types and errors */ | ||
638 | {ASN1_UNI, ASN1_BTS, SNMP_BITSTR}, | ||
639 | {ASN1_APL, SNMP_C64, SNMP_COUNTER64}, | ||
640 | {ASN1_CTX, SERR_NSO, SNMP_NOSUCHOBJECT}, | ||
641 | {ASN1_CTX, SERR_NSI, SNMP_NOSUCHINSTANCE}, | ||
642 | {ASN1_CTX, SERR_EOM, SNMP_ENDOFMIBVIEW}, | ||
643 | {0, 0, -1} | ||
644 | }; | ||
645 | |||
646 | static unsigned char snmp_tag_cls2syntax(unsigned int tag, | ||
647 | unsigned int cls, | ||
648 | unsigned short *syntax) | ||
649 | { | ||
650 | struct snmp_cnv *cnv; | ||
651 | |||
652 | cnv = snmp_conv; | ||
653 | |||
654 | while (cnv->syntax != -1) { | ||
655 | if (cnv->tag == tag && cnv->class == cls) { | ||
656 | *syntax = cnv->syntax; | ||
657 | return 1; | ||
658 | } | ||
659 | cnv++; | ||
660 | } | ||
661 | return 0; | ||
662 | } | ||
663 | |||
664 | static unsigned char snmp_object_decode(struct asn1_ctx *ctx, | ||
665 | struct snmp_object **obj) | ||
666 | { | ||
667 | unsigned int cls, con, tag, len, idlen; | ||
668 | unsigned short type; | ||
669 | unsigned char *eoc, *end, *p; | ||
670 | unsigned long *lp, *id; | ||
671 | unsigned long ul; | ||
672 | long l; | ||
673 | |||
674 | *obj = NULL; | ||
675 | id = NULL; | ||
676 | |||
677 | if (!asn1_header_decode(ctx, &eoc, &cls, &con, &tag)) | ||
678 | return 0; | ||
679 | |||
680 | if (cls != ASN1_UNI || con != ASN1_CON || tag != ASN1_SEQ) | ||
681 | return 0; | ||
682 | |||
683 | if (!asn1_header_decode(ctx, &end, &cls, &con, &tag)) | ||
684 | return 0; | ||
685 | |||
686 | if (cls != ASN1_UNI || con != ASN1_PRI || tag != ASN1_OJI) | ||
687 | return 0; | ||
688 | |||
689 | if (!asn1_oid_decode(ctx, end, &id, &idlen)) | ||
690 | return 0; | ||
691 | |||
692 | if (!asn1_header_decode(ctx, &end, &cls, &con, &tag)) { | ||
693 | kfree(id); | ||
694 | return 0; | ||
695 | } | ||
696 | |||
697 | if (con != ASN1_PRI) { | ||
698 | kfree(id); | ||
699 | return 0; | ||
700 | } | ||
701 | |||
702 | type = 0; | ||
703 | if (!snmp_tag_cls2syntax(tag, cls, &type)) { | ||
704 | kfree(id); | ||
705 | return 0; | ||
706 | } | ||
707 | |||
708 | l = 0; | ||
709 | switch (type) { | ||
710 | case SNMP_INTEGER: | ||
711 | len = sizeof(long); | ||
712 | if (!asn1_long_decode(ctx, end, &l)) { | ||
713 | kfree(id); | ||
714 | return 0; | ||
715 | } | ||
716 | *obj = kmalloc(sizeof(struct snmp_object) + len, | ||
717 | GFP_ATOMIC); | ||
718 | if (*obj == NULL) { | ||
719 | kfree(id); | ||
720 | if (net_ratelimit()) | ||
721 | printk("OOM in bsalg (%d)\n", __LINE__); | ||
722 | return 0; | ||
723 | } | ||
724 | (*obj)->syntax.l[0] = l; | ||
725 | break; | ||
726 | case SNMP_OCTETSTR: | ||
727 | case SNMP_OPAQUE: | ||
728 | if (!asn1_octets_decode(ctx, end, &p, &len)) { | ||
729 | kfree(id); | ||
730 | return 0; | ||
731 | } | ||
732 | *obj = kmalloc(sizeof(struct snmp_object) + len, | ||
733 | GFP_ATOMIC); | ||
734 | if (*obj == NULL) { | ||
735 | kfree(id); | ||
736 | if (net_ratelimit()) | ||
737 | printk("OOM in bsalg (%d)\n", __LINE__); | ||
738 | return 0; | ||
739 | } | ||
740 | memcpy((*obj)->syntax.c, p, len); | ||
741 | kfree(p); | ||
742 | break; | ||
743 | case SNMP_NULL: | ||
744 | case SNMP_NOSUCHOBJECT: | ||
745 | case SNMP_NOSUCHINSTANCE: | ||
746 | case SNMP_ENDOFMIBVIEW: | ||
747 | len = 0; | ||
748 | *obj = kmalloc(sizeof(struct snmp_object), GFP_ATOMIC); | ||
749 | if (*obj == NULL) { | ||
750 | kfree(id); | ||
751 | if (net_ratelimit()) | ||
752 | printk("OOM in bsalg (%d)\n", __LINE__); | ||
753 | return 0; | ||
754 | } | ||
755 | if (!asn1_null_decode(ctx, end)) { | ||
756 | kfree(id); | ||
757 | kfree(*obj); | ||
758 | *obj = NULL; | ||
759 | return 0; | ||
760 | } | ||
761 | break; | ||
762 | case SNMP_OBJECTID: | ||
763 | if (!asn1_oid_decode(ctx, end, (unsigned long **)&lp, &len)) { | ||
764 | kfree(id); | ||
765 | return 0; | ||
766 | } | ||
767 | len *= sizeof(unsigned long); | ||
768 | *obj = kmalloc(sizeof(struct snmp_object) + len, GFP_ATOMIC); | ||
769 | if (*obj == NULL) { | ||
770 | kfree(lp); | ||
771 | kfree(id); | ||
772 | if (net_ratelimit()) | ||
773 | printk("OOM in bsalg (%d)\n", __LINE__); | ||
774 | return 0; | ||
775 | } | ||
776 | memcpy((*obj)->syntax.ul, lp, len); | ||
777 | kfree(lp); | ||
778 | break; | ||
779 | case SNMP_IPADDR: | ||
780 | if (!asn1_octets_decode(ctx, end, &p, &len)) { | ||
781 | kfree(id); | ||
782 | return 0; | ||
783 | } | ||
784 | if (len != 4) { | ||
785 | kfree(p); | ||
786 | kfree(id); | ||
787 | return 0; | ||
788 | } | ||
789 | *obj = kmalloc(sizeof(struct snmp_object) + len, GFP_ATOMIC); | ||
790 | if (*obj == NULL) { | ||
791 | kfree(p); | ||
792 | kfree(id); | ||
793 | if (net_ratelimit()) | ||
794 | printk("OOM in bsalg (%d)\n", __LINE__); | ||
795 | return 0; | ||
796 | } | ||
797 | memcpy((*obj)->syntax.uc, p, len); | ||
798 | kfree(p); | ||
799 | break; | ||
800 | case SNMP_COUNTER: | ||
801 | case SNMP_GAUGE: | ||
802 | case SNMP_TIMETICKS: | ||
803 | len = sizeof(unsigned long); | ||
804 | if (!asn1_ulong_decode(ctx, end, &ul)) { | ||
805 | kfree(id); | ||
806 | return 0; | ||
807 | } | ||
808 | *obj = kmalloc(sizeof(struct snmp_object) + len, GFP_ATOMIC); | ||
809 | if (*obj == NULL) { | ||
810 | kfree(id); | ||
811 | if (net_ratelimit()) | ||
812 | printk("OOM in bsalg (%d)\n", __LINE__); | ||
813 | return 0; | ||
814 | } | ||
815 | (*obj)->syntax.ul[0] = ul; | ||
816 | break; | ||
817 | default: | ||
818 | kfree(id); | ||
819 | return 0; | ||
820 | } | ||
821 | |||
822 | (*obj)->syntax_len = len; | ||
823 | (*obj)->type = type; | ||
824 | (*obj)->id = id; | ||
825 | (*obj)->id_len = idlen; | ||
826 | |||
827 | if (!asn1_eoc_decode(ctx, eoc)) { | ||
828 | kfree(id); | ||
829 | kfree(*obj); | ||
830 | *obj = NULL; | ||
831 | return 0; | ||
832 | } | ||
833 | return 1; | ||
834 | } | ||
835 | |||
836 | static unsigned char snmp_request_decode(struct asn1_ctx *ctx, | ||
837 | struct snmp_request *request) | ||
838 | { | ||
839 | unsigned int cls, con, tag; | ||
840 | unsigned char *end; | ||
841 | |||
842 | if (!asn1_header_decode(ctx, &end, &cls, &con, &tag)) | ||
843 | return 0; | ||
844 | |||
845 | if (cls != ASN1_UNI || con != ASN1_PRI || tag != ASN1_INT) | ||
846 | return 0; | ||
847 | |||
848 | if (!asn1_ulong_decode(ctx, end, &request->id)) | ||
849 | return 0; | ||
850 | |||
851 | if (!asn1_header_decode(ctx, &end, &cls, &con, &tag)) | ||
852 | return 0; | ||
853 | |||
854 | if (cls != ASN1_UNI || con != ASN1_PRI || tag != ASN1_INT) | ||
855 | return 0; | ||
856 | |||
857 | if (!asn1_uint_decode(ctx, end, &request->error_status)) | ||
858 | return 0; | ||
859 | |||
860 | if (!asn1_header_decode(ctx, &end, &cls, &con, &tag)) | ||
861 | return 0; | ||
862 | |||
863 | if (cls != ASN1_UNI || con != ASN1_PRI || tag != ASN1_INT) | ||
864 | return 0; | ||
865 | |||
866 | if (!asn1_uint_decode(ctx, end, &request->error_index)) | ||
867 | return 0; | ||
868 | |||
869 | return 1; | ||
870 | } | ||
871 | |||
872 | /* | ||
873 | * Fast checksum update for possibly oddly-aligned UDP byte, from the | ||
874 | * code example in the draft. | ||
875 | */ | ||
876 | static void fast_csum(__sum16 *csum, | ||
877 | const unsigned char *optr, | ||
878 | const unsigned char *nptr, | ||
879 | int offset) | ||
880 | { | ||
881 | unsigned char s[4]; | ||
882 | |||
883 | if (offset & 1) { | ||
884 | s[0] = s[2] = 0; | ||
885 | s[1] = ~*optr; | ||
886 | s[3] = *nptr; | ||
887 | } else { | ||
888 | s[1] = s[3] = 0; | ||
889 | s[0] = ~*optr; | ||
890 | s[2] = *nptr; | ||
891 | } | ||
892 | |||
893 | *csum = csum_fold(csum_partial(s, 4, ~csum_unfold(*csum))); | ||
894 | } | ||
895 | |||
896 | /* | ||
897 | * Mangle IP address. | ||
898 | * - begin points to the start of the snmp messgae | ||
899 | * - addr points to the start of the address | ||
900 | */ | ||
901 | static inline void mangle_address(unsigned char *begin, | ||
902 | unsigned char *addr, | ||
903 | const struct oct1_map *map, | ||
904 | __sum16 *check) | ||
905 | { | ||
906 | if (map->from == NOCT1(addr)) { | ||
907 | u_int32_t old; | ||
908 | |||
909 | if (debug) | ||
910 | memcpy(&old, (unsigned char *)addr, sizeof(old)); | ||
911 | |||
912 | *addr = map->to; | ||
913 | |||
914 | /* Update UDP checksum if being used */ | ||
915 | if (*check) { | ||
916 | fast_csum(check, | ||
917 | &map->from, &map->to, addr - begin); | ||
918 | } | ||
919 | |||
920 | if (debug) | ||
921 | printk(KERN_DEBUG "bsalg: mapped %u.%u.%u.%u to " | ||
922 | "%u.%u.%u.%u\n", NIPQUAD(old), NIPQUAD(*addr)); | ||
923 | } | ||
924 | } | ||
925 | |||
926 | static unsigned char snmp_trap_decode(struct asn1_ctx *ctx, | ||
927 | struct snmp_v1_trap *trap, | ||
928 | const struct oct1_map *map, | ||
929 | __sum16 *check) | ||
930 | { | ||
931 | unsigned int cls, con, tag, len; | ||
932 | unsigned char *end; | ||
933 | |||
934 | if (!asn1_header_decode(ctx, &end, &cls, &con, &tag)) | ||
935 | return 0; | ||
936 | |||
937 | if (cls != ASN1_UNI || con != ASN1_PRI || tag != ASN1_OJI) | ||
938 | return 0; | ||
939 | |||
940 | if (!asn1_oid_decode(ctx, end, &trap->id, &trap->id_len)) | ||
941 | return 0; | ||
942 | |||
943 | if (!asn1_header_decode(ctx, &end, &cls, &con, &tag)) | ||
944 | goto err_id_free; | ||
945 | |||
946 | if (!((cls == ASN1_APL && con == ASN1_PRI && tag == SNMP_IPA) || | ||
947 | (cls == ASN1_UNI && con == ASN1_PRI && tag == ASN1_OTS))) | ||
948 | goto err_id_free; | ||
949 | |||
950 | if (!asn1_octets_decode(ctx, end, (unsigned char **)&trap->ip_address, &len)) | ||
951 | goto err_id_free; | ||
952 | |||
953 | /* IPv4 only */ | ||
954 | if (len != 4) | ||
955 | goto err_addr_free; | ||
956 | |||
957 | mangle_address(ctx->begin, ctx->pointer - 4, map, check); | ||
958 | |||
959 | if (!asn1_header_decode(ctx, &end, &cls, &con, &tag)) | ||
960 | goto err_addr_free; | ||
961 | |||
962 | if (cls != ASN1_UNI || con != ASN1_PRI || tag != ASN1_INT) | ||
963 | goto err_addr_free; | ||
964 | |||
965 | if (!asn1_uint_decode(ctx, end, &trap->general)) | ||
966 | goto err_addr_free; | ||
967 | |||
968 | if (!asn1_header_decode(ctx, &end, &cls, &con, &tag)) | ||
969 | goto err_addr_free; | ||
970 | |||
971 | if (cls != ASN1_UNI || con != ASN1_PRI || tag != ASN1_INT) | ||
972 | goto err_addr_free; | ||
973 | |||
974 | if (!asn1_uint_decode(ctx, end, &trap->specific)) | ||
975 | goto err_addr_free; | ||
976 | |||
977 | if (!asn1_header_decode(ctx, &end, &cls, &con, &tag)) | ||
978 | goto err_addr_free; | ||
979 | |||
980 | if (!((cls == ASN1_APL && con == ASN1_PRI && tag == SNMP_TIT) || | ||
981 | (cls == ASN1_UNI && con == ASN1_PRI && tag == ASN1_INT))) | ||
982 | goto err_addr_free; | ||
983 | |||
984 | if (!asn1_ulong_decode(ctx, end, &trap->time)) | ||
985 | goto err_addr_free; | ||
986 | |||
987 | return 1; | ||
988 | |||
989 | err_addr_free: | ||
990 | kfree((unsigned long *)trap->ip_address); | ||
991 | |||
992 | err_id_free: | ||
993 | kfree(trap->id); | ||
994 | |||
995 | return 0; | ||
996 | } | ||
997 | |||
998 | /***************************************************************************** | ||
999 | * | ||
1000 | * Misc. routines | ||
1001 | * | ||
1002 | *****************************************************************************/ | ||
1003 | |||
1004 | static void hex_dump(unsigned char *buf, size_t len) | ||
1005 | { | ||
1006 | size_t i; | ||
1007 | |||
1008 | for (i = 0; i < len; i++) { | ||
1009 | if (i && !(i % 16)) | ||
1010 | printk("\n"); | ||
1011 | printk("%02x ", *(buf + i)); | ||
1012 | } | ||
1013 | printk("\n"); | ||
1014 | } | ||
1015 | |||
1016 | /* | ||
1017 | * Parse and mangle SNMP message according to mapping. | ||
1018 | * (And this is the fucking 'basic' method). | ||
1019 | */ | ||
1020 | static int snmp_parse_mangle(unsigned char *msg, | ||
1021 | u_int16_t len, | ||
1022 | const struct oct1_map *map, | ||
1023 | __sum16 *check) | ||
1024 | { | ||
1025 | unsigned char *eoc, *end; | ||
1026 | unsigned int cls, con, tag, vers, pdutype; | ||
1027 | struct asn1_ctx ctx; | ||
1028 | struct asn1_octstr comm; | ||
1029 | struct snmp_object **obj; | ||
1030 | |||
1031 | if (debug > 1) | ||
1032 | hex_dump(msg, len); | ||
1033 | |||
1034 | asn1_open(&ctx, msg, len); | ||
1035 | |||
1036 | /* | ||
1037 | * Start of SNMP message. | ||
1038 | */ | ||
1039 | if (!asn1_header_decode(&ctx, &eoc, &cls, &con, &tag)) | ||
1040 | return 0; | ||
1041 | if (cls != ASN1_UNI || con != ASN1_CON || tag != ASN1_SEQ) | ||
1042 | return 0; | ||
1043 | |||
1044 | /* | ||
1045 | * Version 1 or 2 handled. | ||
1046 | */ | ||
1047 | if (!asn1_header_decode(&ctx, &end, &cls, &con, &tag)) | ||
1048 | return 0; | ||
1049 | if (cls != ASN1_UNI || con != ASN1_PRI || tag != ASN1_INT) | ||
1050 | return 0; | ||
1051 | if (!asn1_uint_decode (&ctx, end, &vers)) | ||
1052 | return 0; | ||
1053 | if (debug > 1) | ||
1054 | printk(KERN_DEBUG "bsalg: snmp version: %u\n", vers + 1); | ||
1055 | if (vers > 1) | ||
1056 | return 1; | ||
1057 | |||
1058 | /* | ||
1059 | * Community. | ||
1060 | */ | ||
1061 | if (!asn1_header_decode (&ctx, &end, &cls, &con, &tag)) | ||
1062 | return 0; | ||
1063 | if (cls != ASN1_UNI || con != ASN1_PRI || tag != ASN1_OTS) | ||
1064 | return 0; | ||
1065 | if (!asn1_octets_decode(&ctx, end, &comm.data, &comm.len)) | ||
1066 | return 0; | ||
1067 | if (debug > 1) { | ||
1068 | unsigned int i; | ||
1069 | |||
1070 | printk(KERN_DEBUG "bsalg: community: "); | ||
1071 | for (i = 0; i < comm.len; i++) | ||
1072 | printk("%c", comm.data[i]); | ||
1073 | printk("\n"); | ||
1074 | } | ||
1075 | kfree(comm.data); | ||
1076 | |||
1077 | /* | ||
1078 | * PDU type | ||
1079 | */ | ||
1080 | if (!asn1_header_decode(&ctx, &eoc, &cls, &con, &pdutype)) | ||
1081 | return 0; | ||
1082 | if (cls != ASN1_CTX || con != ASN1_CON) | ||
1083 | return 0; | ||
1084 | if (debug > 1) { | ||
1085 | unsigned char *pdus[] = { | ||
1086 | [SNMP_PDU_GET] = "get", | ||
1087 | [SNMP_PDU_NEXT] = "get-next", | ||
1088 | [SNMP_PDU_RESPONSE] = "response", | ||
1089 | [SNMP_PDU_SET] = "set", | ||
1090 | [SNMP_PDU_TRAP1] = "trapv1", | ||
1091 | [SNMP_PDU_BULK] = "bulk", | ||
1092 | [SNMP_PDU_INFORM] = "inform", | ||
1093 | [SNMP_PDU_TRAP2] = "trapv2" | ||
1094 | }; | ||
1095 | |||
1096 | if (pdutype > SNMP_PDU_TRAP2) | ||
1097 | printk(KERN_DEBUG "bsalg: bad pdu type %u\n", pdutype); | ||
1098 | else | ||
1099 | printk(KERN_DEBUG "bsalg: pdu: %s\n", pdus[pdutype]); | ||
1100 | } | ||
1101 | if (pdutype != SNMP_PDU_RESPONSE && | ||
1102 | pdutype != SNMP_PDU_TRAP1 && pdutype != SNMP_PDU_TRAP2) | ||
1103 | return 1; | ||
1104 | |||
1105 | /* | ||
1106 | * Request header or v1 trap | ||
1107 | */ | ||
1108 | if (pdutype == SNMP_PDU_TRAP1) { | ||
1109 | struct snmp_v1_trap trap; | ||
1110 | unsigned char ret = snmp_trap_decode(&ctx, &trap, map, check); | ||
1111 | |||
1112 | if (ret) { | ||
1113 | kfree(trap.id); | ||
1114 | kfree((unsigned long *)trap.ip_address); | ||
1115 | } else | ||
1116 | return ret; | ||
1117 | |||
1118 | } else { | ||
1119 | struct snmp_request req; | ||
1120 | |||
1121 | if (!snmp_request_decode(&ctx, &req)) | ||
1122 | return 0; | ||
1123 | |||
1124 | if (debug > 1) | ||
1125 | printk(KERN_DEBUG "bsalg: request: id=0x%lx error_status=%u " | ||
1126 | "error_index=%u\n", req.id, req.error_status, | ||
1127 | req.error_index); | ||
1128 | } | ||
1129 | |||
1130 | /* | ||
1131 | * Loop through objects, look for IP addresses to mangle. | ||
1132 | */ | ||
1133 | if (!asn1_header_decode(&ctx, &eoc, &cls, &con, &tag)) | ||
1134 | return 0; | ||
1135 | |||
1136 | if (cls != ASN1_UNI || con != ASN1_CON || tag != ASN1_SEQ) | ||
1137 | return 0; | ||
1138 | |||
1139 | obj = kmalloc(sizeof(struct snmp_object), GFP_ATOMIC); | ||
1140 | if (obj == NULL) { | ||
1141 | if (net_ratelimit()) | ||
1142 | printk(KERN_WARNING "OOM in bsalg(%d)\n", __LINE__); | ||
1143 | return 0; | ||
1144 | } | ||
1145 | |||
1146 | while (!asn1_eoc_decode(&ctx, eoc)) { | ||
1147 | unsigned int i; | ||
1148 | |||
1149 | if (!snmp_object_decode(&ctx, obj)) { | ||
1150 | if (*obj) { | ||
1151 | kfree((*obj)->id); | ||
1152 | kfree(*obj); | ||
1153 | } | ||
1154 | kfree(obj); | ||
1155 | return 0; | ||
1156 | } | ||
1157 | |||
1158 | if (debug > 1) { | ||
1159 | printk(KERN_DEBUG "bsalg: object: "); | ||
1160 | for (i = 0; i < (*obj)->id_len; i++) { | ||
1161 | if (i > 0) | ||
1162 | printk("."); | ||
1163 | printk("%lu", (*obj)->id[i]); | ||
1164 | } | ||
1165 | printk(": type=%u\n", (*obj)->type); | ||
1166 | |||
1167 | } | ||
1168 | |||
1169 | if ((*obj)->type == SNMP_IPADDR) | ||
1170 | mangle_address(ctx.begin, ctx.pointer - 4 , map, check); | ||
1171 | |||
1172 | kfree((*obj)->id); | ||
1173 | kfree(*obj); | ||
1174 | } | ||
1175 | kfree(obj); | ||
1176 | |||
1177 | if (!asn1_eoc_decode(&ctx, eoc)) | ||
1178 | return 0; | ||
1179 | |||
1180 | return 1; | ||
1181 | } | ||
1182 | |||
1183 | /***************************************************************************** | ||
1184 | * | ||
1185 | * NAT routines. | ||
1186 | * | ||
1187 | *****************************************************************************/ | ||
1188 | |||
1189 | /* | ||
1190 | * SNMP translation routine. | ||
1191 | */ | ||
1192 | static int snmp_translate(struct ip_conntrack *ct, | ||
1193 | enum ip_conntrack_info ctinfo, | ||
1194 | struct sk_buff **pskb) | ||
1195 | { | ||
1196 | struct iphdr *iph = ip_hdr(*pskb); | ||
1197 | struct udphdr *udph = (struct udphdr *)((__be32 *)iph + iph->ihl); | ||
1198 | u_int16_t udplen = ntohs(udph->len); | ||
1199 | u_int16_t paylen = udplen - sizeof(struct udphdr); | ||
1200 | int dir = CTINFO2DIR(ctinfo); | ||
1201 | struct oct1_map map; | ||
1202 | |||
1203 | /* | ||
1204 | * Determine mappping for application layer addresses based | ||
1205 | * on NAT manipulations for the packet. | ||
1206 | */ | ||
1207 | if (dir == IP_CT_DIR_ORIGINAL) { | ||
1208 | /* SNAT traps */ | ||
1209 | map.from = NOCT1(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip); | ||
1210 | map.to = NOCT1(&ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip); | ||
1211 | } else { | ||
1212 | /* DNAT replies */ | ||
1213 | map.from = NOCT1(&ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip); | ||
1214 | map.to = NOCT1(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip); | ||
1215 | } | ||
1216 | |||
1217 | if (map.from == map.to) | ||
1218 | return NF_ACCEPT; | ||
1219 | |||
1220 | if (!snmp_parse_mangle((unsigned char *)udph + sizeof(struct udphdr), | ||
1221 | paylen, &map, &udph->check)) { | ||
1222 | if (net_ratelimit()) | ||
1223 | printk(KERN_WARNING "bsalg: parser failed\n"); | ||
1224 | return NF_DROP; | ||
1225 | } | ||
1226 | return NF_ACCEPT; | ||
1227 | } | ||
1228 | |||
1229 | /* We don't actually set up expectations, just adjust internal IP | ||
1230 | * addresses if this is being NATted */ | ||
1231 | static int help(struct sk_buff **pskb, | ||
1232 | struct ip_conntrack *ct, | ||
1233 | enum ip_conntrack_info ctinfo) | ||
1234 | { | ||
1235 | int dir = CTINFO2DIR(ctinfo); | ||
1236 | unsigned int ret; | ||
1237 | struct iphdr *iph = ip_hdr(*pskb); | ||
1238 | struct udphdr *udph = (struct udphdr *)((u_int32_t *)iph + iph->ihl); | ||
1239 | |||
1240 | /* SNMP replies and originating SNMP traps get mangled */ | ||
1241 | if (udph->source == htons(SNMP_PORT) && dir != IP_CT_DIR_REPLY) | ||
1242 | return NF_ACCEPT; | ||
1243 | if (udph->dest == htons(SNMP_TRAP_PORT) && dir != IP_CT_DIR_ORIGINAL) | ||
1244 | return NF_ACCEPT; | ||
1245 | |||
1246 | /* No NAT? */ | ||
1247 | if (!(ct->status & IPS_NAT_MASK)) | ||
1248 | return NF_ACCEPT; | ||
1249 | |||
1250 | /* | ||
1251 | * Make sure the packet length is ok. So far, we were only guaranteed | ||
1252 | * to have a valid length IP header plus 8 bytes, which means we have | ||
1253 | * enough room for a UDP header. Just verify the UDP length field so we | ||
1254 | * can mess around with the payload. | ||
1255 | */ | ||
1256 | if (ntohs(udph->len) != (*pskb)->len - (iph->ihl << 2)) { | ||
1257 | if (net_ratelimit()) | ||
1258 | printk(KERN_WARNING "SNMP: dropping malformed packet " | ||
1259 | "src=%u.%u.%u.%u dst=%u.%u.%u.%u\n", | ||
1260 | NIPQUAD(iph->saddr), NIPQUAD(iph->daddr)); | ||
1261 | return NF_DROP; | ||
1262 | } | ||
1263 | |||
1264 | if (!skb_make_writable(pskb, (*pskb)->len)) | ||
1265 | return NF_DROP; | ||
1266 | |||
1267 | spin_lock_bh(&snmp_lock); | ||
1268 | ret = snmp_translate(ct, ctinfo, pskb); | ||
1269 | spin_unlock_bh(&snmp_lock); | ||
1270 | return ret; | ||
1271 | } | ||
1272 | |||
1273 | static struct ip_conntrack_helper snmp_helper = { | ||
1274 | .max_expected = 0, | ||
1275 | .timeout = 180, | ||
1276 | .me = THIS_MODULE, | ||
1277 | .help = help, | ||
1278 | .name = "snmp", | ||
1279 | |||
1280 | .tuple = {.src = {.u = {.udp = {.port = __constant_htons(SNMP_PORT)}}}, | ||
1281 | .dst = {.protonum = IPPROTO_UDP}, | ||
1282 | }, | ||
1283 | .mask = {.src = {.u = {0xFFFF}}, | ||
1284 | .dst = {.protonum = 0xFF}, | ||
1285 | }, | ||
1286 | }; | ||
1287 | |||
1288 | static struct ip_conntrack_helper snmp_trap_helper = { | ||
1289 | .max_expected = 0, | ||
1290 | .timeout = 180, | ||
1291 | .me = THIS_MODULE, | ||
1292 | .help = help, | ||
1293 | .name = "snmp_trap", | ||
1294 | |||
1295 | .tuple = {.src = {.u = {.udp = {.port = __constant_htons(SNMP_TRAP_PORT)}}}, | ||
1296 | .dst = {.protonum = IPPROTO_UDP}, | ||
1297 | }, | ||
1298 | .mask = {.src = {.u = {0xFFFF}}, | ||
1299 | .dst = {.protonum = 0xFF}, | ||
1300 | }, | ||
1301 | }; | ||
1302 | |||
1303 | /***************************************************************************** | ||
1304 | * | ||
1305 | * Module stuff. | ||
1306 | * | ||
1307 | *****************************************************************************/ | ||
1308 | |||
1309 | static int __init ip_nat_snmp_basic_init(void) | ||
1310 | { | ||
1311 | int ret = 0; | ||
1312 | |||
1313 | ret = ip_conntrack_helper_register(&snmp_helper); | ||
1314 | if (ret < 0) | ||
1315 | return ret; | ||
1316 | ret = ip_conntrack_helper_register(&snmp_trap_helper); | ||
1317 | if (ret < 0) { | ||
1318 | ip_conntrack_helper_unregister(&snmp_helper); | ||
1319 | return ret; | ||
1320 | } | ||
1321 | return ret; | ||
1322 | } | ||
1323 | |||
1324 | static void __exit ip_nat_snmp_basic_fini(void) | ||
1325 | { | ||
1326 | ip_conntrack_helper_unregister(&snmp_helper); | ||
1327 | ip_conntrack_helper_unregister(&snmp_trap_helper); | ||
1328 | } | ||
1329 | |||
1330 | module_init(ip_nat_snmp_basic_init); | ||
1331 | module_exit(ip_nat_snmp_basic_fini); | ||
1332 | |||
1333 | module_param(debug, int, 0600); | ||
diff --git a/net/ipv4/netfilter/ip_nat_standalone.c b/net/ipv4/netfilter/ip_nat_standalone.c deleted file mode 100644 index 32f7bf661fc8..000000000000 --- a/net/ipv4/netfilter/ip_nat_standalone.c +++ /dev/null | |||
@@ -1,387 +0,0 @@ | |||
1 | /* This file contains all the functions required for the standalone | ||
2 | ip_nat module. | ||
3 | |||
4 | These are not required by the compatibility layer. | ||
5 | */ | ||
6 | |||
7 | /* (C) 1999-2001 Paul `Rusty' Russell | ||
8 | * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org> | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License version 2 as | ||
12 | * published by the Free Software Foundation. | ||
13 | */ | ||
14 | |||
15 | /* | ||
16 | * 23 Apr 2001: Harald Welte <laforge@gnumonks.org> | ||
17 | * - new API and handling of conntrack/nat helpers | ||
18 | * - now capable of multiple expectations for one master | ||
19 | * */ | ||
20 | |||
21 | #include <linux/types.h> | ||
22 | #include <linux/icmp.h> | ||
23 | #include <linux/ip.h> | ||
24 | #include <linux/netfilter.h> | ||
25 | #include <linux/netfilter_ipv4.h> | ||
26 | #include <linux/module.h> | ||
27 | #include <linux/skbuff.h> | ||
28 | #include <linux/proc_fs.h> | ||
29 | #include <net/ip.h> | ||
30 | #include <net/checksum.h> | ||
31 | #include <linux/spinlock.h> | ||
32 | |||
33 | #include <linux/netfilter_ipv4/ip_nat.h> | ||
34 | #include <linux/netfilter_ipv4/ip_nat_rule.h> | ||
35 | #include <linux/netfilter_ipv4/ip_nat_protocol.h> | ||
36 | #include <linux/netfilter_ipv4/ip_nat_core.h> | ||
37 | #include <linux/netfilter_ipv4/ip_nat_helper.h> | ||
38 | #include <linux/netfilter_ipv4/ip_tables.h> | ||
39 | #include <linux/netfilter_ipv4/ip_conntrack_core.h> | ||
40 | |||
41 | #if 0 | ||
42 | #define DEBUGP printk | ||
43 | #else | ||
44 | #define DEBUGP(format, args...) | ||
45 | #endif | ||
46 | |||
47 | #ifdef CONFIG_XFRM | ||
48 | static void nat_decode_session(struct sk_buff *skb, struct flowi *fl) | ||
49 | { | ||
50 | struct ip_conntrack *ct; | ||
51 | struct ip_conntrack_tuple *t; | ||
52 | enum ip_conntrack_info ctinfo; | ||
53 | enum ip_conntrack_dir dir; | ||
54 | unsigned long statusbit; | ||
55 | |||
56 | ct = ip_conntrack_get(skb, &ctinfo); | ||
57 | if (ct == NULL) | ||
58 | return; | ||
59 | dir = CTINFO2DIR(ctinfo); | ||
60 | t = &ct->tuplehash[dir].tuple; | ||
61 | |||
62 | if (dir == IP_CT_DIR_ORIGINAL) | ||
63 | statusbit = IPS_DST_NAT; | ||
64 | else | ||
65 | statusbit = IPS_SRC_NAT; | ||
66 | |||
67 | if (ct->status & statusbit) { | ||
68 | fl->fl4_dst = t->dst.ip; | ||
69 | if (t->dst.protonum == IPPROTO_TCP || | ||
70 | t->dst.protonum == IPPROTO_UDP) | ||
71 | fl->fl_ip_dport = t->dst.u.tcp.port; | ||
72 | } | ||
73 | |||
74 | statusbit ^= IPS_NAT_MASK; | ||
75 | |||
76 | if (ct->status & statusbit) { | ||
77 | fl->fl4_src = t->src.ip; | ||
78 | if (t->dst.protonum == IPPROTO_TCP || | ||
79 | t->dst.protonum == IPPROTO_UDP) | ||
80 | fl->fl_ip_sport = t->src.u.tcp.port; | ||
81 | } | ||
82 | } | ||
83 | #endif | ||
84 | |||
85 | static unsigned int | ||
86 | ip_nat_fn(unsigned int hooknum, | ||
87 | struct sk_buff **pskb, | ||
88 | const struct net_device *in, | ||
89 | const struct net_device *out, | ||
90 | int (*okfn)(struct sk_buff *)) | ||
91 | { | ||
92 | struct ip_conntrack *ct; | ||
93 | enum ip_conntrack_info ctinfo; | ||
94 | struct ip_nat_info *info; | ||
95 | /* maniptype == SRC for postrouting. */ | ||
96 | enum ip_nat_manip_type maniptype = HOOK2MANIP(hooknum); | ||
97 | |||
98 | /* We never see fragments: conntrack defrags on pre-routing | ||
99 | and local-out, and ip_nat_out protects post-routing. */ | ||
100 | IP_NF_ASSERT(!(ip_hdr(*pskb)->frag_off | ||
101 | & htons(IP_MF|IP_OFFSET))); | ||
102 | |||
103 | ct = ip_conntrack_get(*pskb, &ctinfo); | ||
104 | /* Can't track? It's not due to stress, or conntrack would | ||
105 | have dropped it. Hence it's the user's responsibilty to | ||
106 | packet filter it out, or implement conntrack/NAT for that | ||
107 | protocol. 8) --RR */ | ||
108 | if (!ct) { | ||
109 | /* Exception: ICMP redirect to new connection (not in | ||
110 | hash table yet). We must not let this through, in | ||
111 | case we're doing NAT to the same network. */ | ||
112 | if (ip_hdr(*pskb)->protocol == IPPROTO_ICMP) { | ||
113 | struct icmphdr _hdr, *hp; | ||
114 | |||
115 | hp = skb_header_pointer(*pskb, ip_hdrlen(*pskb), | ||
116 | sizeof(_hdr), &_hdr); | ||
117 | if (hp != NULL && | ||
118 | hp->type == ICMP_REDIRECT) | ||
119 | return NF_DROP; | ||
120 | } | ||
121 | return NF_ACCEPT; | ||
122 | } | ||
123 | |||
124 | /* Don't try to NAT if this packet is not conntracked */ | ||
125 | if (ct == &ip_conntrack_untracked) | ||
126 | return NF_ACCEPT; | ||
127 | |||
128 | switch (ctinfo) { | ||
129 | case IP_CT_RELATED: | ||
130 | case IP_CT_RELATED+IP_CT_IS_REPLY: | ||
131 | if (ip_hdr(*pskb)->protocol == IPPROTO_ICMP) { | ||
132 | if (!ip_nat_icmp_reply_translation(ct, ctinfo, | ||
133 | hooknum, pskb)) | ||
134 | return NF_DROP; | ||
135 | else | ||
136 | return NF_ACCEPT; | ||
137 | } | ||
138 | /* Fall thru... (Only ICMPs can be IP_CT_IS_REPLY) */ | ||
139 | case IP_CT_NEW: | ||
140 | info = &ct->nat.info; | ||
141 | |||
142 | /* Seen it before? This can happen for loopback, retrans, | ||
143 | or local packets.. */ | ||
144 | if (!ip_nat_initialized(ct, maniptype)) { | ||
145 | unsigned int ret; | ||
146 | |||
147 | if (unlikely(is_confirmed(ct))) | ||
148 | /* NAT module was loaded late */ | ||
149 | ret = alloc_null_binding_confirmed(ct, info, | ||
150 | hooknum); | ||
151 | else if (hooknum == NF_IP_LOCAL_IN) | ||
152 | /* LOCAL_IN hook doesn't have a chain! */ | ||
153 | ret = alloc_null_binding(ct, info, hooknum); | ||
154 | else | ||
155 | ret = ip_nat_rule_find(pskb, hooknum, | ||
156 | in, out, ct, | ||
157 | info); | ||
158 | |||
159 | if (ret != NF_ACCEPT) { | ||
160 | return ret; | ||
161 | } | ||
162 | } else | ||
163 | DEBUGP("Already setup manip %s for ct %p\n", | ||
164 | maniptype == IP_NAT_MANIP_SRC ? "SRC" : "DST", | ||
165 | ct); | ||
166 | break; | ||
167 | |||
168 | default: | ||
169 | /* ESTABLISHED */ | ||
170 | IP_NF_ASSERT(ctinfo == IP_CT_ESTABLISHED | ||
171 | || ctinfo == (IP_CT_ESTABLISHED+IP_CT_IS_REPLY)); | ||
172 | info = &ct->nat.info; | ||
173 | } | ||
174 | |||
175 | IP_NF_ASSERT(info); | ||
176 | return ip_nat_packet(ct, ctinfo, hooknum, pskb); | ||
177 | } | ||
178 | |||
179 | static unsigned int | ||
180 | ip_nat_in(unsigned int hooknum, | ||
181 | struct sk_buff **pskb, | ||
182 | const struct net_device *in, | ||
183 | const struct net_device *out, | ||
184 | int (*okfn)(struct sk_buff *)) | ||
185 | { | ||
186 | unsigned int ret; | ||
187 | __be32 daddr = ip_hdr(*pskb)->daddr; | ||
188 | |||
189 | ret = ip_nat_fn(hooknum, pskb, in, out, okfn); | ||
190 | if (ret != NF_DROP && ret != NF_STOLEN | ||
191 | && daddr != ip_hdr(*pskb)->daddr) { | ||
192 | dst_release((*pskb)->dst); | ||
193 | (*pskb)->dst = NULL; | ||
194 | } | ||
195 | return ret; | ||
196 | } | ||
197 | |||
198 | static unsigned int | ||
199 | ip_nat_out(unsigned int hooknum, | ||
200 | struct sk_buff **pskb, | ||
201 | const struct net_device *in, | ||
202 | const struct net_device *out, | ||
203 | int (*okfn)(struct sk_buff *)) | ||
204 | { | ||
205 | #ifdef CONFIG_XFRM | ||
206 | struct ip_conntrack *ct; | ||
207 | enum ip_conntrack_info ctinfo; | ||
208 | #endif | ||
209 | unsigned int ret; | ||
210 | |||
211 | /* root is playing with raw sockets. */ | ||
212 | if ((*pskb)->len < sizeof(struct iphdr) | ||
213 | || ip_hdrlen(*pskb) < sizeof(struct iphdr)) | ||
214 | return NF_ACCEPT; | ||
215 | |||
216 | ret = ip_nat_fn(hooknum, pskb, in, out, okfn); | ||
217 | #ifdef CONFIG_XFRM | ||
218 | if (ret != NF_DROP && ret != NF_STOLEN | ||
219 | && (ct = ip_conntrack_get(*pskb, &ctinfo)) != NULL) { | ||
220 | enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); | ||
221 | |||
222 | if (ct->tuplehash[dir].tuple.src.ip != | ||
223 | ct->tuplehash[!dir].tuple.dst.ip | ||
224 | || ct->tuplehash[dir].tuple.src.u.all != | ||
225 | ct->tuplehash[!dir].tuple.dst.u.all | ||
226 | ) | ||
227 | return ip_xfrm_me_harder(pskb) == 0 ? ret : NF_DROP; | ||
228 | } | ||
229 | #endif | ||
230 | return ret; | ||
231 | } | ||
232 | |||
233 | static unsigned int | ||
234 | ip_nat_local_fn(unsigned int hooknum, | ||
235 | struct sk_buff **pskb, | ||
236 | const struct net_device *in, | ||
237 | const struct net_device *out, | ||
238 | int (*okfn)(struct sk_buff *)) | ||
239 | { | ||
240 | struct ip_conntrack *ct; | ||
241 | enum ip_conntrack_info ctinfo; | ||
242 | unsigned int ret; | ||
243 | |||
244 | /* root is playing with raw sockets. */ | ||
245 | if ((*pskb)->len < sizeof(struct iphdr) | ||
246 | || ip_hdrlen(*pskb) < sizeof(struct iphdr)) | ||
247 | return NF_ACCEPT; | ||
248 | |||
249 | ret = ip_nat_fn(hooknum, pskb, in, out, okfn); | ||
250 | if (ret != NF_DROP && ret != NF_STOLEN | ||
251 | && (ct = ip_conntrack_get(*pskb, &ctinfo)) != NULL) { | ||
252 | enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); | ||
253 | |||
254 | if (ct->tuplehash[dir].tuple.dst.ip != | ||
255 | ct->tuplehash[!dir].tuple.src.ip) { | ||
256 | if (ip_route_me_harder(pskb, RTN_UNSPEC)) | ||
257 | ret = NF_DROP; | ||
258 | } | ||
259 | #ifdef CONFIG_XFRM | ||
260 | else if (ct->tuplehash[dir].tuple.dst.u.all != | ||
261 | ct->tuplehash[!dir].tuple.src.u.all) | ||
262 | if (ip_xfrm_me_harder(pskb)) | ||
263 | ret = NF_DROP; | ||
264 | #endif | ||
265 | |||
266 | } | ||
267 | return ret; | ||
268 | } | ||
269 | |||
270 | static unsigned int | ||
271 | ip_nat_adjust(unsigned int hooknum, | ||
272 | struct sk_buff **pskb, | ||
273 | const struct net_device *in, | ||
274 | const struct net_device *out, | ||
275 | int (*okfn)(struct sk_buff *)) | ||
276 | { | ||
277 | struct ip_conntrack *ct; | ||
278 | enum ip_conntrack_info ctinfo; | ||
279 | |||
280 | ct = ip_conntrack_get(*pskb, &ctinfo); | ||
281 | if (ct && test_bit(IPS_SEQ_ADJUST_BIT, &ct->status)) { | ||
282 | DEBUGP("ip_nat_standalone: adjusting sequence number\n"); | ||
283 | if (!ip_nat_seq_adjust(pskb, ct, ctinfo)) | ||
284 | return NF_DROP; | ||
285 | } | ||
286 | return NF_ACCEPT; | ||
287 | } | ||
288 | |||
289 | /* We must be after connection tracking and before packet filtering. */ | ||
290 | |||
291 | static struct nf_hook_ops ip_nat_ops[] = { | ||
292 | /* Before packet filtering, change destination */ | ||
293 | { | ||
294 | .hook = ip_nat_in, | ||
295 | .owner = THIS_MODULE, | ||
296 | .pf = PF_INET, | ||
297 | .hooknum = NF_IP_PRE_ROUTING, | ||
298 | .priority = NF_IP_PRI_NAT_DST, | ||
299 | }, | ||
300 | /* After packet filtering, change source */ | ||
301 | { | ||
302 | .hook = ip_nat_out, | ||
303 | .owner = THIS_MODULE, | ||
304 | .pf = PF_INET, | ||
305 | .hooknum = NF_IP_POST_ROUTING, | ||
306 | .priority = NF_IP_PRI_NAT_SRC, | ||
307 | }, | ||
308 | /* After conntrack, adjust sequence number */ | ||
309 | { | ||
310 | .hook = ip_nat_adjust, | ||
311 | .owner = THIS_MODULE, | ||
312 | .pf = PF_INET, | ||
313 | .hooknum = NF_IP_POST_ROUTING, | ||
314 | .priority = NF_IP_PRI_NAT_SEQ_ADJUST, | ||
315 | }, | ||
316 | /* Before packet filtering, change destination */ | ||
317 | { | ||
318 | .hook = ip_nat_local_fn, | ||
319 | .owner = THIS_MODULE, | ||
320 | .pf = PF_INET, | ||
321 | .hooknum = NF_IP_LOCAL_OUT, | ||
322 | .priority = NF_IP_PRI_NAT_DST, | ||
323 | }, | ||
324 | /* After packet filtering, change source */ | ||
325 | { | ||
326 | .hook = ip_nat_fn, | ||
327 | .owner = THIS_MODULE, | ||
328 | .pf = PF_INET, | ||
329 | .hooknum = NF_IP_LOCAL_IN, | ||
330 | .priority = NF_IP_PRI_NAT_SRC, | ||
331 | }, | ||
332 | /* After conntrack, adjust sequence number */ | ||
333 | { | ||
334 | .hook = ip_nat_adjust, | ||
335 | .owner = THIS_MODULE, | ||
336 | .pf = PF_INET, | ||
337 | .hooknum = NF_IP_LOCAL_IN, | ||
338 | .priority = NF_IP_PRI_NAT_SEQ_ADJUST, | ||
339 | }, | ||
340 | }; | ||
341 | |||
342 | static int __init ip_nat_standalone_init(void) | ||
343 | { | ||
344 | int ret = 0; | ||
345 | |||
346 | need_conntrack(); | ||
347 | |||
348 | #ifdef CONFIG_XFRM | ||
349 | BUG_ON(ip_nat_decode_session != NULL); | ||
350 | ip_nat_decode_session = nat_decode_session; | ||
351 | #endif | ||
352 | ret = ip_nat_rule_init(); | ||
353 | if (ret < 0) { | ||
354 | printk("ip_nat_init: can't setup rules.\n"); | ||
355 | goto cleanup_decode_session; | ||
356 | } | ||
357 | ret = nf_register_hooks(ip_nat_ops, ARRAY_SIZE(ip_nat_ops)); | ||
358 | if (ret < 0) { | ||
359 | printk("ip_nat_init: can't register hooks.\n"); | ||
360 | goto cleanup_rule_init; | ||
361 | } | ||
362 | return ret; | ||
363 | |||
364 | cleanup_rule_init: | ||
365 | ip_nat_rule_cleanup(); | ||
366 | cleanup_decode_session: | ||
367 | #ifdef CONFIG_XFRM | ||
368 | ip_nat_decode_session = NULL; | ||
369 | synchronize_net(); | ||
370 | #endif | ||
371 | return ret; | ||
372 | } | ||
373 | |||
374 | static void __exit ip_nat_standalone_fini(void) | ||
375 | { | ||
376 | nf_unregister_hooks(ip_nat_ops, ARRAY_SIZE(ip_nat_ops)); | ||
377 | ip_nat_rule_cleanup(); | ||
378 | #ifdef CONFIG_XFRM | ||
379 | ip_nat_decode_session = NULL; | ||
380 | synchronize_net(); | ||
381 | #endif | ||
382 | } | ||
383 | |||
384 | module_init(ip_nat_standalone_init); | ||
385 | module_exit(ip_nat_standalone_fini); | ||
386 | |||
387 | MODULE_LICENSE("GPL"); | ||
diff --git a/net/ipv4/netfilter/ip_nat_tftp.c b/net/ipv4/netfilter/ip_nat_tftp.c deleted file mode 100644 index 604793536fc1..000000000000 --- a/net/ipv4/netfilter/ip_nat_tftp.c +++ /dev/null | |||
@@ -1,70 +0,0 @@ | |||
1 | /* (C) 2001-2002 Magnus Boden <mb@ozaba.mine.nu> | ||
2 | * | ||
3 | * This program is free software; you can redistribute it and/or modify | ||
4 | * it under the terms of the GNU General Public License version 2 as | ||
5 | * published by the Free Software Foundation. | ||
6 | * | ||
7 | * Version: 0.0.7 | ||
8 | * | ||
9 | * Thu 21 Mar 2002 Harald Welte <laforge@gnumonks.org> | ||
10 | * - Port to newnat API | ||
11 | * | ||
12 | * This module currently supports DNAT: | ||
13 | * iptables -t nat -A PREROUTING -d x.x.x.x -j DNAT --to-dest x.x.x.y | ||
14 | * | ||
15 | * and SNAT: | ||
16 | * iptables -t nat -A POSTROUTING { -j MASQUERADE , -j SNAT --to-source x.x.x.x } | ||
17 | * | ||
18 | * It has not been tested with | ||
19 | * -j SNAT --to-source x.x.x.x-x.x.x.y since I only have one external ip | ||
20 | * If you do test this please let me know if it works or not. | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | #include <linux/module.h> | ||
25 | #include <linux/netfilter_ipv4.h> | ||
26 | #include <linux/ip.h> | ||
27 | #include <linux/udp.h> | ||
28 | |||
29 | #include <linux/netfilter.h> | ||
30 | #include <linux/netfilter_ipv4/ip_tables.h> | ||
31 | #include <linux/netfilter_ipv4/ip_conntrack_helper.h> | ||
32 | #include <linux/netfilter_ipv4/ip_conntrack_tftp.h> | ||
33 | #include <linux/netfilter_ipv4/ip_nat_helper.h> | ||
34 | #include <linux/netfilter_ipv4/ip_nat_rule.h> | ||
35 | #include <linux/moduleparam.h> | ||
36 | |||
37 | MODULE_AUTHOR("Magnus Boden <mb@ozaba.mine.nu>"); | ||
38 | MODULE_DESCRIPTION("tftp NAT helper"); | ||
39 | MODULE_LICENSE("GPL"); | ||
40 | |||
41 | static unsigned int help(struct sk_buff **pskb, | ||
42 | enum ip_conntrack_info ctinfo, | ||
43 | struct ip_conntrack_expect *exp) | ||
44 | { | ||
45 | struct ip_conntrack *ct = exp->master; | ||
46 | |||
47 | exp->saved_proto.udp.port | ||
48 | = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.udp.port; | ||
49 | exp->dir = IP_CT_DIR_REPLY; | ||
50 | exp->expectfn = ip_nat_follow_master; | ||
51 | if (ip_conntrack_expect_related(exp) != 0) | ||
52 | return NF_DROP; | ||
53 | return NF_ACCEPT; | ||
54 | } | ||
55 | |||
56 | static void __exit ip_nat_tftp_fini(void) | ||
57 | { | ||
58 | rcu_assign_pointer(ip_nat_tftp_hook, NULL); | ||
59 | synchronize_rcu(); | ||
60 | } | ||
61 | |||
62 | static int __init ip_nat_tftp_init(void) | ||
63 | { | ||
64 | BUG_ON(rcu_dereference(ip_nat_tftp_hook)); | ||
65 | rcu_assign_pointer(ip_nat_tftp_hook, help); | ||
66 | return 0; | ||
67 | } | ||
68 | |||
69 | module_init(ip_nat_tftp_init); | ||
70 | module_exit(ip_nat_tftp_fini); | ||
diff --git a/net/ipv4/netfilter/ipt_CLUSTERIP.c b/net/ipv4/netfilter/ipt_CLUSTERIP.c index d3b16817a991..40e273421398 100644 --- a/net/ipv4/netfilter/ipt_CLUSTERIP.c +++ b/net/ipv4/netfilter/ipt_CLUSTERIP.c | |||
@@ -21,15 +21,12 @@ | |||
21 | #include <linux/if_arp.h> | 21 | #include <linux/if_arp.h> |
22 | #include <linux/proc_fs.h> | 22 | #include <linux/proc_fs.h> |
23 | #include <linux/seq_file.h> | 23 | #include <linux/seq_file.h> |
24 | |||
25 | #include <net/checksum.h> | ||
26 | |||
27 | #include <linux/netfilter_arp.h> | 24 | #include <linux/netfilter_arp.h> |
28 | |||
29 | #include <linux/netfilter/x_tables.h> | 25 | #include <linux/netfilter/x_tables.h> |
30 | #include <linux/netfilter_ipv4/ip_tables.h> | 26 | #include <linux/netfilter_ipv4/ip_tables.h> |
31 | #include <linux/netfilter_ipv4/ipt_CLUSTERIP.h> | 27 | #include <linux/netfilter_ipv4/ipt_CLUSTERIP.h> |
32 | #include <net/netfilter/nf_conntrack_compat.h> | 28 | #include <net/netfilter/nf_conntrack.h> |
29 | #include <net/checksum.h> | ||
33 | 30 | ||
34 | #define CLUSTERIP_VERSION "0.8" | 31 | #define CLUSTERIP_VERSION "0.8" |
35 | 32 | ||
@@ -310,15 +307,16 @@ target(struct sk_buff **pskb, | |||
310 | const void *targinfo) | 307 | const void *targinfo) |
311 | { | 308 | { |
312 | const struct ipt_clusterip_tgt_info *cipinfo = targinfo; | 309 | const struct ipt_clusterip_tgt_info *cipinfo = targinfo; |
310 | struct nf_conn *ct; | ||
313 | enum ip_conntrack_info ctinfo; | 311 | enum ip_conntrack_info ctinfo; |
314 | u_int32_t *mark, hash; | 312 | u_int32_t hash; |
315 | 313 | ||
316 | /* don't need to clusterip_config_get() here, since refcount | 314 | /* don't need to clusterip_config_get() here, since refcount |
317 | * is only decremented by destroy() - and ip_tables guarantees | 315 | * is only decremented by destroy() - and ip_tables guarantees |
318 | * that the ->target() function isn't called after ->destroy() */ | 316 | * that the ->target() function isn't called after ->destroy() */ |
319 | 317 | ||
320 | mark = nf_ct_get_mark((*pskb), &ctinfo); | 318 | ct = nf_ct_get(*pskb, &ctinfo); |
321 | if (mark == NULL) { | 319 | if (ct == NULL) { |
322 | printk(KERN_ERR "CLUSTERIP: no conntrack!\n"); | 320 | printk(KERN_ERR "CLUSTERIP: no conntrack!\n"); |
323 | /* FIXME: need to drop invalid ones, since replies | 321 | /* FIXME: need to drop invalid ones, since replies |
324 | * to outgoing connections of other nodes will be | 322 | * to outgoing connections of other nodes will be |
@@ -341,7 +339,7 @@ target(struct sk_buff **pskb, | |||
341 | 339 | ||
342 | switch (ctinfo) { | 340 | switch (ctinfo) { |
343 | case IP_CT_NEW: | 341 | case IP_CT_NEW: |
344 | *mark = hash; | 342 | ct->mark = hash; |
345 | break; | 343 | break; |
346 | case IP_CT_RELATED: | 344 | case IP_CT_RELATED: |
347 | case IP_CT_RELATED+IP_CT_IS_REPLY: | 345 | case IP_CT_RELATED+IP_CT_IS_REPLY: |
@@ -358,7 +356,7 @@ target(struct sk_buff **pskb, | |||
358 | #ifdef DEBUG_CLUSTERP | 356 | #ifdef DEBUG_CLUSTERP |
359 | DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); | 357 | DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); |
360 | #endif | 358 | #endif |
361 | DEBUGP("hash=%u ct_hash=%u ", hash, *mark); | 359 | DEBUGP("hash=%u ct_hash=%u ", hash, ct->mark); |
362 | if (!clusterip_responsible(cipinfo->config, hash)) { | 360 | if (!clusterip_responsible(cipinfo->config, hash)) { |
363 | DEBUGP("not responsible\n"); | 361 | DEBUGP("not responsible\n"); |
364 | return NF_DROP; | 362 | return NF_DROP; |
diff --git a/net/ipv4/netfilter/ipt_MASQUERADE.c b/net/ipv4/netfilter/ipt_MASQUERADE.c index b5955f3a3f8f..d4f2d7775330 100644 --- a/net/ipv4/netfilter/ipt_MASQUERADE.c +++ b/net/ipv4/netfilter/ipt_MASQUERADE.c | |||
@@ -19,12 +19,8 @@ | |||
19 | #include <net/ip.h> | 19 | #include <net/ip.h> |
20 | #include <net/checksum.h> | 20 | #include <net/checksum.h> |
21 | #include <net/route.h> | 21 | #include <net/route.h> |
22 | #include <linux/netfilter_ipv4.h> | ||
23 | #ifdef CONFIG_NF_NAT_NEEDED | ||
24 | #include <net/netfilter/nf_nat_rule.h> | 22 | #include <net/netfilter/nf_nat_rule.h> |
25 | #else | 23 | #include <linux/netfilter_ipv4.h> |
26 | #include <linux/netfilter_ipv4/ip_nat_rule.h> | ||
27 | #endif | ||
28 | #include <linux/netfilter/x_tables.h> | 24 | #include <linux/netfilter/x_tables.h> |
29 | 25 | ||
30 | MODULE_LICENSE("GPL"); | 26 | MODULE_LICENSE("GPL"); |
@@ -48,7 +44,7 @@ masquerade_check(const char *tablename, | |||
48 | void *targinfo, | 44 | void *targinfo, |
49 | unsigned int hook_mask) | 45 | unsigned int hook_mask) |
50 | { | 46 | { |
51 | const struct ip_nat_multi_range_compat *mr = targinfo; | 47 | const struct nf_nat_multi_range_compat *mr = targinfo; |
52 | 48 | ||
53 | if (mr->range[0].flags & IP_NAT_RANGE_MAP_IPS) { | 49 | if (mr->range[0].flags & IP_NAT_RANGE_MAP_IPS) { |
54 | DEBUGP("masquerade_check: bad MAP_IPS.\n"); | 50 | DEBUGP("masquerade_check: bad MAP_IPS.\n"); |
@@ -69,33 +65,26 @@ masquerade_target(struct sk_buff **pskb, | |||
69 | const struct xt_target *target, | 65 | const struct xt_target *target, |
70 | const void *targinfo) | 66 | const void *targinfo) |
71 | { | 67 | { |
72 | #ifdef CONFIG_NF_NAT_NEEDED | 68 | struct nf_conn *ct; |
73 | struct nf_conn_nat *nat; | 69 | struct nf_conn_nat *nat; |
74 | #endif | ||
75 | struct ip_conntrack *ct; | ||
76 | enum ip_conntrack_info ctinfo; | 70 | enum ip_conntrack_info ctinfo; |
77 | struct ip_nat_range newrange; | 71 | struct nf_nat_range newrange; |
78 | const struct ip_nat_multi_range_compat *mr; | 72 | const struct nf_nat_multi_range_compat *mr; |
79 | struct rtable *rt; | 73 | struct rtable *rt; |
80 | __be32 newsrc; | 74 | __be32 newsrc; |
81 | 75 | ||
82 | IP_NF_ASSERT(hooknum == NF_IP_POST_ROUTING); | 76 | NF_CT_ASSERT(hooknum == NF_IP_POST_ROUTING); |
83 | 77 | ||
84 | ct = ip_conntrack_get(*pskb, &ctinfo); | 78 | ct = nf_ct_get(*pskb, &ctinfo); |
85 | #ifdef CONFIG_NF_NAT_NEEDED | ||
86 | nat = nfct_nat(ct); | 79 | nat = nfct_nat(ct); |
87 | #endif | 80 | |
88 | IP_NF_ASSERT(ct && (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED | 81 | NF_CT_ASSERT(ct && (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED |
89 | || ctinfo == IP_CT_RELATED + IP_CT_IS_REPLY)); | 82 | || ctinfo == IP_CT_RELATED + IP_CT_IS_REPLY)); |
90 | 83 | ||
91 | /* Source address is 0.0.0.0 - locally generated packet that is | 84 | /* Source address is 0.0.0.0 - locally generated packet that is |
92 | * probably not supposed to be masqueraded. | 85 | * probably not supposed to be masqueraded. |
93 | */ | 86 | */ |
94 | #ifdef CONFIG_NF_NAT_NEEDED | ||
95 | if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip == 0) | 87 | if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip == 0) |
96 | #else | ||
97 | if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip == 0) | ||
98 | #endif | ||
99 | return NF_ACCEPT; | 88 | return NF_ACCEPT; |
100 | 89 | ||
101 | mr = targinfo; | 90 | mr = targinfo; |
@@ -107,40 +96,30 @@ masquerade_target(struct sk_buff **pskb, | |||
107 | } | 96 | } |
108 | 97 | ||
109 | write_lock_bh(&masq_lock); | 98 | write_lock_bh(&masq_lock); |
110 | #ifdef CONFIG_NF_NAT_NEEDED | ||
111 | nat->masq_index = out->ifindex; | 99 | nat->masq_index = out->ifindex; |
112 | #else | ||
113 | ct->nat.masq_index = out->ifindex; | ||
114 | #endif | ||
115 | write_unlock_bh(&masq_lock); | 100 | write_unlock_bh(&masq_lock); |
116 | 101 | ||
117 | /* Transfer from original range. */ | 102 | /* Transfer from original range. */ |
118 | newrange = ((struct ip_nat_range) | 103 | newrange = ((struct nf_nat_range) |
119 | { mr->range[0].flags | IP_NAT_RANGE_MAP_IPS, | 104 | { mr->range[0].flags | IP_NAT_RANGE_MAP_IPS, |
120 | newsrc, newsrc, | 105 | newsrc, newsrc, |
121 | mr->range[0].min, mr->range[0].max }); | 106 | mr->range[0].min, mr->range[0].max }); |
122 | 107 | ||
123 | /* Hand modified range to generic setup. */ | 108 | /* Hand modified range to generic setup. */ |
124 | return ip_nat_setup_info(ct, &newrange, hooknum); | 109 | return nf_nat_setup_info(ct, &newrange, hooknum); |
125 | } | 110 | } |
126 | 111 | ||
127 | static inline int | 112 | static inline int |
128 | device_cmp(struct ip_conntrack *i, void *ifindex) | 113 | device_cmp(struct nf_conn *i, void *ifindex) |
129 | { | 114 | { |
130 | int ret; | ||
131 | #ifdef CONFIG_NF_NAT_NEEDED | ||
132 | struct nf_conn_nat *nat = nfct_nat(i); | 115 | struct nf_conn_nat *nat = nfct_nat(i); |
116 | int ret; | ||
133 | 117 | ||
134 | if (!nat) | 118 | if (!nat) |
135 | return 0; | 119 | return 0; |
136 | #endif | ||
137 | 120 | ||
138 | read_lock_bh(&masq_lock); | 121 | read_lock_bh(&masq_lock); |
139 | #ifdef CONFIG_NF_NAT_NEEDED | ||
140 | ret = (nat->masq_index == (int)(long)ifindex); | 122 | ret = (nat->masq_index == (int)(long)ifindex); |
141 | #else | ||
142 | ret = (i->nat.masq_index == (int)(long)ifindex); | ||
143 | #endif | ||
144 | read_unlock_bh(&masq_lock); | 123 | read_unlock_bh(&masq_lock); |
145 | 124 | ||
146 | return ret; | 125 | return ret; |
@@ -156,9 +135,9 @@ static int masq_device_event(struct notifier_block *this, | |||
156 | /* Device was downed. Search entire table for | 135 | /* Device was downed. Search entire table for |
157 | conntracks which were associated with that device, | 136 | conntracks which were associated with that device, |
158 | and forget them. */ | 137 | and forget them. */ |
159 | IP_NF_ASSERT(dev->ifindex != 0); | 138 | NF_CT_ASSERT(dev->ifindex != 0); |
160 | 139 | ||
161 | ip_ct_iterate_cleanup(device_cmp, (void *)(long)dev->ifindex); | 140 | nf_ct_iterate_cleanup(device_cmp, (void *)(long)dev->ifindex); |
162 | } | 141 | } |
163 | 142 | ||
164 | return NOTIFY_DONE; | 143 | return NOTIFY_DONE; |
@@ -174,9 +153,9 @@ static int masq_inet_event(struct notifier_block *this, | |||
174 | /* IP address was deleted. Search entire table for | 153 | /* IP address was deleted. Search entire table for |
175 | conntracks which were associated with that device, | 154 | conntracks which were associated with that device, |
176 | and forget them. */ | 155 | and forget them. */ |
177 | IP_NF_ASSERT(dev->ifindex != 0); | 156 | NF_CT_ASSERT(dev->ifindex != 0); |
178 | 157 | ||
179 | ip_ct_iterate_cleanup(device_cmp, (void *)(long)dev->ifindex); | 158 | nf_ct_iterate_cleanup(device_cmp, (void *)(long)dev->ifindex); |
180 | } | 159 | } |
181 | 160 | ||
182 | return NOTIFY_DONE; | 161 | return NOTIFY_DONE; |
@@ -194,7 +173,7 @@ static struct xt_target masquerade = { | |||
194 | .name = "MASQUERADE", | 173 | .name = "MASQUERADE", |
195 | .family = AF_INET, | 174 | .family = AF_INET, |
196 | .target = masquerade_target, | 175 | .target = masquerade_target, |
197 | .targetsize = sizeof(struct ip_nat_multi_range_compat), | 176 | .targetsize = sizeof(struct nf_nat_multi_range_compat), |
198 | .table = "nat", | 177 | .table = "nat", |
199 | .hooks = 1 << NF_IP_POST_ROUTING, | 178 | .hooks = 1 << NF_IP_POST_ROUTING, |
200 | .checkentry = masquerade_check, | 179 | .checkentry = masquerade_check, |
diff --git a/net/ipv4/netfilter/ipt_NETMAP.c b/net/ipv4/netfilter/ipt_NETMAP.c index d03f165722da..068c69bce30e 100644 --- a/net/ipv4/netfilter/ipt_NETMAP.c +++ b/net/ipv4/netfilter/ipt_NETMAP.c | |||
@@ -16,11 +16,7 @@ | |||
16 | #include <linux/netfilter.h> | 16 | #include <linux/netfilter.h> |
17 | #include <linux/netfilter_ipv4.h> | 17 | #include <linux/netfilter_ipv4.h> |
18 | #include <linux/netfilter/x_tables.h> | 18 | #include <linux/netfilter/x_tables.h> |
19 | #ifdef CONFIG_NF_NAT_NEEDED | ||
20 | #include <net/netfilter/nf_nat_rule.h> | 19 | #include <net/netfilter/nf_nat_rule.h> |
21 | #else | ||
22 | #include <linux/netfilter_ipv4/ip_nat_rule.h> | ||
23 | #endif | ||
24 | 20 | ||
25 | #define MODULENAME "NETMAP" | 21 | #define MODULENAME "NETMAP" |
26 | MODULE_LICENSE("GPL"); | 22 | MODULE_LICENSE("GPL"); |
@@ -40,7 +36,7 @@ check(const char *tablename, | |||
40 | void *targinfo, | 36 | void *targinfo, |
41 | unsigned int hook_mask) | 37 | unsigned int hook_mask) |
42 | { | 38 | { |
43 | const struct ip_nat_multi_range_compat *mr = targinfo; | 39 | const struct nf_nat_multi_range_compat *mr = targinfo; |
44 | 40 | ||
45 | if (!(mr->range[0].flags & IP_NAT_RANGE_MAP_IPS)) { | 41 | if (!(mr->range[0].flags & IP_NAT_RANGE_MAP_IPS)) { |
46 | DEBUGP(MODULENAME":check: bad MAP_IPS.\n"); | 42 | DEBUGP(MODULENAME":check: bad MAP_IPS.\n"); |
@@ -61,16 +57,16 @@ target(struct sk_buff **pskb, | |||
61 | const struct xt_target *target, | 57 | const struct xt_target *target, |
62 | const void *targinfo) | 58 | const void *targinfo) |
63 | { | 59 | { |
64 | struct ip_conntrack *ct; | 60 | struct nf_conn *ct; |
65 | enum ip_conntrack_info ctinfo; | 61 | enum ip_conntrack_info ctinfo; |
66 | __be32 new_ip, netmask; | 62 | __be32 new_ip, netmask; |
67 | const struct ip_nat_multi_range_compat *mr = targinfo; | 63 | const struct nf_nat_multi_range_compat *mr = targinfo; |
68 | struct ip_nat_range newrange; | 64 | struct nf_nat_range newrange; |
69 | 65 | ||
70 | IP_NF_ASSERT(hooknum == NF_IP_PRE_ROUTING | 66 | NF_CT_ASSERT(hooknum == NF_IP_PRE_ROUTING |
71 | || hooknum == NF_IP_POST_ROUTING | 67 | || hooknum == NF_IP_POST_ROUTING |
72 | || hooknum == NF_IP_LOCAL_OUT); | 68 | || hooknum == NF_IP_LOCAL_OUT); |
73 | ct = ip_conntrack_get(*pskb, &ctinfo); | 69 | ct = nf_ct_get(*pskb, &ctinfo); |
74 | 70 | ||
75 | netmask = ~(mr->range[0].min_ip ^ mr->range[0].max_ip); | 71 | netmask = ~(mr->range[0].min_ip ^ mr->range[0].max_ip); |
76 | 72 | ||
@@ -80,20 +76,20 @@ target(struct sk_buff **pskb, | |||
80 | new_ip = ip_hdr(*pskb)->saddr & ~netmask; | 76 | new_ip = ip_hdr(*pskb)->saddr & ~netmask; |
81 | new_ip |= mr->range[0].min_ip & netmask; | 77 | new_ip |= mr->range[0].min_ip & netmask; |
82 | 78 | ||
83 | newrange = ((struct ip_nat_range) | 79 | newrange = ((struct nf_nat_range) |
84 | { mr->range[0].flags | IP_NAT_RANGE_MAP_IPS, | 80 | { mr->range[0].flags | IP_NAT_RANGE_MAP_IPS, |
85 | new_ip, new_ip, | 81 | new_ip, new_ip, |
86 | mr->range[0].min, mr->range[0].max }); | 82 | mr->range[0].min, mr->range[0].max }); |
87 | 83 | ||
88 | /* Hand modified range to generic setup. */ | 84 | /* Hand modified range to generic setup. */ |
89 | return ip_nat_setup_info(ct, &newrange, hooknum); | 85 | return nf_nat_setup_info(ct, &newrange, hooknum); |
90 | } | 86 | } |
91 | 87 | ||
92 | static struct xt_target target_module = { | 88 | static struct xt_target target_module = { |
93 | .name = MODULENAME, | 89 | .name = MODULENAME, |
94 | .family = AF_INET, | 90 | .family = AF_INET, |
95 | .target = target, | 91 | .target = target, |
96 | .targetsize = sizeof(struct ip_nat_multi_range_compat), | 92 | .targetsize = sizeof(struct nf_nat_multi_range_compat), |
97 | .table = "nat", | 93 | .table = "nat", |
98 | .hooks = (1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_POST_ROUTING) | | 94 | .hooks = (1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_POST_ROUTING) | |
99 | (1 << NF_IP_LOCAL_OUT), | 95 | (1 << NF_IP_LOCAL_OUT), |
diff --git a/net/ipv4/netfilter/ipt_REDIRECT.c b/net/ipv4/netfilter/ipt_REDIRECT.c index c2b6b80670f8..68cc76a198eb 100644 --- a/net/ipv4/netfilter/ipt_REDIRECT.c +++ b/net/ipv4/netfilter/ipt_REDIRECT.c | |||
@@ -19,11 +19,7 @@ | |||
19 | #include <net/checksum.h> | 19 | #include <net/checksum.h> |
20 | #include <linux/netfilter_ipv4.h> | 20 | #include <linux/netfilter_ipv4.h> |
21 | #include <linux/netfilter/x_tables.h> | 21 | #include <linux/netfilter/x_tables.h> |
22 | #ifdef CONFIG_NF_NAT_NEEDED | ||
23 | #include <net/netfilter/nf_nat_rule.h> | 22 | #include <net/netfilter/nf_nat_rule.h> |
24 | #else | ||
25 | #include <linux/netfilter_ipv4/ip_nat_rule.h> | ||
26 | #endif | ||
27 | 23 | ||
28 | MODULE_LICENSE("GPL"); | 24 | MODULE_LICENSE("GPL"); |
29 | MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>"); | 25 | MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>"); |
@@ -43,7 +39,7 @@ redirect_check(const char *tablename, | |||
43 | void *targinfo, | 39 | void *targinfo, |
44 | unsigned int hook_mask) | 40 | unsigned int hook_mask) |
45 | { | 41 | { |
46 | const struct ip_nat_multi_range_compat *mr = targinfo; | 42 | const struct nf_nat_multi_range_compat *mr = targinfo; |
47 | 43 | ||
48 | if (mr->range[0].flags & IP_NAT_RANGE_MAP_IPS) { | 44 | if (mr->range[0].flags & IP_NAT_RANGE_MAP_IPS) { |
49 | DEBUGP("redirect_check: bad MAP_IPS.\n"); | 45 | DEBUGP("redirect_check: bad MAP_IPS.\n"); |
@@ -64,17 +60,17 @@ redirect_target(struct sk_buff **pskb, | |||
64 | const struct xt_target *target, | 60 | const struct xt_target *target, |
65 | const void *targinfo) | 61 | const void *targinfo) |
66 | { | 62 | { |
67 | struct ip_conntrack *ct; | 63 | struct nf_conn *ct; |
68 | enum ip_conntrack_info ctinfo; | 64 | enum ip_conntrack_info ctinfo; |
69 | __be32 newdst; | 65 | __be32 newdst; |
70 | const struct ip_nat_multi_range_compat *mr = targinfo; | 66 | const struct nf_nat_multi_range_compat *mr = targinfo; |
71 | struct ip_nat_range newrange; | 67 | struct nf_nat_range newrange; |
72 | 68 | ||
73 | IP_NF_ASSERT(hooknum == NF_IP_PRE_ROUTING | 69 | NF_CT_ASSERT(hooknum == NF_IP_PRE_ROUTING |
74 | || hooknum == NF_IP_LOCAL_OUT); | 70 | || hooknum == NF_IP_LOCAL_OUT); |
75 | 71 | ||
76 | ct = ip_conntrack_get(*pskb, &ctinfo); | 72 | ct = nf_ct_get(*pskb, &ctinfo); |
77 | IP_NF_ASSERT(ct && (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED)); | 73 | NF_CT_ASSERT(ct && (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED)); |
78 | 74 | ||
79 | /* Local packets: make them go to loopback */ | 75 | /* Local packets: make them go to loopback */ |
80 | if (hooknum == NF_IP_LOCAL_OUT) | 76 | if (hooknum == NF_IP_LOCAL_OUT) |
@@ -96,20 +92,20 @@ redirect_target(struct sk_buff **pskb, | |||
96 | } | 92 | } |
97 | 93 | ||
98 | /* Transfer from original range. */ | 94 | /* Transfer from original range. */ |
99 | newrange = ((struct ip_nat_range) | 95 | newrange = ((struct nf_nat_range) |
100 | { mr->range[0].flags | IP_NAT_RANGE_MAP_IPS, | 96 | { mr->range[0].flags | IP_NAT_RANGE_MAP_IPS, |
101 | newdst, newdst, | 97 | newdst, newdst, |
102 | mr->range[0].min, mr->range[0].max }); | 98 | mr->range[0].min, mr->range[0].max }); |
103 | 99 | ||
104 | /* Hand modified range to generic setup. */ | 100 | /* Hand modified range to generic setup. */ |
105 | return ip_nat_setup_info(ct, &newrange, hooknum); | 101 | return nf_nat_setup_info(ct, &newrange, hooknum); |
106 | } | 102 | } |
107 | 103 | ||
108 | static struct xt_target redirect_reg = { | 104 | static struct xt_target redirect_reg = { |
109 | .name = "REDIRECT", | 105 | .name = "REDIRECT", |
110 | .family = AF_INET, | 106 | .family = AF_INET, |
111 | .target = redirect_target, | 107 | .target = redirect_target, |
112 | .targetsize = sizeof(struct ip_nat_multi_range_compat), | 108 | .targetsize = sizeof(struct nf_nat_multi_range_compat), |
113 | .table = "nat", | 109 | .table = "nat", |
114 | .hooks = (1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_LOCAL_OUT), | 110 | .hooks = (1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_LOCAL_OUT), |
115 | .checkentry = redirect_check, | 111 | .checkentry = redirect_check, |
diff --git a/net/ipv4/netfilter/ipt_SAME.c b/net/ipv4/netfilter/ipt_SAME.c index bd4404e5c688..fe76ffc0caed 100644 --- a/net/ipv4/netfilter/ipt_SAME.c +++ b/net/ipv4/netfilter/ipt_SAME.c | |||
@@ -35,11 +35,7 @@ | |||
35 | #include <net/checksum.h> | 35 | #include <net/checksum.h> |
36 | #include <linux/netfilter_ipv4.h> | 36 | #include <linux/netfilter_ipv4.h> |
37 | #include <linux/netfilter/x_tables.h> | 37 | #include <linux/netfilter/x_tables.h> |
38 | #ifdef CONFIG_NF_NAT_NEEDED | ||
39 | #include <net/netfilter/nf_nat_rule.h> | 38 | #include <net/netfilter/nf_nat_rule.h> |
40 | #else | ||
41 | #include <linux/netfilter_ipv4/ip_nat_rule.h> | ||
42 | #endif | ||
43 | #include <linux/netfilter_ipv4/ipt_SAME.h> | 39 | #include <linux/netfilter_ipv4/ipt_SAME.h> |
44 | 40 | ||
45 | MODULE_LICENSE("GPL"); | 41 | MODULE_LICENSE("GPL"); |
@@ -138,17 +134,17 @@ same_target(struct sk_buff **pskb, | |||
138 | const struct xt_target *target, | 134 | const struct xt_target *target, |
139 | const void *targinfo) | 135 | const void *targinfo) |
140 | { | 136 | { |
141 | struct ip_conntrack *ct; | 137 | struct nf_conn *ct; |
142 | enum ip_conntrack_info ctinfo; | 138 | enum ip_conntrack_info ctinfo; |
143 | u_int32_t tmpip, aindex; | 139 | u_int32_t tmpip, aindex; |
144 | __be32 new_ip; | 140 | __be32 new_ip; |
145 | const struct ipt_same_info *same = targinfo; | 141 | const struct ipt_same_info *same = targinfo; |
146 | struct ip_nat_range newrange; | 142 | struct nf_nat_range newrange; |
147 | const struct ip_conntrack_tuple *t; | 143 | const struct nf_conntrack_tuple *t; |
148 | 144 | ||
149 | IP_NF_ASSERT(hooknum == NF_IP_PRE_ROUTING || | 145 | NF_CT_ASSERT(hooknum == NF_IP_PRE_ROUTING || |
150 | hooknum == NF_IP_POST_ROUTING); | 146 | hooknum == NF_IP_POST_ROUTING); |
151 | ct = ip_conntrack_get(*pskb, &ctinfo); | 147 | ct = nf_ct_get(*pskb, &ctinfo); |
152 | 148 | ||
153 | t = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple; | 149 | t = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple; |
154 | 150 | ||
@@ -157,17 +153,10 @@ same_target(struct sk_buff **pskb, | |||
157 | Here we calculate the index in same->iparray which | 153 | Here we calculate the index in same->iparray which |
158 | holds the ipaddress we should use */ | 154 | holds the ipaddress we should use */ |
159 | 155 | ||
160 | #ifdef CONFIG_NF_NAT_NEEDED | ||
161 | tmpip = ntohl(t->src.u3.ip); | 156 | tmpip = ntohl(t->src.u3.ip); |
162 | 157 | ||
163 | if (!(same->info & IPT_SAME_NODST)) | 158 | if (!(same->info & IPT_SAME_NODST)) |
164 | tmpip += ntohl(t->dst.u3.ip); | 159 | tmpip += ntohl(t->dst.u3.ip); |
165 | #else | ||
166 | tmpip = ntohl(t->src.ip); | ||
167 | |||
168 | if (!(same->info & IPT_SAME_NODST)) | ||
169 | tmpip += ntohl(t->dst.ip); | ||
170 | #endif | ||
171 | aindex = tmpip % same->ipnum; | 160 | aindex = tmpip % same->ipnum; |
172 | 161 | ||
173 | new_ip = htonl(same->iparray[aindex]); | 162 | new_ip = htonl(same->iparray[aindex]); |
@@ -178,13 +167,13 @@ same_target(struct sk_buff **pskb, | |||
178 | NIPQUAD(new_ip)); | 167 | NIPQUAD(new_ip)); |
179 | 168 | ||
180 | /* Transfer from original range. */ | 169 | /* Transfer from original range. */ |
181 | newrange = ((struct ip_nat_range) | 170 | newrange = ((struct nf_nat_range) |
182 | { same->range[0].flags, new_ip, new_ip, | 171 | { same->range[0].flags, new_ip, new_ip, |
183 | /* FIXME: Use ports from correct range! */ | 172 | /* FIXME: Use ports from correct range! */ |
184 | same->range[0].min, same->range[0].max }); | 173 | same->range[0].min, same->range[0].max }); |
185 | 174 | ||
186 | /* Hand modified range to generic setup. */ | 175 | /* Hand modified range to generic setup. */ |
187 | return ip_nat_setup_info(ct, &newrange, hooknum); | 176 | return nf_nat_setup_info(ct, &newrange, hooknum); |
188 | } | 177 | } |
189 | 178 | ||
190 | static struct xt_target same_reg = { | 179 | static struct xt_target same_reg = { |
diff --git a/net/ipv4/netfilter/nf_nat_h323.c b/net/ipv4/netfilter/nf_nat_h323.c index 3c58fea0d391..fcebc968d37f 100644 --- a/net/ipv4/netfilter/nf_nat_h323.c +++ b/net/ipv4/netfilter/nf_nat_h323.c | |||
@@ -33,7 +33,7 @@ static int set_addr(struct sk_buff **pskb, | |||
33 | unsigned int addroff, __be32 ip, __be16 port) | 33 | unsigned int addroff, __be32 ip, __be16 port) |
34 | { | 34 | { |
35 | enum ip_conntrack_info ctinfo; | 35 | enum ip_conntrack_info ctinfo; |
36 | struct nf_conn *ct = ip_conntrack_get(*pskb, &ctinfo); | 36 | struct nf_conn *ct = nf_ct_get(*pskb, &ctinfo); |
37 | struct { | 37 | struct { |
38 | __be32 ip; | 38 | __be32 ip; |
39 | __be16 port; | 39 | __be16 port; |
@@ -383,7 +383,7 @@ static int nat_h245(struct sk_buff **pskb, struct nf_conn *ct, | |||
383 | static void ip_nat_q931_expect(struct nf_conn *new, | 383 | static void ip_nat_q931_expect(struct nf_conn *new, |
384 | struct nf_conntrack_expect *this) | 384 | struct nf_conntrack_expect *this) |
385 | { | 385 | { |
386 | struct ip_nat_range range; | 386 | struct nf_nat_range range; |
387 | 387 | ||
388 | if (this->tuple.src.u3.ip != 0) { /* Only accept calls from GK */ | 388 | if (this->tuple.src.u3.ip != 0) { /* Only accept calls from GK */ |
389 | nf_nat_follow_master(new, this); | 389 | nf_nat_follow_master(new, this); |
diff --git a/net/ipv4/netfilter/nf_nat_pptp.c b/net/ipv4/netfilter/nf_nat_pptp.c index 7ba341c22eaa..a66888749ceb 100644 --- a/net/ipv4/netfilter/nf_nat_pptp.c +++ b/net/ipv4/netfilter/nf_nat_pptp.c | |||
@@ -53,7 +53,7 @@ static void pptp_nat_expected(struct nf_conn *ct, | |||
53 | struct nf_conntrack_tuple t; | 53 | struct nf_conntrack_tuple t; |
54 | struct nf_ct_pptp_master *ct_pptp_info; | 54 | struct nf_ct_pptp_master *ct_pptp_info; |
55 | struct nf_nat_pptp *nat_pptp_info; | 55 | struct nf_nat_pptp *nat_pptp_info; |
56 | struct ip_nat_range range; | 56 | struct nf_nat_range range; |
57 | 57 | ||
58 | ct_pptp_info = &nfct_help(master)->help.ct_pptp_info; | 58 | ct_pptp_info = &nfct_help(master)->help.ct_pptp_info; |
59 | nat_pptp_info = &nfct_nat(master)->help.nat_pptp_info; | 59 | nat_pptp_info = &nfct_nat(master)->help.nat_pptp_info; |
diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig index 54698af6d0af..c558f3214255 100644 --- a/net/netfilter/Kconfig +++ b/net/netfilter/Kconfig | |||
@@ -25,6 +25,7 @@ config NETFILTER_NETLINK_LOG | |||
25 | and is also scheduled to replace the old syslog-based ipt_LOG | 25 | and is also scheduled to replace the old syslog-based ipt_LOG |
26 | and ip6t_LOG modules. | 26 | and ip6t_LOG modules. |
27 | 27 | ||
28 | # Rename this to NF_CONNTRACK in a 2.6.25 | ||
28 | config NF_CONNTRACK_ENABLED | 29 | config NF_CONNTRACK_ENABLED |
29 | tristate "Netfilter connection tracking support" | 30 | tristate "Netfilter connection tracking support" |
30 | help | 31 | help |
@@ -39,42 +40,9 @@ config NF_CONNTRACK_ENABLED | |||
39 | 40 | ||
40 | To compile it as a module, choose M here. If unsure, say N. | 41 | To compile it as a module, choose M here. If unsure, say N. |
41 | 42 | ||
42 | choice | ||
43 | prompt "Netfilter connection tracking support" | ||
44 | depends on NF_CONNTRACK_ENABLED | ||
45 | |||
46 | config NF_CONNTRACK_SUPPORT | ||
47 | bool "Layer 3 Independent Connection tracking" | ||
48 | help | ||
49 | Layer 3 independent connection tracking is experimental scheme | ||
50 | which generalize ip_conntrack to support other layer 3 protocols. | ||
51 | |||
52 | This is required to do Masquerading or other kinds of Network | ||
53 | Address Translation (except for Fast NAT). It can also be used to | ||
54 | enhance packet filtering (see `Connection state match support' | ||
55 | below). | ||
56 | |||
57 | config IP_NF_CONNTRACK_SUPPORT | ||
58 | bool "Layer 3 Dependent Connection tracking (OBSOLETE)" | ||
59 | help | ||
60 | The old, Layer 3 dependent ip_conntrack subsystem of netfilter. | ||
61 | |||
62 | This is required to do Masquerading or other kinds of Network | ||
63 | Address Translation (except for Fast NAT). It can also be used to | ||
64 | enhance packet filtering (see `Connection state match support' | ||
65 | below). | ||
66 | |||
67 | endchoice | ||
68 | |||
69 | config NF_CONNTRACK | 43 | config NF_CONNTRACK |
70 | tristate | 44 | tristate |
71 | default m if NF_CONNTRACK_SUPPORT && NF_CONNTRACK_ENABLED=m | 45 | default NF_CONNTRACK_ENABLED |
72 | default y if NF_CONNTRACK_SUPPORT && NF_CONNTRACK_ENABLED=y | ||
73 | |||
74 | config IP_NF_CONNTRACK | ||
75 | tristate | ||
76 | default m if IP_NF_CONNTRACK_SUPPORT && NF_CONNTRACK_ENABLED=m | ||
77 | default y if IP_NF_CONNTRACK_SUPPORT && NF_CONNTRACK_ENABLED=y | ||
78 | 46 | ||
79 | config NF_CT_ACCT | 47 | config NF_CT_ACCT |
80 | bool "Connection tracking flow accounting" | 48 | bool "Connection tracking flow accounting" |
@@ -303,9 +271,8 @@ config NETFILTER_XT_TARGET_CONNMARK | |||
303 | tristate '"CONNMARK" target support' | 271 | tristate '"CONNMARK" target support' |
304 | depends on NETFILTER_XTABLES | 272 | depends on NETFILTER_XTABLES |
305 | depends on IP_NF_MANGLE || IP6_NF_MANGLE | 273 | depends on IP_NF_MANGLE || IP6_NF_MANGLE |
306 | depends on IP_NF_CONNTRACK || NF_CONNTRACK | 274 | depends on NF_CONNTRACK |
307 | select IP_NF_CONNTRACK_MARK if IP_NF_CONNTRACK | 275 | select NF_CONNTRACK_MARK |
308 | select NF_CONNTRACK_MARK if NF_CONNTRACK | ||
309 | help | 276 | help |
310 | This option adds a `CONNMARK' target, which allows one to manipulate | 277 | This option adds a `CONNMARK' target, which allows one to manipulate |
311 | the connection mark value. Similar to the MARK target, but | 278 | the connection mark value. Similar to the MARK target, but |
@@ -366,7 +333,7 @@ config NETFILTER_XT_TARGET_NOTRACK | |||
366 | tristate '"NOTRACK" target support' | 333 | tristate '"NOTRACK" target support' |
367 | depends on NETFILTER_XTABLES | 334 | depends on NETFILTER_XTABLES |
368 | depends on IP_NF_RAW || IP6_NF_RAW | 335 | depends on IP_NF_RAW || IP6_NF_RAW |
369 | depends on IP_NF_CONNTRACK || NF_CONNTRACK | 336 | depends on NF_CONNTRACK |
370 | help | 337 | help |
371 | The NOTRACK target allows a select rule to specify | 338 | The NOTRACK target allows a select rule to specify |
372 | which packets *not* to enter the conntrack/NAT | 339 | which packets *not* to enter the conntrack/NAT |
@@ -387,9 +354,7 @@ config NETFILTER_XT_TARGET_SECMARK | |||
387 | 354 | ||
388 | config NETFILTER_XT_TARGET_CONNSECMARK | 355 | config NETFILTER_XT_TARGET_CONNSECMARK |
389 | tristate '"CONNSECMARK" target support' | 356 | tristate '"CONNSECMARK" target support' |
390 | depends on NETFILTER_XTABLES && \ | 357 | depends on NETFILTER_XTABLES && NF_CONNTRACK && NF_CONNTRACK_SECMARK |
391 | ((NF_CONNTRACK && NF_CONNTRACK_SECMARK) || \ | ||
392 | (IP_NF_CONNTRACK && IP_NF_CONNTRACK_SECMARK)) | ||
393 | help | 358 | help |
394 | The CONNSECMARK target copies security markings from packets | 359 | The CONNSECMARK target copies security markings from packets |
395 | to connections, and restores security markings from connections | 360 | to connections, and restores security markings from connections |
@@ -437,9 +402,8 @@ config NETFILTER_XT_MATCH_COMMENT | |||
437 | config NETFILTER_XT_MATCH_CONNBYTES | 402 | config NETFILTER_XT_MATCH_CONNBYTES |
438 | tristate '"connbytes" per-connection counter match support' | 403 | tristate '"connbytes" per-connection counter match support' |
439 | depends on NETFILTER_XTABLES | 404 | depends on NETFILTER_XTABLES |
440 | depends on IP_NF_CONNTRACK || NF_CONNTRACK | 405 | depends on NF_CONNTRACK |
441 | select IP_NF_CT_ACCT if IP_NF_CONNTRACK | 406 | select NF_CT_ACCT |
442 | select NF_CT_ACCT if NF_CONNTRACK | ||
443 | help | 407 | help |
444 | This option adds a `connbytes' match, which allows you to match the | 408 | This option adds a `connbytes' match, which allows you to match the |
445 | number of bytes and/or packets for each direction within a connection. | 409 | number of bytes and/or packets for each direction within a connection. |
@@ -450,9 +414,8 @@ config NETFILTER_XT_MATCH_CONNBYTES | |||
450 | config NETFILTER_XT_MATCH_CONNMARK | 414 | config NETFILTER_XT_MATCH_CONNMARK |
451 | tristate '"connmark" connection mark match support' | 415 | tristate '"connmark" connection mark match support' |
452 | depends on NETFILTER_XTABLES | 416 | depends on NETFILTER_XTABLES |
453 | depends on IP_NF_CONNTRACK || NF_CONNTRACK | 417 | depends on NF_CONNTRACK |
454 | select IP_NF_CONNTRACK_MARK if IP_NF_CONNTRACK | 418 | select NF_CONNTRACK_MARK |
455 | select NF_CONNTRACK_MARK if NF_CONNTRACK | ||
456 | help | 419 | help |
457 | This option adds a `connmark' match, which allows you to match the | 420 | This option adds a `connmark' match, which allows you to match the |
458 | connection mark value previously set for the session by `CONNMARK'. | 421 | connection mark value previously set for the session by `CONNMARK'. |
@@ -464,7 +427,7 @@ config NETFILTER_XT_MATCH_CONNMARK | |||
464 | config NETFILTER_XT_MATCH_CONNTRACK | 427 | config NETFILTER_XT_MATCH_CONNTRACK |
465 | tristate '"conntrack" connection tracking match support' | 428 | tristate '"conntrack" connection tracking match support' |
466 | depends on NETFILTER_XTABLES | 429 | depends on NETFILTER_XTABLES |
467 | depends on IP_NF_CONNTRACK || NF_CONNTRACK | 430 | depends on NF_CONNTRACK |
468 | help | 431 | help |
469 | This is a general conntrack match module, a superset of the state match. | 432 | This is a general conntrack match module, a superset of the state match. |
470 | 433 | ||
@@ -508,7 +471,7 @@ config NETFILTER_XT_MATCH_ESP | |||
508 | config NETFILTER_XT_MATCH_HELPER | 471 | config NETFILTER_XT_MATCH_HELPER |
509 | tristate '"helper" match support' | 472 | tristate '"helper" match support' |
510 | depends on NETFILTER_XTABLES | 473 | depends on NETFILTER_XTABLES |
511 | depends on IP_NF_CONNTRACK || NF_CONNTRACK | 474 | depends on NF_CONNTRACK |
512 | help | 475 | help |
513 | Helper matching allows you to match packets in dynamic connections | 476 | Helper matching allows you to match packets in dynamic connections |
514 | tracked by a conntrack-helper, ie. ip_conntrack_ftp | 477 | tracked by a conntrack-helper, ie. ip_conntrack_ftp |
@@ -632,7 +595,7 @@ config NETFILTER_XT_MATCH_SCTP | |||
632 | config NETFILTER_XT_MATCH_STATE | 595 | config NETFILTER_XT_MATCH_STATE |
633 | tristate '"state" match support' | 596 | tristate '"state" match support' |
634 | depends on NETFILTER_XTABLES | 597 | depends on NETFILTER_XTABLES |
635 | depends on IP_NF_CONNTRACK || NF_CONNTRACK | 598 | depends on NF_CONNTRACK |
636 | help | 599 | help |
637 | Connection state matching allows you to match packets based on their | 600 | Connection state matching allows you to match packets based on their |
638 | relationship to a tracked connection (ie. previous packets). This | 601 | relationship to a tracked connection (ie. previous packets). This |
diff --git a/net/netfilter/xt_CONNMARK.c b/net/netfilter/xt_CONNMARK.c index 795c058b16a5..b03ce009d0bf 100644 --- a/net/netfilter/xt_CONNMARK.c +++ b/net/netfilter/xt_CONNMARK.c | |||
@@ -30,10 +30,7 @@ MODULE_ALIAS("ipt_CONNMARK"); | |||
30 | 30 | ||
31 | #include <linux/netfilter/x_tables.h> | 31 | #include <linux/netfilter/x_tables.h> |
32 | #include <linux/netfilter/xt_CONNMARK.h> | 32 | #include <linux/netfilter/xt_CONNMARK.h> |
33 | #include <net/netfilter/nf_conntrack_compat.h> | ||
34 | #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE) | ||
35 | #include <net/netfilter/nf_conntrack_ecache.h> | 33 | #include <net/netfilter/nf_conntrack_ecache.h> |
36 | #endif | ||
37 | 34 | ||
38 | static unsigned int | 35 | static unsigned int |
39 | target(struct sk_buff **pskb, | 36 | target(struct sk_buff **pskb, |
@@ -44,40 +41,33 @@ target(struct sk_buff **pskb, | |||
44 | const void *targinfo) | 41 | const void *targinfo) |
45 | { | 42 | { |
46 | const struct xt_connmark_target_info *markinfo = targinfo; | 43 | const struct xt_connmark_target_info *markinfo = targinfo; |
44 | struct nf_conn *ct; | ||
45 | enum ip_conntrack_info ctinfo; | ||
47 | u_int32_t diff; | 46 | u_int32_t diff; |
48 | u_int32_t mark; | 47 | u_int32_t mark; |
49 | u_int32_t newmark; | 48 | u_int32_t newmark; |
50 | u_int32_t ctinfo; | ||
51 | u_int32_t *ctmark = nf_ct_get_mark(*pskb, &ctinfo); | ||
52 | 49 | ||
53 | if (ctmark) { | 50 | ct = nf_ct_get(*pskb, &ctinfo); |
51 | if (ct) { | ||
54 | switch(markinfo->mode) { | 52 | switch(markinfo->mode) { |
55 | case XT_CONNMARK_SET: | 53 | case XT_CONNMARK_SET: |
56 | newmark = (*ctmark & ~markinfo->mask) | markinfo->mark; | 54 | newmark = (ct->mark & ~markinfo->mask) | markinfo->mark; |
57 | if (newmark != *ctmark) { | 55 | if (newmark != ct->mark) { |
58 | *ctmark = newmark; | 56 | ct->mark = newmark; |
59 | #if defined(CONFIG_IP_NF_CONNTRACK) || defined(CONFIG_IP_NF_CONNTRACK_MODULE) | ||
60 | ip_conntrack_event_cache(IPCT_MARK, *pskb); | ||
61 | #else | ||
62 | nf_conntrack_event_cache(IPCT_MARK, *pskb); | 57 | nf_conntrack_event_cache(IPCT_MARK, *pskb); |
63 | #endif | ||
64 | } | 58 | } |
65 | break; | 59 | break; |
66 | case XT_CONNMARK_SAVE: | 60 | case XT_CONNMARK_SAVE: |
67 | newmark = (*ctmark & ~markinfo->mask) | | 61 | newmark = (ct->mark & ~markinfo->mask) | |
68 | ((*pskb)->mark & markinfo->mask); | 62 | ((*pskb)->mark & markinfo->mask); |
69 | if (*ctmark != newmark) { | 63 | if (ct->mark != newmark) { |
70 | *ctmark = newmark; | 64 | ct->mark = newmark; |
71 | #if defined(CONFIG_IP_NF_CONNTRACK) || defined(CONFIG_IP_NF_CONNTRACK_MODULE) | ||
72 | ip_conntrack_event_cache(IPCT_MARK, *pskb); | ||
73 | #else | ||
74 | nf_conntrack_event_cache(IPCT_MARK, *pskb); | 65 | nf_conntrack_event_cache(IPCT_MARK, *pskb); |
75 | #endif | ||
76 | } | 66 | } |
77 | break; | 67 | break; |
78 | case XT_CONNMARK_RESTORE: | 68 | case XT_CONNMARK_RESTORE: |
79 | mark = (*pskb)->mark; | 69 | mark = (*pskb)->mark; |
80 | diff = (*ctmark ^ mark) & markinfo->mask; | 70 | diff = (ct->mark ^ mark) & markinfo->mask; |
81 | (*pskb)->mark = mark ^ diff; | 71 | (*pskb)->mark = mark ^ diff; |
82 | break; | 72 | break; |
83 | } | 73 | } |
diff --git a/net/netfilter/xt_CONNSECMARK.c b/net/netfilter/xt_CONNSECMARK.c index 1ab0db641f96..81c0c58bab47 100644 --- a/net/netfilter/xt_CONNSECMARK.c +++ b/net/netfilter/xt_CONNSECMARK.c | |||
@@ -19,7 +19,7 @@ | |||
19 | #include <linux/skbuff.h> | 19 | #include <linux/skbuff.h> |
20 | #include <linux/netfilter/x_tables.h> | 20 | #include <linux/netfilter/x_tables.h> |
21 | #include <linux/netfilter/xt_CONNSECMARK.h> | 21 | #include <linux/netfilter/xt_CONNSECMARK.h> |
22 | #include <net/netfilter/nf_conntrack_compat.h> | 22 | #include <net/netfilter/nf_conntrack.h> |
23 | 23 | ||
24 | #define PFX "CONNSECMARK: " | 24 | #define PFX "CONNSECMARK: " |
25 | 25 | ||
@@ -36,12 +36,12 @@ MODULE_ALIAS("ip6t_CONNSECMARK"); | |||
36 | static void secmark_save(struct sk_buff *skb) | 36 | static void secmark_save(struct sk_buff *skb) |
37 | { | 37 | { |
38 | if (skb->secmark) { | 38 | if (skb->secmark) { |
39 | u32 *connsecmark; | 39 | struct nf_conn *ct; |
40 | enum ip_conntrack_info ctinfo; | 40 | enum ip_conntrack_info ctinfo; |
41 | 41 | ||
42 | connsecmark = nf_ct_get_secmark(skb, &ctinfo); | 42 | ct = nf_ct_get(skb, &ctinfo); |
43 | if (connsecmark && !*connsecmark) | 43 | if (ct && !ct->secmark) |
44 | *connsecmark = skb->secmark; | 44 | ct->secmark = skb->secmark; |
45 | } | 45 | } |
46 | } | 46 | } |
47 | 47 | ||
@@ -52,12 +52,12 @@ static void secmark_save(struct sk_buff *skb) | |||
52 | static void secmark_restore(struct sk_buff *skb) | 52 | static void secmark_restore(struct sk_buff *skb) |
53 | { | 53 | { |
54 | if (!skb->secmark) { | 54 | if (!skb->secmark) { |
55 | u32 *connsecmark; | 55 | struct nf_conn *ct; |
56 | enum ip_conntrack_info ctinfo; | 56 | enum ip_conntrack_info ctinfo; |
57 | 57 | ||
58 | connsecmark = nf_ct_get_secmark(skb, &ctinfo); | 58 | ct = nf_ct_get(skb, &ctinfo); |
59 | if (connsecmark && *connsecmark) | 59 | if (ct && ct->secmark) |
60 | skb->secmark = *connsecmark; | 60 | skb->secmark = ct->secmark; |
61 | } | 61 | } |
62 | } | 62 | } |
63 | 63 | ||
diff --git a/net/netfilter/xt_NOTRACK.c b/net/netfilter/xt_NOTRACK.c index b874a2008b2b..5085fb3d1e2d 100644 --- a/net/netfilter/xt_NOTRACK.c +++ b/net/netfilter/xt_NOTRACK.c | |||
@@ -5,7 +5,7 @@ | |||
5 | #include <linux/skbuff.h> | 5 | #include <linux/skbuff.h> |
6 | 6 | ||
7 | #include <linux/netfilter/x_tables.h> | 7 | #include <linux/netfilter/x_tables.h> |
8 | #include <net/netfilter/nf_conntrack_compat.h> | 8 | #include <net/netfilter/nf_conntrack.h> |
9 | 9 | ||
10 | MODULE_LICENSE("GPL"); | 10 | MODULE_LICENSE("GPL"); |
11 | MODULE_ALIAS("ipt_NOTRACK"); | 11 | MODULE_ALIAS("ipt_NOTRACK"); |
@@ -26,7 +26,7 @@ target(struct sk_buff **pskb, | |||
26 | If there is a real ct entry correspondig to this packet, | 26 | If there is a real ct entry correspondig to this packet, |
27 | it'll hang aroun till timing out. We don't deal with it | 27 | it'll hang aroun till timing out. We don't deal with it |
28 | for performance reasons. JK */ | 28 | for performance reasons. JK */ |
29 | nf_ct_untrack(*pskb); | 29 | (*pskb)->nfct = &nf_conntrack_untracked.ct_general; |
30 | (*pskb)->nfctinfo = IP_CT_NEW; | 30 | (*pskb)->nfctinfo = IP_CT_NEW; |
31 | nf_conntrack_get((*pskb)->nfct); | 31 | nf_conntrack_get((*pskb)->nfct); |
32 | 32 | ||
diff --git a/net/netfilter/xt_connbytes.c b/net/netfilter/xt_connbytes.c index 302043bc41b2..fec9316a1e10 100644 --- a/net/netfilter/xt_connbytes.c +++ b/net/netfilter/xt_connbytes.c | |||
@@ -12,9 +12,9 @@ | |||
12 | */ | 12 | */ |
13 | #include <linux/module.h> | 13 | #include <linux/module.h> |
14 | #include <linux/skbuff.h> | 14 | #include <linux/skbuff.h> |
15 | #include <net/netfilter/nf_conntrack_compat.h> | ||
16 | #include <linux/netfilter/x_tables.h> | 15 | #include <linux/netfilter/x_tables.h> |
17 | #include <linux/netfilter/xt_connbytes.h> | 16 | #include <linux/netfilter/xt_connbytes.h> |
17 | #include <net/netfilter/nf_conntrack.h> | ||
18 | 18 | ||
19 | #include <asm/div64.h> | 19 | #include <asm/div64.h> |
20 | #include <asm/bitops.h> | 20 | #include <asm/bitops.h> |
@@ -35,13 +35,17 @@ match(const struct sk_buff *skb, | |||
35 | int *hotdrop) | 35 | int *hotdrop) |
36 | { | 36 | { |
37 | const struct xt_connbytes_info *sinfo = matchinfo; | 37 | const struct xt_connbytes_info *sinfo = matchinfo; |
38 | struct nf_conn *ct; | ||
39 | enum ip_conntrack_info ctinfo; | ||
38 | u_int64_t what = 0; /* initialize to make gcc happy */ | 40 | u_int64_t what = 0; /* initialize to make gcc happy */ |
39 | u_int64_t bytes = 0; | 41 | u_int64_t bytes = 0; |
40 | u_int64_t pkts = 0; | 42 | u_int64_t pkts = 0; |
41 | const struct ip_conntrack_counter *counters; | 43 | const struct ip_conntrack_counter *counters; |
42 | 44 | ||
43 | if (!(counters = nf_ct_get_counters(skb))) | 45 | ct = nf_ct_get(skb, &ctinfo); |
44 | return 0; /* no match */ | 46 | if (!ct) |
47 | return 0; | ||
48 | counters = ct->counters; | ||
45 | 49 | ||
46 | switch (sinfo->what) { | 50 | switch (sinfo->what) { |
47 | case XT_CONNBYTES_PKTS: | 51 | case XT_CONNBYTES_PKTS: |
diff --git a/net/netfilter/xt_connmark.c b/net/netfilter/xt_connmark.c index 36c2defff238..e1803256c792 100644 --- a/net/netfilter/xt_connmark.c +++ b/net/netfilter/xt_connmark.c | |||
@@ -21,16 +21,15 @@ | |||
21 | 21 | ||
22 | #include <linux/module.h> | 22 | #include <linux/module.h> |
23 | #include <linux/skbuff.h> | 23 | #include <linux/skbuff.h> |
24 | #include <net/netfilter/nf_conntrack.h> | ||
25 | #include <linux/netfilter/x_tables.h> | ||
26 | #include <linux/netfilter/xt_connmark.h> | ||
24 | 27 | ||
25 | MODULE_AUTHOR("Henrik Nordstrom <hno@marasytems.com>"); | 28 | MODULE_AUTHOR("Henrik Nordstrom <hno@marasytems.com>"); |
26 | MODULE_DESCRIPTION("IP tables connmark match module"); | 29 | MODULE_DESCRIPTION("IP tables connmark match module"); |
27 | MODULE_LICENSE("GPL"); | 30 | MODULE_LICENSE("GPL"); |
28 | MODULE_ALIAS("ipt_connmark"); | 31 | MODULE_ALIAS("ipt_connmark"); |
29 | 32 | ||
30 | #include <linux/netfilter/x_tables.h> | ||
31 | #include <linux/netfilter/xt_connmark.h> | ||
32 | #include <net/netfilter/nf_conntrack_compat.h> | ||
33 | |||
34 | static int | 33 | static int |
35 | match(const struct sk_buff *skb, | 34 | match(const struct sk_buff *skb, |
36 | const struct net_device *in, | 35 | const struct net_device *in, |
@@ -42,12 +41,14 @@ match(const struct sk_buff *skb, | |||
42 | int *hotdrop) | 41 | int *hotdrop) |
43 | { | 42 | { |
44 | const struct xt_connmark_info *info = matchinfo; | 43 | const struct xt_connmark_info *info = matchinfo; |
45 | u_int32_t ctinfo; | 44 | struct nf_conn *ct; |
46 | const u_int32_t *ctmark = nf_ct_get_mark(skb, &ctinfo); | 45 | enum ip_conntrack_info ctinfo; |
47 | if (!ctmark) | 46 | |
47 | ct = nf_ct_get(skb, &ctinfo); | ||
48 | if (!ct) | ||
48 | return 0; | 49 | return 0; |
49 | 50 | ||
50 | return (((*ctmark) & info->mask) == info->mark) ^ info->invert; | 51 | return (((ct->mark) & info->mask) == info->mark) ^ info->invert; |
51 | } | 52 | } |
52 | 53 | ||
53 | static int | 54 | static int |
diff --git a/net/netfilter/xt_conntrack.c b/net/netfilter/xt_conntrack.c index 2885c378288e..f4ea8fe07a53 100644 --- a/net/netfilter/xt_conntrack.c +++ b/net/netfilter/xt_conntrack.c | |||
@@ -10,121 +10,15 @@ | |||
10 | 10 | ||
11 | #include <linux/module.h> | 11 | #include <linux/module.h> |
12 | #include <linux/skbuff.h> | 12 | #include <linux/skbuff.h> |
13 | |||
14 | #if defined(CONFIG_IP_NF_CONNTRACK) || defined(CONFIG_IP_NF_CONNTRACK_MODULE) | ||
15 | #include <linux/netfilter_ipv4/ip_conntrack.h> | ||
16 | #include <linux/netfilter_ipv4/ip_conntrack_tuple.h> | ||
17 | #else | ||
18 | #include <net/netfilter/nf_conntrack.h> | ||
19 | #endif | ||
20 | |||
21 | #include <linux/netfilter/x_tables.h> | 13 | #include <linux/netfilter/x_tables.h> |
22 | #include <linux/netfilter/xt_conntrack.h> | 14 | #include <linux/netfilter/xt_conntrack.h> |
23 | #include <net/netfilter/nf_conntrack_compat.h> | 15 | #include <net/netfilter/nf_conntrack.h> |
24 | 16 | ||
25 | MODULE_LICENSE("GPL"); | 17 | MODULE_LICENSE("GPL"); |
26 | MODULE_AUTHOR("Marc Boucher <marc@mbsi.ca>"); | 18 | MODULE_AUTHOR("Marc Boucher <marc@mbsi.ca>"); |
27 | MODULE_DESCRIPTION("iptables connection tracking match module"); | 19 | MODULE_DESCRIPTION("iptables connection tracking match module"); |
28 | MODULE_ALIAS("ipt_conntrack"); | 20 | MODULE_ALIAS("ipt_conntrack"); |
29 | 21 | ||
30 | #if defined(CONFIG_IP_NF_CONNTRACK) || defined(CONFIG_IP_NF_CONNTRACK_MODULE) | ||
31 | |||
32 | static int | ||
33 | match(const struct sk_buff *skb, | ||
34 | const struct net_device *in, | ||
35 | const struct net_device *out, | ||
36 | const struct xt_match *match, | ||
37 | const void *matchinfo, | ||
38 | int offset, | ||
39 | unsigned int protoff, | ||
40 | int *hotdrop) | ||
41 | { | ||
42 | const struct xt_conntrack_info *sinfo = matchinfo; | ||
43 | struct ip_conntrack *ct; | ||
44 | enum ip_conntrack_info ctinfo; | ||
45 | unsigned int statebit; | ||
46 | |||
47 | ct = ip_conntrack_get((struct sk_buff *)skb, &ctinfo); | ||
48 | |||
49 | #define FWINV(bool, invflg) ((bool) ^ !!(sinfo->invflags & invflg)) | ||
50 | |||
51 | if (ct == &ip_conntrack_untracked) | ||
52 | statebit = XT_CONNTRACK_STATE_UNTRACKED; | ||
53 | else if (ct) | ||
54 | statebit = XT_CONNTRACK_STATE_BIT(ctinfo); | ||
55 | else | ||
56 | statebit = XT_CONNTRACK_STATE_INVALID; | ||
57 | |||
58 | if (sinfo->flags & XT_CONNTRACK_STATE) { | ||
59 | if (ct) { | ||
60 | if (test_bit(IPS_SRC_NAT_BIT, &ct->status)) | ||
61 | statebit |= XT_CONNTRACK_STATE_SNAT; | ||
62 | if (test_bit(IPS_DST_NAT_BIT, &ct->status)) | ||
63 | statebit |= XT_CONNTRACK_STATE_DNAT; | ||
64 | } | ||
65 | if (FWINV((statebit & sinfo->statemask) == 0, | ||
66 | XT_CONNTRACK_STATE)) | ||
67 | return 0; | ||
68 | } | ||
69 | |||
70 | if (ct == NULL) { | ||
71 | if (sinfo->flags & ~XT_CONNTRACK_STATE) | ||
72 | return 0; | ||
73 | return 1; | ||
74 | } | ||
75 | |||
76 | if (sinfo->flags & XT_CONNTRACK_PROTO && | ||
77 | FWINV(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum != | ||
78 | sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.protonum, | ||
79 | XT_CONNTRACK_PROTO)) | ||
80 | return 0; | ||
81 | |||
82 | if (sinfo->flags & XT_CONNTRACK_ORIGSRC && | ||
83 | FWINV((ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip & | ||
84 | sinfo->sipmsk[IP_CT_DIR_ORIGINAL].s_addr) != | ||
85 | sinfo->tuple[IP_CT_DIR_ORIGINAL].src.ip, | ||
86 | XT_CONNTRACK_ORIGSRC)) | ||
87 | return 0; | ||
88 | |||
89 | if (sinfo->flags & XT_CONNTRACK_ORIGDST && | ||
90 | FWINV((ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip & | ||
91 | sinfo->dipmsk[IP_CT_DIR_ORIGINAL].s_addr) != | ||
92 | sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.ip, | ||
93 | XT_CONNTRACK_ORIGDST)) | ||
94 | return 0; | ||
95 | |||
96 | if (sinfo->flags & XT_CONNTRACK_REPLSRC && | ||
97 | FWINV((ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip & | ||
98 | sinfo->sipmsk[IP_CT_DIR_REPLY].s_addr) != | ||
99 | sinfo->tuple[IP_CT_DIR_REPLY].src.ip, | ||
100 | XT_CONNTRACK_REPLSRC)) | ||
101 | return 0; | ||
102 | |||
103 | if (sinfo->flags & XT_CONNTRACK_REPLDST && | ||
104 | FWINV((ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip & | ||
105 | sinfo->dipmsk[IP_CT_DIR_REPLY].s_addr) != | ||
106 | sinfo->tuple[IP_CT_DIR_REPLY].dst.ip, | ||
107 | XT_CONNTRACK_REPLDST)) | ||
108 | return 0; | ||
109 | |||
110 | if (sinfo->flags & XT_CONNTRACK_STATUS && | ||
111 | FWINV((ct->status & sinfo->statusmask) == 0, | ||
112 | XT_CONNTRACK_STATUS)) | ||
113 | return 0; | ||
114 | |||
115 | if (sinfo->flags & XT_CONNTRACK_EXPIRES) { | ||
116 | unsigned long expires = timer_pending(&ct->timeout) ? | ||
117 | (ct->timeout.expires - jiffies)/HZ : 0; | ||
118 | |||
119 | if (FWINV(!(expires >= sinfo->expires_min && | ||
120 | expires <= sinfo->expires_max), | ||
121 | XT_CONNTRACK_EXPIRES)) | ||
122 | return 0; | ||
123 | } | ||
124 | return 1; | ||
125 | } | ||
126 | |||
127 | #else /* CONFIG_IP_NF_CONNTRACK */ | ||
128 | static int | 22 | static int |
129 | match(const struct sk_buff *skb, | 23 | match(const struct sk_buff *skb, |
130 | const struct net_device *in, | 24 | const struct net_device *in, |
@@ -220,8 +114,6 @@ match(const struct sk_buff *skb, | |||
220 | return 1; | 114 | return 1; |
221 | } | 115 | } |
222 | 116 | ||
223 | #endif /* CONFIG_NF_IP_CONNTRACK */ | ||
224 | |||
225 | static int | 117 | static int |
226 | checkentry(const char *tablename, | 118 | checkentry(const char *tablename, |
227 | const void *ip, | 119 | const void *ip, |
diff --git a/net/netfilter/xt_helper.c b/net/netfilter/xt_helper.c index 407d1d5da8a1..bc70b26ba5b4 100644 --- a/net/netfilter/xt_helper.c +++ b/net/netfilter/xt_helper.c | |||
@@ -13,18 +13,11 @@ | |||
13 | #include <linux/module.h> | 13 | #include <linux/module.h> |
14 | #include <linux/skbuff.h> | 14 | #include <linux/skbuff.h> |
15 | #include <linux/netfilter.h> | 15 | #include <linux/netfilter.h> |
16 | #if defined(CONFIG_IP_NF_CONNTRACK) || defined(CONFIG_IP_NF_CONNTRACK_MODULE) | ||
17 | #include <linux/netfilter_ipv4/ip_conntrack.h> | ||
18 | #include <linux/netfilter_ipv4/ip_conntrack_core.h> | ||
19 | #include <linux/netfilter_ipv4/ip_conntrack_helper.h> | ||
20 | #else | ||
21 | #include <net/netfilter/nf_conntrack.h> | 16 | #include <net/netfilter/nf_conntrack.h> |
22 | #include <net/netfilter/nf_conntrack_core.h> | 17 | #include <net/netfilter/nf_conntrack_core.h> |
23 | #include <net/netfilter/nf_conntrack_helper.h> | 18 | #include <net/netfilter/nf_conntrack_helper.h> |
24 | #endif | ||
25 | #include <linux/netfilter/x_tables.h> | 19 | #include <linux/netfilter/x_tables.h> |
26 | #include <linux/netfilter/xt_helper.h> | 20 | #include <linux/netfilter/xt_helper.h> |
27 | #include <net/netfilter/nf_conntrack_compat.h> | ||
28 | 21 | ||
29 | MODULE_LICENSE("GPL"); | 22 | MODULE_LICENSE("GPL"); |
30 | MODULE_AUTHOR("Martin Josefsson <gandalf@netfilter.org>"); | 23 | MODULE_AUTHOR("Martin Josefsson <gandalf@netfilter.org>"); |
@@ -38,55 +31,6 @@ MODULE_ALIAS("ip6t_helper"); | |||
38 | #define DEBUGP(format, args...) | 31 | #define DEBUGP(format, args...) |
39 | #endif | 32 | #endif |
40 | 33 | ||
41 | #if defined(CONFIG_IP_NF_CONNTRACK) || defined(CONFIG_IP_NF_CONNTRACK_MODULE) | ||
42 | static int | ||
43 | match(const struct sk_buff *skb, | ||
44 | const struct net_device *in, | ||
45 | const struct net_device *out, | ||
46 | const struct xt_match *match, | ||
47 | const void *matchinfo, | ||
48 | int offset, | ||
49 | unsigned int protoff, | ||
50 | int *hotdrop) | ||
51 | { | ||
52 | const struct xt_helper_info *info = matchinfo; | ||
53 | struct ip_conntrack *ct; | ||
54 | enum ip_conntrack_info ctinfo; | ||
55 | int ret = info->invert; | ||
56 | |||
57 | ct = ip_conntrack_get((struct sk_buff *)skb, &ctinfo); | ||
58 | if (!ct) { | ||
59 | DEBUGP("xt_helper: Eek! invalid conntrack?\n"); | ||
60 | return ret; | ||
61 | } | ||
62 | |||
63 | if (!ct->master) { | ||
64 | DEBUGP("xt_helper: conntrack %p has no master\n", ct); | ||
65 | return ret; | ||
66 | } | ||
67 | |||
68 | read_lock_bh(&ip_conntrack_lock); | ||
69 | if (!ct->master->helper) { | ||
70 | DEBUGP("xt_helper: master ct %p has no helper\n", | ||
71 | exp->expectant); | ||
72 | goto out_unlock; | ||
73 | } | ||
74 | |||
75 | DEBUGP("master's name = %s , info->name = %s\n", | ||
76 | ct->master->helper->name, info->name); | ||
77 | |||
78 | if (info->name[0] == '\0') | ||
79 | ret ^= 1; | ||
80 | else | ||
81 | ret ^= !strncmp(ct->master->helper->name, info->name, | ||
82 | strlen(ct->master->helper->name)); | ||
83 | out_unlock: | ||
84 | read_unlock_bh(&ip_conntrack_lock); | ||
85 | return ret; | ||
86 | } | ||
87 | |||
88 | #else /* CONFIG_IP_NF_CONNTRACK */ | ||
89 | |||
90 | static int | 34 | static int |
91 | match(const struct sk_buff *skb, | 35 | match(const struct sk_buff *skb, |
92 | const struct net_device *in, | 36 | const struct net_device *in, |
@@ -134,7 +78,6 @@ out_unlock: | |||
134 | read_unlock_bh(&nf_conntrack_lock); | 78 | read_unlock_bh(&nf_conntrack_lock); |
135 | return ret; | 79 | return ret; |
136 | } | 80 | } |
137 | #endif | ||
138 | 81 | ||
139 | static int check(const char *tablename, | 82 | static int check(const char *tablename, |
140 | const void *inf, | 83 | const void *inf, |
diff --git a/net/netfilter/xt_state.c b/net/netfilter/xt_state.c index df37b912163a..149294f7df71 100644 --- a/net/netfilter/xt_state.c +++ b/net/netfilter/xt_state.c | |||
@@ -10,7 +10,7 @@ | |||
10 | 10 | ||
11 | #include <linux/module.h> | 11 | #include <linux/module.h> |
12 | #include <linux/skbuff.h> | 12 | #include <linux/skbuff.h> |
13 | #include <net/netfilter/nf_conntrack_compat.h> | 13 | #include <net/netfilter/nf_conntrack.h> |
14 | #include <linux/netfilter/x_tables.h> | 14 | #include <linux/netfilter/x_tables.h> |
15 | #include <linux/netfilter/xt_state.h> | 15 | #include <linux/netfilter/xt_state.h> |
16 | 16 | ||
@@ -36,7 +36,7 @@ match(const struct sk_buff *skb, | |||
36 | 36 | ||
37 | if (nf_ct_is_untracked(skb)) | 37 | if (nf_ct_is_untracked(skb)) |
38 | statebit = XT_STATE_UNTRACKED; | 38 | statebit = XT_STATE_UNTRACKED; |
39 | else if (!nf_ct_get_ctinfo(skb, &ctinfo)) | 39 | else if (!nf_ct_get(skb, &ctinfo)) |
40 | statebit = XT_STATE_INVALID; | 40 | statebit = XT_STATE_INVALID; |
41 | else | 41 | else |
42 | statebit = XT_STATE_BIT(ctinfo); | 42 | statebit = XT_STATE_BIT(ctinfo); |