[NETFILTER]: nf_conntrack: reduce masks to a subset of tuples
[safe/jmp/linux-2.6] / net / netfilter / nf_conntrack_expect.c
1 /* Expectation handling for nf_conntrack. */
2
3 /* (C) 1999-2001 Paul `Rusty' Russell
4  * (C) 2002-2006 Netfilter Core Team <coreteam@netfilter.org>
5  * (C) 2003,2004 USAGI/WIDE Project <http://www.linux-ipv6.org>
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 #include <linux/types.h>
13 #include <linux/netfilter.h>
14 #include <linux/skbuff.h>
15 #include <linux/proc_fs.h>
16 #include <linux/seq_file.h>
17 #include <linux/stddef.h>
18 #include <linux/slab.h>
19 #include <linux/err.h>
20 #include <linux/percpu.h>
21 #include <linux/kernel.h>
22
23 #include <net/netfilter/nf_conntrack.h>
24 #include <net/netfilter/nf_conntrack_core.h>
25 #include <net/netfilter/nf_conntrack_expect.h>
26 #include <net/netfilter/nf_conntrack_helper.h>
27 #include <net/netfilter/nf_conntrack_tuple.h>
28
29 LIST_HEAD(nf_ct_expect_list);
30 EXPORT_SYMBOL_GPL(nf_ct_expect_list);
31
32 struct kmem_cache *nf_ct_expect_cachep __read_mostly;
33 static unsigned int nf_ct_expect_next_id;
34
35 /* nf_conntrack_expect helper functions */
36 void nf_ct_unlink_expect(struct nf_conntrack_expect *exp)
37 {
38         struct nf_conn_help *master_help = nfct_help(exp->master);
39
40         NF_CT_ASSERT(master_help);
41         NF_CT_ASSERT(!timer_pending(&exp->timeout));
42
43         list_del(&exp->list);
44         NF_CT_STAT_INC(expect_delete);
45         master_help->expecting--;
46         nf_ct_expect_put(exp);
47 }
48 EXPORT_SYMBOL_GPL(nf_ct_unlink_expect);
49
50 static void nf_ct_expectation_timed_out(unsigned long ul_expect)
51 {
52         struct nf_conntrack_expect *exp = (void *)ul_expect;
53
54         write_lock_bh(&nf_conntrack_lock);
55         nf_ct_unlink_expect(exp);
56         write_unlock_bh(&nf_conntrack_lock);
57         nf_ct_expect_put(exp);
58 }
59
60 struct nf_conntrack_expect *
61 __nf_ct_expect_find(const struct nf_conntrack_tuple *tuple)
62 {
63         struct nf_conntrack_expect *i;
64
65         list_for_each_entry(i, &nf_ct_expect_list, list) {
66                 if (nf_ct_tuple_mask_cmp(tuple, &i->tuple, &i->mask))
67                         return i;
68         }
69         return NULL;
70 }
71 EXPORT_SYMBOL_GPL(__nf_ct_expect_find);
72
73 /* Just find a expectation corresponding to a tuple. */
74 struct nf_conntrack_expect *
75 nf_ct_expect_find_get(const struct nf_conntrack_tuple *tuple)
76 {
77         struct nf_conntrack_expect *i;
78
79         read_lock_bh(&nf_conntrack_lock);
80         i = __nf_ct_expect_find(tuple);
81         if (i)
82                 atomic_inc(&i->use);
83         read_unlock_bh(&nf_conntrack_lock);
84
85         return i;
86 }
87 EXPORT_SYMBOL_GPL(nf_ct_expect_find_get);
88
89 /* If an expectation for this connection is found, it gets delete from
90  * global list then returned. */
91 struct nf_conntrack_expect *
92 nf_ct_find_expectation(const struct nf_conntrack_tuple *tuple)
93 {
94         struct nf_conntrack_expect *exp;
95
96         exp = __nf_ct_expect_find(tuple);
97         if (!exp)
98                 return NULL;
99
100         /* If master is not in hash table yet (ie. packet hasn't left
101            this machine yet), how can other end know about expected?
102            Hence these are not the droids you are looking for (if
103            master ct never got confirmed, we'd hold a reference to it
104            and weird things would happen to future packets). */
105         if (!nf_ct_is_confirmed(exp->master))
106                 return NULL;
107
108         if (exp->flags & NF_CT_EXPECT_PERMANENT) {
109                 atomic_inc(&exp->use);
110                 return exp;
111         } else if (del_timer(&exp->timeout)) {
112                 nf_ct_unlink_expect(exp);
113                 return exp;
114         }
115
116         return NULL;
117 }
118
119 /* delete all expectations for this conntrack */
120 void nf_ct_remove_expectations(struct nf_conn *ct)
121 {
122         struct nf_conntrack_expect *i, *tmp;
123         struct nf_conn_help *help = nfct_help(ct);
124
125         /* Optimization: most connection never expect any others. */
126         if (!help || help->expecting == 0)
127                 return;
128
129         list_for_each_entry_safe(i, tmp, &nf_ct_expect_list, list) {
130                 if (i->master == ct && del_timer(&i->timeout)) {
131                         nf_ct_unlink_expect(i);
132                         nf_ct_expect_put(i);
133                 }
134         }
135 }
136 EXPORT_SYMBOL_GPL(nf_ct_remove_expectations);
137
138 /* Would two expected things clash? */
139 static inline int expect_clash(const struct nf_conntrack_expect *a,
140                                const struct nf_conntrack_expect *b)
141 {
142         /* Part covered by intersection of masks must be unequal,
143            otherwise they clash */
144         struct nf_conntrack_tuple_mask intersect_mask;
145         int count;
146
147         intersect_mask.src.u.all = a->mask.src.u.all & b->mask.src.u.all;
148
149         for (count = 0; count < NF_CT_TUPLE_L3SIZE; count++){
150                 intersect_mask.src.u3.all[count] =
151                         a->mask.src.u3.all[count] & b->mask.src.u3.all[count];
152         }
153
154         return nf_ct_tuple_mask_cmp(&a->tuple, &b->tuple, &intersect_mask);
155 }
156
157 static inline int expect_matches(const struct nf_conntrack_expect *a,
158                                  const struct nf_conntrack_expect *b)
159 {
160         return a->master == b->master
161                 && nf_ct_tuple_equal(&a->tuple, &b->tuple)
162                 && nf_ct_tuple_mask_equal(&a->mask, &b->mask);
163 }
164
165 /* Generally a bad idea to call this: could have matched already. */
166 void nf_ct_unexpect_related(struct nf_conntrack_expect *exp)
167 {
168         struct nf_conntrack_expect *i;
169
170         write_lock_bh(&nf_conntrack_lock);
171         /* choose the oldest expectation to evict */
172         list_for_each_entry_reverse(i, &nf_ct_expect_list, list) {
173                 if (expect_matches(i, exp) && del_timer(&i->timeout)) {
174                         nf_ct_unlink_expect(i);
175                         write_unlock_bh(&nf_conntrack_lock);
176                         nf_ct_expect_put(i);
177                         return;
178                 }
179         }
180         write_unlock_bh(&nf_conntrack_lock);
181 }
182 EXPORT_SYMBOL_GPL(nf_ct_unexpect_related);
183
184 /* We don't increase the master conntrack refcount for non-fulfilled
185  * conntracks. During the conntrack destruction, the expectations are
186  * always killed before the conntrack itself */
187 struct nf_conntrack_expect *nf_ct_expect_alloc(struct nf_conn *me)
188 {
189         struct nf_conntrack_expect *new;
190
191         new = kmem_cache_alloc(nf_ct_expect_cachep, GFP_ATOMIC);
192         if (!new)
193                 return NULL;
194
195         new->master = me;
196         atomic_set(&new->use, 1);
197         return new;
198 }
199 EXPORT_SYMBOL_GPL(nf_ct_expect_alloc);
200
201 void nf_ct_expect_init(struct nf_conntrack_expect *exp, int family,
202                        union nf_conntrack_address *saddr,
203                        union nf_conntrack_address *daddr,
204                        u_int8_t proto, __be16 *src, __be16 *dst)
205 {
206         int len;
207
208         if (family == AF_INET)
209                 len = 4;
210         else
211                 len = 16;
212
213         exp->flags = 0;
214         exp->expectfn = NULL;
215         exp->helper = NULL;
216         exp->tuple.src.l3num = family;
217         exp->tuple.dst.protonum = proto;
218
219         if (saddr) {
220                 memcpy(&exp->tuple.src.u3, saddr, len);
221                 if (sizeof(exp->tuple.src.u3) > len)
222                         /* address needs to be cleared for nf_ct_tuple_equal */
223                         memset((void *)&exp->tuple.src.u3 + len, 0x00,
224                                sizeof(exp->tuple.src.u3) - len);
225                 memset(&exp->mask.src.u3, 0xFF, len);
226                 if (sizeof(exp->mask.src.u3) > len)
227                         memset((void *)&exp->mask.src.u3 + len, 0x00,
228                                sizeof(exp->mask.src.u3) - len);
229         } else {
230                 memset(&exp->tuple.src.u3, 0x00, sizeof(exp->tuple.src.u3));
231                 memset(&exp->mask.src.u3, 0x00, sizeof(exp->mask.src.u3));
232         }
233
234         if (src) {
235                 exp->tuple.src.u.all = (__force u16)*src;
236                 exp->mask.src.u.all = 0xFFFF;
237         } else {
238                 exp->tuple.src.u.all = 0;
239                 exp->mask.src.u.all = 0;
240         }
241
242         memcpy(&exp->tuple.dst.u3, daddr, len);
243         if (sizeof(exp->tuple.dst.u3) > len)
244                 /* address needs to be cleared for nf_ct_tuple_equal */
245                 memset((void *)&exp->tuple.dst.u3 + len, 0x00,
246                        sizeof(exp->tuple.dst.u3) - len);
247
248         exp->tuple.dst.u.all = (__force u16)*dst;
249 }
250 EXPORT_SYMBOL_GPL(nf_ct_expect_init);
251
252 void nf_ct_expect_put(struct nf_conntrack_expect *exp)
253 {
254         if (atomic_dec_and_test(&exp->use))
255                 kmem_cache_free(nf_ct_expect_cachep, exp);
256 }
257 EXPORT_SYMBOL_GPL(nf_ct_expect_put);
258
259 static void nf_ct_expect_insert(struct nf_conntrack_expect *exp)
260 {
261         struct nf_conn_help *master_help = nfct_help(exp->master);
262
263         atomic_inc(&exp->use);
264         master_help->expecting++;
265         list_add(&exp->list, &nf_ct_expect_list);
266
267         setup_timer(&exp->timeout, nf_ct_expectation_timed_out,
268                     (unsigned long)exp);
269         exp->timeout.expires = jiffies + master_help->helper->timeout * HZ;
270         add_timer(&exp->timeout);
271
272         exp->id = ++nf_ct_expect_next_id;
273         atomic_inc(&exp->use);
274         NF_CT_STAT_INC(expect_create);
275 }
276
277 /* Race with expectations being used means we could have none to find; OK. */
278 static void evict_oldest_expect(struct nf_conn *master)
279 {
280         struct nf_conntrack_expect *i;
281
282         list_for_each_entry_reverse(i, &nf_ct_expect_list, list) {
283                 if (i->master == master) {
284                         if (del_timer(&i->timeout)) {
285                                 nf_ct_unlink_expect(i);
286                                 nf_ct_expect_put(i);
287                         }
288                         break;
289                 }
290         }
291 }
292
293 static inline int refresh_timer(struct nf_conntrack_expect *i)
294 {
295         struct nf_conn_help *master_help = nfct_help(i->master);
296
297         if (!del_timer(&i->timeout))
298                 return 0;
299
300         i->timeout.expires = jiffies + master_help->helper->timeout*HZ;
301         add_timer(&i->timeout);
302         return 1;
303 }
304
305 int nf_ct_expect_related(struct nf_conntrack_expect *expect)
306 {
307         struct nf_conntrack_expect *i;
308         struct nf_conn *master = expect->master;
309         struct nf_conn_help *master_help = nfct_help(master);
310         int ret;
311
312         NF_CT_ASSERT(master_help);
313
314         write_lock_bh(&nf_conntrack_lock);
315         if (!master_help->helper) {
316                 ret = -ESHUTDOWN;
317                 goto out;
318         }
319         list_for_each_entry(i, &nf_ct_expect_list, list) {
320                 if (expect_matches(i, expect)) {
321                         /* Refresh timer: if it's dying, ignore.. */
322                         if (refresh_timer(i)) {
323                                 ret = 0;
324                                 goto out;
325                         }
326                 } else if (expect_clash(i, expect)) {
327                         ret = -EBUSY;
328                         goto out;
329                 }
330         }
331         /* Will be over limit? */
332         if (master_help->helper->max_expected &&
333             master_help->expecting >= master_help->helper->max_expected)
334                 evict_oldest_expect(master);
335
336         nf_ct_expect_insert(expect);
337         nf_ct_expect_event(IPEXP_NEW, expect);
338         ret = 0;
339 out:
340         write_unlock_bh(&nf_conntrack_lock);
341         return ret;
342 }
343 EXPORT_SYMBOL_GPL(nf_ct_expect_related);
344
345 #ifdef CONFIG_PROC_FS
346 static void *exp_seq_start(struct seq_file *s, loff_t *pos)
347 {
348         struct list_head *e = &nf_ct_expect_list;
349         loff_t i;
350
351         /* strange seq_file api calls stop even if we fail,
352          * thus we need to grab lock since stop unlocks */
353         read_lock_bh(&nf_conntrack_lock);
354
355         if (list_empty(e))
356                 return NULL;
357
358         for (i = 0; i <= *pos; i++) {
359                 e = e->next;
360                 if (e == &nf_ct_expect_list)
361                         return NULL;
362         }
363         return e;
364 }
365
366 static void *exp_seq_next(struct seq_file *s, void *v, loff_t *pos)
367 {
368         struct list_head *e = v;
369
370         ++*pos;
371         e = e->next;
372
373         if (e == &nf_ct_expect_list)
374                 return NULL;
375
376         return e;
377 }
378
379 static void exp_seq_stop(struct seq_file *s, void *v)
380 {
381         read_unlock_bh(&nf_conntrack_lock);
382 }
383
384 static int exp_seq_show(struct seq_file *s, void *v)
385 {
386         struct nf_conntrack_expect *expect = v;
387
388         if (expect->timeout.function)
389                 seq_printf(s, "%ld ", timer_pending(&expect->timeout)
390                            ? (long)(expect->timeout.expires - jiffies)/HZ : 0);
391         else
392                 seq_printf(s, "- ");
393         seq_printf(s, "l3proto = %u proto=%u ",
394                    expect->tuple.src.l3num,
395                    expect->tuple.dst.protonum);
396         print_tuple(s, &expect->tuple,
397                     __nf_ct_l3proto_find(expect->tuple.src.l3num),
398                     __nf_ct_l4proto_find(expect->tuple.src.l3num,
399                                        expect->tuple.dst.protonum));
400         return seq_putc(s, '\n');
401 }
402
403 static struct seq_operations exp_seq_ops = {
404         .start = exp_seq_start,
405         .next = exp_seq_next,
406         .stop = exp_seq_stop,
407         .show = exp_seq_show
408 };
409
410 static int exp_open(struct inode *inode, struct file *file)
411 {
412         return seq_open(file, &exp_seq_ops);
413 }
414
415 const struct file_operations exp_file_ops = {
416         .owner   = THIS_MODULE,
417         .open    = exp_open,
418         .read    = seq_read,
419         .llseek  = seq_lseek,
420         .release = seq_release
421 };
422 #endif /* CONFIG_PROC_FS */