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