nf_conntrack_expect.c revision 4e1d4e6c5a448bd114e0cef6311c974cb7c7385e
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
29LIST_HEAD(nf_ct_expect_list);
30EXPORT_SYMBOL_GPL(nf_ct_expect_list);
31
32struct kmem_cache *nf_ct_expect_cachep __read_mostly;
33static unsigned int nf_ct_expect_next_id;
34
35/* nf_conntrack_expect helper functions */
36void 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}
48EXPORT_SYMBOL_GPL(nf_ct_unlink_expect);
49
50static 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
60struct 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}
71EXPORT_SYMBOL_GPL(__nf_ct_expect_find);
72
73/* Just find a expectation corresponding to a tuple. */
74struct nf_conntrack_expect *
75nf_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}
87EXPORT_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. */
91struct nf_conntrack_expect *
92nf_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 */
120void 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}
136EXPORT_SYMBOL_GPL(nf_ct_remove_expectations);
137
138/* Would two expected things clash? */
139static 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
157static 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. */
166void nf_ct_unexpect_related(struct nf_conntrack_expect *exp)
167{
168	write_lock_bh(&nf_conntrack_lock);
169	if (del_timer(&exp->timeout)) {
170		nf_ct_unlink_expect(exp);
171		nf_ct_expect_put(exp);
172	}
173	write_unlock_bh(&nf_conntrack_lock);
174}
175EXPORT_SYMBOL_GPL(nf_ct_unexpect_related);
176
177/* We don't increase the master conntrack refcount for non-fulfilled
178 * conntracks. During the conntrack destruction, the expectations are
179 * always killed before the conntrack itself */
180struct nf_conntrack_expect *nf_ct_expect_alloc(struct nf_conn *me)
181{
182	struct nf_conntrack_expect *new;
183
184	new = kmem_cache_alloc(nf_ct_expect_cachep, GFP_ATOMIC);
185	if (!new)
186		return NULL;
187
188	new->master = me;
189	atomic_set(&new->use, 1);
190	return new;
191}
192EXPORT_SYMBOL_GPL(nf_ct_expect_alloc);
193
194void nf_ct_expect_init(struct nf_conntrack_expect *exp, int family,
195		       union nf_conntrack_address *saddr,
196		       union nf_conntrack_address *daddr,
197		       u_int8_t proto, __be16 *src, __be16 *dst)
198{
199	int len;
200
201	if (family == AF_INET)
202		len = 4;
203	else
204		len = 16;
205
206	exp->flags = 0;
207	exp->expectfn = NULL;
208	exp->helper = NULL;
209	exp->tuple.src.l3num = family;
210	exp->tuple.dst.protonum = proto;
211
212	if (saddr) {
213		memcpy(&exp->tuple.src.u3, saddr, len);
214		if (sizeof(exp->tuple.src.u3) > len)
215			/* address needs to be cleared for nf_ct_tuple_equal */
216			memset((void *)&exp->tuple.src.u3 + len, 0x00,
217			       sizeof(exp->tuple.src.u3) - len);
218		memset(&exp->mask.src.u3, 0xFF, len);
219		if (sizeof(exp->mask.src.u3) > len)
220			memset((void *)&exp->mask.src.u3 + len, 0x00,
221			       sizeof(exp->mask.src.u3) - len);
222	} else {
223		memset(&exp->tuple.src.u3, 0x00, sizeof(exp->tuple.src.u3));
224		memset(&exp->mask.src.u3, 0x00, sizeof(exp->mask.src.u3));
225	}
226
227	if (src) {
228		exp->tuple.src.u.all = (__force u16)*src;
229		exp->mask.src.u.all = 0xFFFF;
230	} else {
231		exp->tuple.src.u.all = 0;
232		exp->mask.src.u.all = 0;
233	}
234
235	memcpy(&exp->tuple.dst.u3, daddr, len);
236	if (sizeof(exp->tuple.dst.u3) > len)
237		/* address needs to be cleared for nf_ct_tuple_equal */
238		memset((void *)&exp->tuple.dst.u3 + len, 0x00,
239		       sizeof(exp->tuple.dst.u3) - len);
240
241	exp->tuple.dst.u.all = (__force u16)*dst;
242}
243EXPORT_SYMBOL_GPL(nf_ct_expect_init);
244
245void nf_ct_expect_put(struct nf_conntrack_expect *exp)
246{
247	if (atomic_dec_and_test(&exp->use))
248		kmem_cache_free(nf_ct_expect_cachep, exp);
249}
250EXPORT_SYMBOL_GPL(nf_ct_expect_put);
251
252static void nf_ct_expect_insert(struct nf_conntrack_expect *exp)
253{
254	struct nf_conn_help *master_help = nfct_help(exp->master);
255
256	atomic_inc(&exp->use);
257	master_help->expecting++;
258	list_add(&exp->list, &nf_ct_expect_list);
259
260	setup_timer(&exp->timeout, nf_ct_expectation_timed_out,
261		    (unsigned long)exp);
262	exp->timeout.expires = jiffies + master_help->helper->timeout * HZ;
263	add_timer(&exp->timeout);
264
265	exp->id = ++nf_ct_expect_next_id;
266	atomic_inc(&exp->use);
267	NF_CT_STAT_INC(expect_create);
268}
269
270/* Race with expectations being used means we could have none to find; OK. */
271static void evict_oldest_expect(struct nf_conn *master)
272{
273	struct nf_conntrack_expect *i;
274
275	list_for_each_entry_reverse(i, &nf_ct_expect_list, list) {
276		if (i->master == master) {
277			if (del_timer(&i->timeout)) {
278				nf_ct_unlink_expect(i);
279				nf_ct_expect_put(i);
280			}
281			break;
282		}
283	}
284}
285
286static inline int refresh_timer(struct nf_conntrack_expect *i)
287{
288	struct nf_conn_help *master_help = nfct_help(i->master);
289
290	if (!del_timer(&i->timeout))
291		return 0;
292
293	i->timeout.expires = jiffies + master_help->helper->timeout*HZ;
294	add_timer(&i->timeout);
295	return 1;
296}
297
298int nf_ct_expect_related(struct nf_conntrack_expect *expect)
299{
300	struct nf_conntrack_expect *i;
301	struct nf_conn *master = expect->master;
302	struct nf_conn_help *master_help = nfct_help(master);
303	int ret;
304
305	NF_CT_ASSERT(master_help);
306
307	write_lock_bh(&nf_conntrack_lock);
308	if (!master_help->helper) {
309		ret = -ESHUTDOWN;
310		goto out;
311	}
312	list_for_each_entry(i, &nf_ct_expect_list, list) {
313		if (expect_matches(i, expect)) {
314			/* Refresh timer: if it's dying, ignore.. */
315			if (refresh_timer(i)) {
316				ret = 0;
317				goto out;
318			}
319		} else if (expect_clash(i, expect)) {
320			ret = -EBUSY;
321			goto out;
322		}
323	}
324	/* Will be over limit? */
325	if (master_help->helper->max_expected &&
326	    master_help->expecting >= master_help->helper->max_expected)
327		evict_oldest_expect(master);
328
329	nf_ct_expect_insert(expect);
330	nf_ct_expect_event(IPEXP_NEW, expect);
331	ret = 0;
332out:
333	write_unlock_bh(&nf_conntrack_lock);
334	return ret;
335}
336EXPORT_SYMBOL_GPL(nf_ct_expect_related);
337
338#ifdef CONFIG_PROC_FS
339static void *exp_seq_start(struct seq_file *s, loff_t *pos)
340{
341	struct list_head *e = &nf_ct_expect_list;
342	loff_t i;
343
344	/* strange seq_file api calls stop even if we fail,
345	 * thus we need to grab lock since stop unlocks */
346	read_lock_bh(&nf_conntrack_lock);
347
348	if (list_empty(e))
349		return NULL;
350
351	for (i = 0; i <= *pos; i++) {
352		e = e->next;
353		if (e == &nf_ct_expect_list)
354			return NULL;
355	}
356	return e;
357}
358
359static void *exp_seq_next(struct seq_file *s, void *v, loff_t *pos)
360{
361	struct list_head *e = v;
362
363	++*pos;
364	e = e->next;
365
366	if (e == &nf_ct_expect_list)
367		return NULL;
368
369	return e;
370}
371
372static void exp_seq_stop(struct seq_file *s, void *v)
373{
374	read_unlock_bh(&nf_conntrack_lock);
375}
376
377static int exp_seq_show(struct seq_file *s, void *v)
378{
379	struct nf_conntrack_expect *expect = v;
380
381	if (expect->timeout.function)
382		seq_printf(s, "%ld ", timer_pending(&expect->timeout)
383			   ? (long)(expect->timeout.expires - jiffies)/HZ : 0);
384	else
385		seq_printf(s, "- ");
386	seq_printf(s, "l3proto = %u proto=%u ",
387		   expect->tuple.src.l3num,
388		   expect->tuple.dst.protonum);
389	print_tuple(s, &expect->tuple,
390		    __nf_ct_l3proto_find(expect->tuple.src.l3num),
391		    __nf_ct_l4proto_find(expect->tuple.src.l3num,
392				       expect->tuple.dst.protonum));
393	return seq_putc(s, '\n');
394}
395
396static struct seq_operations exp_seq_ops = {
397	.start = exp_seq_start,
398	.next = exp_seq_next,
399	.stop = exp_seq_stop,
400	.show = exp_seq_show
401};
402
403static int exp_open(struct inode *inode, struct file *file)
404{
405	return seq_open(file, &exp_seq_ops);
406}
407
408const struct file_operations exp_file_ops = {
409	.owner   = THIS_MODULE,
410	.open    = exp_open,
411	.read    = seq_read,
412	.llseek  = seq_lseek,
413	.release = seq_release
414};
415#endif /* CONFIG_PROC_FS */
416