netfilter: xtables: add struct xt_mtchk_param::net
[safe/jmp/linux-2.6] / net / ipv4 / netfilter / nf_conntrack_l3proto_ipv4_compat.c
1 /* ip_conntrack proc compat - based on ip_conntrack_standalone.c
2  *
3  * (C) 1999-2001 Paul `Rusty' Russell
4  * (C) 2002-2006 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 #include <linux/types.h>
11 #include <linux/proc_fs.h>
12 #include <linux/seq_file.h>
13 #include <linux/percpu.h>
14 #include <net/net_namespace.h>
15
16 #include <linux/netfilter.h>
17 #include <net/netfilter/nf_conntrack_core.h>
18 #include <net/netfilter/nf_conntrack_l3proto.h>
19 #include <net/netfilter/nf_conntrack_l4proto.h>
20 #include <net/netfilter/nf_conntrack_expect.h>
21 #include <net/netfilter/nf_conntrack_acct.h>
22
23 struct ct_iter_state {
24         struct seq_net_private p;
25         unsigned int bucket;
26 };
27
28 static struct hlist_nulls_node *ct_get_first(struct seq_file *seq)
29 {
30         struct net *net = seq_file_net(seq);
31         struct ct_iter_state *st = seq->private;
32         struct hlist_nulls_node *n;
33
34         for (st->bucket = 0;
35              st->bucket < nf_conntrack_htable_size;
36              st->bucket++) {
37                 n = rcu_dereference(net->ct.hash[st->bucket].first);
38                 if (!is_a_nulls(n))
39                         return n;
40         }
41         return NULL;
42 }
43
44 static struct hlist_nulls_node *ct_get_next(struct seq_file *seq,
45                                       struct hlist_nulls_node *head)
46 {
47         struct net *net = seq_file_net(seq);
48         struct ct_iter_state *st = seq->private;
49
50         head = rcu_dereference(head->next);
51         while (is_a_nulls(head)) {
52                 if (likely(get_nulls_value(head) == st->bucket)) {
53                         if (++st->bucket >= nf_conntrack_htable_size)
54                                 return NULL;
55                 }
56                 head = rcu_dereference(net->ct.hash[st->bucket].first);
57         }
58         return head;
59 }
60
61 static struct hlist_nulls_node *ct_get_idx(struct seq_file *seq, loff_t pos)
62 {
63         struct hlist_nulls_node *head = ct_get_first(seq);
64
65         if (head)
66                 while (pos && (head = ct_get_next(seq, head)))
67                         pos--;
68         return pos ? NULL : head;
69 }
70
71 static void *ct_seq_start(struct seq_file *seq, loff_t *pos)
72         __acquires(RCU)
73 {
74         rcu_read_lock();
75         return ct_get_idx(seq, *pos);
76 }
77
78 static void *ct_seq_next(struct seq_file *s, void *v, loff_t *pos)
79 {
80         (*pos)++;
81         return ct_get_next(s, v);
82 }
83
84 static void ct_seq_stop(struct seq_file *s, void *v)
85         __releases(RCU)
86 {
87         rcu_read_unlock();
88 }
89
90 static int ct_seq_show(struct seq_file *s, void *v)
91 {
92         struct nf_conntrack_tuple_hash *hash = v;
93         struct nf_conn *ct = nf_ct_tuplehash_to_ctrack(hash);
94         const struct nf_conntrack_l3proto *l3proto;
95         const struct nf_conntrack_l4proto *l4proto;
96         int ret = 0;
97
98         NF_CT_ASSERT(ct);
99         if (unlikely(!atomic_inc_not_zero(&ct->ct_general.use)))
100                 return 0;
101
102
103         /* we only want to print DIR_ORIGINAL */
104         if (NF_CT_DIRECTION(hash))
105                 goto release;
106         if (nf_ct_l3num(ct) != AF_INET)
107                 goto release;
108
109         l3proto = __nf_ct_l3proto_find(nf_ct_l3num(ct));
110         NF_CT_ASSERT(l3proto);
111         l4proto = __nf_ct_l4proto_find(nf_ct_l3num(ct), nf_ct_protonum(ct));
112         NF_CT_ASSERT(l4proto);
113
114         ret = -ENOSPC;
115         if (seq_printf(s, "%-8s %u %ld ",
116                       l4proto->name, nf_ct_protonum(ct),
117                       timer_pending(&ct->timeout)
118                       ? (long)(ct->timeout.expires - jiffies)/HZ : 0) != 0)
119                 goto release;
120
121         if (l4proto->print_conntrack && l4proto->print_conntrack(s, ct))
122                 goto release;
123
124         if (print_tuple(s, &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple,
125                         l3proto, l4proto))
126                 goto release;
127
128         if (seq_print_acct(s, ct, IP_CT_DIR_ORIGINAL))
129                 goto release;
130
131         if (!(test_bit(IPS_SEEN_REPLY_BIT, &ct->status)))
132                 if (seq_printf(s, "[UNREPLIED] "))
133                         goto release;
134
135         if (print_tuple(s, &ct->tuplehash[IP_CT_DIR_REPLY].tuple,
136                         l3proto, l4proto))
137                 goto release;
138
139         if (seq_print_acct(s, ct, IP_CT_DIR_REPLY))
140                 goto release;
141
142         if (test_bit(IPS_ASSURED_BIT, &ct->status))
143                 if (seq_printf(s, "[ASSURED] "))
144                         goto release;
145
146 #ifdef CONFIG_NF_CONNTRACK_MARK
147         if (seq_printf(s, "mark=%u ", ct->mark))
148                 goto release;
149 #endif
150
151 #ifdef CONFIG_NF_CONNTRACK_SECMARK
152         if (seq_printf(s, "secmark=%u ", ct->secmark))
153                 goto release;
154 #endif
155
156         if (seq_printf(s, "use=%u\n", atomic_read(&ct->ct_general.use)))
157                 goto release;
158         ret = 0;
159 release:
160         nf_ct_put(ct);
161         return ret;
162 }
163
164 static const struct seq_operations ct_seq_ops = {
165         .start = ct_seq_start,
166         .next  = ct_seq_next,
167         .stop  = ct_seq_stop,
168         .show  = ct_seq_show
169 };
170
171 static int ct_open(struct inode *inode, struct file *file)
172 {
173         return seq_open_net(inode, file, &ct_seq_ops,
174                             sizeof(struct ct_iter_state));
175 }
176
177 static const struct file_operations ct_file_ops = {
178         .owner   = THIS_MODULE,
179         .open    = ct_open,
180         .read    = seq_read,
181         .llseek  = seq_lseek,
182         .release = seq_release_net,
183 };
184
185 /* expects */
186 struct ct_expect_iter_state {
187         struct seq_net_private p;
188         unsigned int bucket;
189 };
190
191 static struct hlist_node *ct_expect_get_first(struct seq_file *seq)
192 {
193         struct net *net = seq_file_net(seq);
194         struct ct_expect_iter_state *st = seq->private;
195         struct hlist_node *n;
196
197         for (st->bucket = 0; st->bucket < nf_ct_expect_hsize; st->bucket++) {
198                 n = rcu_dereference(net->ct.expect_hash[st->bucket].first);
199                 if (n)
200                         return n;
201         }
202         return NULL;
203 }
204
205 static struct hlist_node *ct_expect_get_next(struct seq_file *seq,
206                                              struct hlist_node *head)
207 {
208         struct net *net = seq_file_net(seq);
209         struct ct_expect_iter_state *st = seq->private;
210
211         head = rcu_dereference(head->next);
212         while (head == NULL) {
213                 if (++st->bucket >= nf_ct_expect_hsize)
214                         return NULL;
215                 head = rcu_dereference(net->ct.expect_hash[st->bucket].first);
216         }
217         return head;
218 }
219
220 static struct hlist_node *ct_expect_get_idx(struct seq_file *seq, loff_t pos)
221 {
222         struct hlist_node *head = ct_expect_get_first(seq);
223
224         if (head)
225                 while (pos && (head = ct_expect_get_next(seq, head)))
226                         pos--;
227         return pos ? NULL : head;
228 }
229
230 static void *exp_seq_start(struct seq_file *seq, loff_t *pos)
231         __acquires(RCU)
232 {
233         rcu_read_lock();
234         return ct_expect_get_idx(seq, *pos);
235 }
236
237 static void *exp_seq_next(struct seq_file *seq, void *v, loff_t *pos)
238 {
239         (*pos)++;
240         return ct_expect_get_next(seq, v);
241 }
242
243 static void exp_seq_stop(struct seq_file *seq, void *v)
244         __releases(RCU)
245 {
246         rcu_read_unlock();
247 }
248
249 static int exp_seq_show(struct seq_file *s, void *v)
250 {
251         struct nf_conntrack_expect *exp;
252         const struct hlist_node *n = v;
253
254         exp = hlist_entry(n, struct nf_conntrack_expect, hnode);
255
256         if (exp->tuple.src.l3num != AF_INET)
257                 return 0;
258
259         if (exp->timeout.function)
260                 seq_printf(s, "%ld ", timer_pending(&exp->timeout)
261                            ? (long)(exp->timeout.expires - jiffies)/HZ : 0);
262         else
263                 seq_printf(s, "- ");
264
265         seq_printf(s, "proto=%u ", exp->tuple.dst.protonum);
266
267         print_tuple(s, &exp->tuple,
268                     __nf_ct_l3proto_find(exp->tuple.src.l3num),
269                     __nf_ct_l4proto_find(exp->tuple.src.l3num,
270                                          exp->tuple.dst.protonum));
271         return seq_putc(s, '\n');
272 }
273
274 static const struct seq_operations exp_seq_ops = {
275         .start = exp_seq_start,
276         .next = exp_seq_next,
277         .stop = exp_seq_stop,
278         .show = exp_seq_show
279 };
280
281 static int exp_open(struct inode *inode, struct file *file)
282 {
283         return seq_open_net(inode, file, &exp_seq_ops,
284                             sizeof(struct ct_expect_iter_state));
285 }
286
287 static const struct file_operations ip_exp_file_ops = {
288         .owner   = THIS_MODULE,
289         .open    = exp_open,
290         .read    = seq_read,
291         .llseek  = seq_lseek,
292         .release = seq_release_net,
293 };
294
295 static void *ct_cpu_seq_start(struct seq_file *seq, loff_t *pos)
296 {
297         struct net *net = seq_file_net(seq);
298         int cpu;
299
300         if (*pos == 0)
301                 return SEQ_START_TOKEN;
302
303         for (cpu = *pos-1; cpu < nr_cpu_ids; ++cpu) {
304                 if (!cpu_possible(cpu))
305                         continue;
306                 *pos = cpu+1;
307                 return per_cpu_ptr(net->ct.stat, cpu);
308         }
309
310         return NULL;
311 }
312
313 static void *ct_cpu_seq_next(struct seq_file *seq, void *v, loff_t *pos)
314 {
315         struct net *net = seq_file_net(seq);
316         int cpu;
317
318         for (cpu = *pos; cpu < nr_cpu_ids; ++cpu) {
319                 if (!cpu_possible(cpu))
320                         continue;
321                 *pos = cpu+1;
322                 return per_cpu_ptr(net->ct.stat, cpu);
323         }
324
325         return NULL;
326 }
327
328 static void ct_cpu_seq_stop(struct seq_file *seq, void *v)
329 {
330 }
331
332 static int ct_cpu_seq_show(struct seq_file *seq, void *v)
333 {
334         struct net *net = seq_file_net(seq);
335         unsigned int nr_conntracks = atomic_read(&net->ct.count);
336         const struct ip_conntrack_stat *st = v;
337
338         if (v == SEQ_START_TOKEN) {
339                 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");
340                 return 0;
341         }
342
343         seq_printf(seq, "%08x  %08x %08x %08x %08x %08x %08x %08x "
344                         "%08x %08x %08x %08x %08x  %08x %08x %08x \n",
345                    nr_conntracks,
346                    st->searched,
347                    st->found,
348                    st->new,
349                    st->invalid,
350                    st->ignore,
351                    st->delete,
352                    st->delete_list,
353                    st->insert,
354                    st->insert_failed,
355                    st->drop,
356                    st->early_drop,
357                    st->error,
358
359                    st->expect_new,
360                    st->expect_create,
361                    st->expect_delete
362                 );
363         return 0;
364 }
365
366 static const struct seq_operations ct_cpu_seq_ops = {
367         .start  = ct_cpu_seq_start,
368         .next   = ct_cpu_seq_next,
369         .stop   = ct_cpu_seq_stop,
370         .show   = ct_cpu_seq_show,
371 };
372
373 static int ct_cpu_seq_open(struct inode *inode, struct file *file)
374 {
375         return seq_open_net(inode, file, &ct_cpu_seq_ops,
376                             sizeof(struct seq_net_private));
377 }
378
379 static const struct file_operations ct_cpu_seq_fops = {
380         .owner   = THIS_MODULE,
381         .open    = ct_cpu_seq_open,
382         .read    = seq_read,
383         .llseek  = seq_lseek,
384         .release = seq_release_net,
385 };
386
387 static int __net_init ip_conntrack_net_init(struct net *net)
388 {
389         struct proc_dir_entry *proc, *proc_exp, *proc_stat;
390
391         proc = proc_net_fops_create(net, "ip_conntrack", 0440, &ct_file_ops);
392         if (!proc)
393                 goto err1;
394
395         proc_exp = proc_net_fops_create(net, "ip_conntrack_expect", 0440,
396                                         &ip_exp_file_ops);
397         if (!proc_exp)
398                 goto err2;
399
400         proc_stat = proc_create("ip_conntrack", S_IRUGO,
401                                 net->proc_net_stat, &ct_cpu_seq_fops);
402         if (!proc_stat)
403                 goto err3;
404         return 0;
405
406 err3:
407         proc_net_remove(net, "ip_conntrack_expect");
408 err2:
409         proc_net_remove(net, "ip_conntrack");
410 err1:
411         return -ENOMEM;
412 }
413
414 static void __net_exit ip_conntrack_net_exit(struct net *net)
415 {
416         remove_proc_entry("ip_conntrack", net->proc_net_stat);
417         proc_net_remove(net, "ip_conntrack_expect");
418         proc_net_remove(net, "ip_conntrack");
419 }
420
421 static struct pernet_operations ip_conntrack_net_ops = {
422         .init = ip_conntrack_net_init,
423         .exit = ip_conntrack_net_exit,
424 };
425
426 int __init nf_conntrack_ipv4_compat_init(void)
427 {
428         return register_pernet_subsys(&ip_conntrack_net_ops);
429 }
430
431 void __exit nf_conntrack_ipv4_compat_fini(void)
432 {
433         unregister_pernet_subsys(&ip_conntrack_net_ops);
434 }