netfilter: conntrack: merge acct and helper sysctl table with main one
[linux-2.6-block.git] / net / netfilter / nf_conntrack_standalone.c
CommitLineData
a0ae2562 1// SPDX-License-Identifier: GPL-2.0
9fb9cbb1
YK
2#include <linux/types.h>
3#include <linux/netfilter.h>
5a0e3ad6 4#include <linux/slab.h>
9fb9cbb1
YK
5#include <linux/module.h>
6#include <linux/skbuff.h>
7#include <linux/proc_fs.h>
8#include <linux/seq_file.h>
9#include <linux/percpu.h>
10#include <linux/netdevice.h>
1ae4de0c 11#include <linux/security.h>
457c4cbc 12#include <net/net_namespace.h>
9fb9cbb1
YK
13#ifdef CONFIG_SYSCTL
14#include <linux/sysctl.h>
15#endif
16
9fb9cbb1 17#include <net/netfilter/nf_conntrack.h>
f6180121 18#include <net/netfilter/nf_conntrack_core.h>
605dcad6 19#include <net/netfilter/nf_conntrack_l4proto.h>
77ab9cff 20#include <net/netfilter/nf_conntrack_expect.h>
9fb9cbb1 21#include <net/netfilter/nf_conntrack_helper.h>
58401572 22#include <net/netfilter/nf_conntrack_acct.h>
5d0aa2cc 23#include <net/netfilter/nf_conntrack_zones.h>
a992ca2a 24#include <net/netfilter/nf_conntrack_timestamp.h>
0e60ebe0 25#include <linux/rculist_nulls.h>
9fb9cbb1 26
a0ae2562 27unsigned int nf_conntrack_net_id __read_mostly;
9fb9cbb1 28
54b07dca 29#ifdef CONFIG_NF_CONNTRACK_PROCFS
824f1fbe 30void
9fb9cbb1 31print_tuple(struct seq_file *s, const struct nf_conntrack_tuple *tuple,
32948588 32 const struct nf_conntrack_l4proto *l4proto)
9fb9cbb1 33{
f957be9d 34 switch (tuple->src.l3num) {
91950833
FW
35 case NFPROTO_IPV4:
36 seq_printf(s, "src=%pI4 dst=%pI4 ",
37 &tuple->src.u3.ip, &tuple->dst.u3.ip);
38 break;
39 case NFPROTO_IPV6:
40 seq_printf(s, "src=%pI6 dst=%pI6 ",
41 tuple->src.u3.ip6, tuple->dst.u3.ip6);
42 break;
43 default:
44 break;
45 }
46
47 switch (l4proto->l4proto) {
48 case IPPROTO_ICMP:
49 seq_printf(s, "type=%u code=%u id=%u ",
50 tuple->dst.u.icmp.type,
51 tuple->dst.u.icmp.code,
52 ntohs(tuple->src.u.icmp.id));
53 break;
54 case IPPROTO_TCP:
55 seq_printf(s, "sport=%hu dport=%hu ",
56 ntohs(tuple->src.u.tcp.port),
57 ntohs(tuple->dst.u.tcp.port));
58 break;
59 case IPPROTO_UDPLITE: /* fallthrough */
60 case IPPROTO_UDP:
61 seq_printf(s, "sport=%hu dport=%hu ",
62 ntohs(tuple->src.u.udp.port),
63 ntohs(tuple->dst.u.udp.port));
64
65 break;
66 case IPPROTO_DCCP:
67 seq_printf(s, "sport=%hu dport=%hu ",
68 ntohs(tuple->src.u.dccp.port),
69 ntohs(tuple->dst.u.dccp.port));
70 break;
71 case IPPROTO_SCTP:
72 seq_printf(s, "sport=%hu dport=%hu ",
73 ntohs(tuple->src.u.sctp.port),
74 ntohs(tuple->dst.u.sctp.port));
75 break;
76 case IPPROTO_ICMPV6:
77 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 break;
82 case IPPROTO_GRE:
83 seq_printf(s, "srckey=0x%x dstkey=0x%x ",
84 ntohs(tuple->src.u.gre.key),
85 ntohs(tuple->dst.u.gre.key));
86 break;
87 default:
88 break;
89 }
9fb9cbb1 90}
e4bd8bce 91EXPORT_SYMBOL_GPL(print_tuple);
9fb9cbb1 92
9fb9cbb1 93struct ct_iter_state {
b2ce2c74 94 struct seq_net_private p;
64b87639
LZ
95 struct hlist_nulls_head *hash;
96 unsigned int htable_size;
9fb9cbb1 97 unsigned int bucket;
a992ca2a 98 u_int64_t time_now;
9fb9cbb1
YK
99};
100
ea781f19 101static struct hlist_nulls_node *ct_get_first(struct seq_file *seq)
9fb9cbb1
YK
102{
103 struct ct_iter_state *st = seq->private;
ea781f19 104 struct hlist_nulls_node *n;
9fb9cbb1
YK
105
106 for (st->bucket = 0;
64b87639 107 st->bucket < st->htable_size;
9fb9cbb1 108 st->bucket++) {
64b87639
LZ
109 n = rcu_dereference(
110 hlist_nulls_first_rcu(&st->hash[st->bucket]));
ea781f19 111 if (!is_a_nulls(n))
76507f69 112 return n;
9fb9cbb1
YK
113 }
114 return NULL;
115}
116
ea781f19
ED
117static struct hlist_nulls_node *ct_get_next(struct seq_file *seq,
118 struct hlist_nulls_node *head)
9fb9cbb1
YK
119{
120 struct ct_iter_state *st = seq->private;
121
0e60ebe0 122 head = rcu_dereference(hlist_nulls_next_rcu(head));
ea781f19
ED
123 while (is_a_nulls(head)) {
124 if (likely(get_nulls_value(head) == st->bucket)) {
64b87639 125 if (++st->bucket >= st->htable_size)
ea781f19
ED
126 return NULL;
127 }
0e60ebe0 128 head = rcu_dereference(
64b87639 129 hlist_nulls_first_rcu(&st->hash[st->bucket]));
9fb9cbb1
YK
130 }
131 return head;
132}
133
ea781f19 134static struct hlist_nulls_node *ct_get_idx(struct seq_file *seq, loff_t pos)
9fb9cbb1 135{
ea781f19 136 struct hlist_nulls_node *head = ct_get_first(seq);
9fb9cbb1
YK
137
138 if (head)
139 while (pos && (head = ct_get_next(seq, head)))
140 pos--;
141 return pos ? NULL : head;
142}
143
144static void *ct_seq_start(struct seq_file *seq, loff_t *pos)
76507f69 145 __acquires(RCU)
9fb9cbb1 146{
a992ca2a
PNA
147 struct ct_iter_state *st = seq->private;
148
d2de875c 149 st->time_now = ktime_get_real_ns();
76507f69 150 rcu_read_lock();
64b87639
LZ
151
152 nf_conntrack_get_ht(&st->hash, &st->htable_size);
9fb9cbb1
YK
153 return ct_get_idx(seq, *pos);
154}
155
156static void *ct_seq_next(struct seq_file *s, void *v, loff_t *pos)
157{
158 (*pos)++;
159 return ct_get_next(s, v);
160}
161
162static void ct_seq_stop(struct seq_file *s, void *v)
76507f69 163 __releases(RCU)
9fb9cbb1 164{
76507f69 165 rcu_read_unlock();
9fb9cbb1
YK
166}
167
1ae4de0c 168#ifdef CONFIG_NF_CONNTRACK_SECMARK
e71456ae 169static void ct_show_secctx(struct seq_file *s, const struct nf_conn *ct)
1ae4de0c
EP
170{
171 int ret;
172 u32 len;
173 char *secctx;
174
175 ret = security_secid_to_secctx(ct->secmark, &secctx, &len);
176 if (ret)
e71456ae 177 return;
1ae4de0c 178
e71456ae 179 seq_printf(s, "secctx=%s ", secctx);
1ae4de0c
EP
180
181 security_release_secctx(secctx, len);
1ae4de0c
EP
182}
183#else
e71456ae 184static inline void ct_show_secctx(struct seq_file *s, const struct nf_conn *ct)
1ae4de0c 185{
1ae4de0c
EP
186}
187#endif
188
308ac914 189#ifdef CONFIG_NF_CONNTRACK_ZONES
deedb590
DB
190static void ct_show_zone(struct seq_file *s, const struct nf_conn *ct,
191 int dir)
308ac914 192{
deedb590
DB
193 const struct nf_conntrack_zone *zone = nf_ct_zone(ct);
194
195 if (zone->dir != dir)
196 return;
197 switch (zone->dir) {
198 case NF_CT_DEFAULT_ZONE_DIR:
199 seq_printf(s, "zone=%u ", zone->id);
200 break;
201 case NF_CT_ZONE_DIR_ORIG:
202 seq_printf(s, "zone-orig=%u ", zone->id);
203 break;
204 case NF_CT_ZONE_DIR_REPL:
205 seq_printf(s, "zone-reply=%u ", zone->id);
206 break;
207 default:
208 break;
209 }
308ac914
DB
210}
211#else
deedb590
DB
212static inline void ct_show_zone(struct seq_file *s, const struct nf_conn *ct,
213 int dir)
308ac914
DB
214{
215}
216#endif
217
a992ca2a 218#ifdef CONFIG_NF_CONNTRACK_TIMESTAMP
e71456ae 219static void ct_show_delta_time(struct seq_file *s, const struct nf_conn *ct)
a992ca2a 220{
f5c88f56 221 struct ct_iter_state *st = s->private;
a992ca2a 222 struct nf_conn_tstamp *tstamp;
f5c88f56 223 s64 delta_time;
a992ca2a
PNA
224
225 tstamp = nf_conn_tstamp_find(ct);
226 if (tstamp) {
f5c88f56
PM
227 delta_time = st->time_now - tstamp->start;
228 if (delta_time > 0)
229 delta_time = div_s64(delta_time, NSEC_PER_SEC);
230 else
231 delta_time = 0;
232
e71456ae
SRRH
233 seq_printf(s, "delta-time=%llu ",
234 (unsigned long long)delta_time);
a992ca2a 235 }
e71456ae 236 return;
a992ca2a
PNA
237}
238#else
e71456ae 239static inline void
a992ca2a
PNA
240ct_show_delta_time(struct seq_file *s, const struct nf_conn *ct)
241{
a992ca2a
PNA
242}
243#endif
244
a3134d53
FW
245static const char* l3proto_name(u16 proto)
246{
247 switch (proto) {
248 case AF_INET: return "ipv4";
249 case AF_INET6: return "ipv6";
250 }
251
252 return "unknown";
253}
254
09ec82f5
FW
255static const char* l4proto_name(u16 proto)
256{
257 switch (proto) {
258 case IPPROTO_ICMP: return "icmp";
259 case IPPROTO_TCP: return "tcp";
260 case IPPROTO_UDP: return "udp";
261 case IPPROTO_DCCP: return "dccp";
262 case IPPROTO_GRE: return "gre";
263 case IPPROTO_SCTP: return "sctp";
264 case IPPROTO_UDPLITE: return "udplite";
265 }
266
267 return "unknown";
268}
269
4b216e21
FW
270static unsigned int
271seq_print_acct(struct seq_file *s, const struct nf_conn *ct, int dir)
272{
273 struct nf_conn_acct *acct;
274 struct nf_conn_counter *counter;
275
276 acct = nf_conn_acct_find(ct);
277 if (!acct)
278 return 0;
279
280 counter = acct->counter;
281 seq_printf(s, "packets=%llu bytes=%llu ",
282 (unsigned long long)atomic64_read(&counter[dir].packets),
283 (unsigned long long)atomic64_read(&counter[dir].bytes));
284
285 return 0;
286}
287
9fb9cbb1
YK
288/* return 0 on success, 1 in case of error */
289static int ct_seq_show(struct seq_file *s, void *v)
290{
ea781f19
ED
291 struct nf_conntrack_tuple_hash *hash = v;
292 struct nf_conn *ct = nf_ct_tuplehash_to_ctrack(hash);
32948588 293 const struct nf_conntrack_l4proto *l4proto;
e77e6ff5 294 struct net *net = seq_file_net(s);
ea781f19 295 int ret = 0;
9fb9cbb1 296
44d6e2f2 297 WARN_ON(!ct);
ea781f19
ED
298 if (unlikely(!atomic_inc_not_zero(&ct->ct_general.use)))
299 return 0;
9fb9cbb1 300
58e207e4
FW
301 if (nf_ct_should_gc(ct)) {
302 nf_ct_kill(ct);
303 goto release;
304 }
305
9fb9cbb1
YK
306 /* we only want to print DIR_ORIGINAL */
307 if (NF_CT_DIRECTION(hash))
ea781f19 308 goto release;
9fb9cbb1 309
e77e6ff5
LZ
310 if (!net_eq(nf_ct_net(ct), net))
311 goto release;
312
dd2934a9 313 l4proto = __nf_ct_l4proto_find(nf_ct_protonum(ct));
44d6e2f2 314 WARN_ON(!l4proto);
9fb9cbb1 315
ea781f19 316 ret = -ENOSPC;
90964016 317 seq_printf(s, "%-8s %u %-8s %u ",
f957be9d 318 l3proto_name(nf_ct_l3num(ct)), nf_ct_l3num(ct),
90964016
PNA
319 l4proto_name(l4proto->l4proto), nf_ct_protonum(ct));
320
321 if (!test_bit(IPS_OFFLOAD_BIT, &ct->status))
322 seq_printf(s, "%ld ", nf_ct_expires(ct) / HZ);
9fb9cbb1 323
37246a58
SRRH
324 if (l4proto->print_conntrack)
325 l4proto->print_conntrack(s, ct);
9fb9cbb1 326
824f1fbe 327 print_tuple(s, &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple,
f957be9d 328 l4proto);
9fb9cbb1 329
deedb590
DB
330 ct_show_zone(s, ct, NF_CT_ZONE_DIR_ORIG);
331
e71456ae
SRRH
332 if (seq_has_overflowed(s))
333 goto release;
334
58401572 335 if (seq_print_acct(s, ct, IP_CT_DIR_ORIGINAL))
ea781f19 336 goto release;
9fb9cbb1 337
c88130bc 338 if (!(test_bit(IPS_SEEN_REPLY_BIT, &ct->status)))
cdec2685 339 seq_puts(s, "[UNREPLIED] ");
9fb9cbb1 340
f957be9d 341 print_tuple(s, &ct->tuplehash[IP_CT_DIR_REPLY].tuple, l4proto);
9fb9cbb1 342
deedb590
DB
343 ct_show_zone(s, ct, NF_CT_ZONE_DIR_REPL);
344
58401572 345 if (seq_print_acct(s, ct, IP_CT_DIR_REPLY))
ea781f19 346 goto release;
9fb9cbb1 347
90964016
PNA
348 if (test_bit(IPS_OFFLOAD_BIT, &ct->status))
349 seq_puts(s, "[OFFLOAD] ");
350 else if (test_bit(IPS_ASSURED_BIT, &ct->status))
cdec2685 351 seq_puts(s, "[ASSURED] ");
9fb9cbb1 352
e71456ae 353 if (seq_has_overflowed(s))
ea781f19 354 goto release;
e71456ae
SRRH
355
356#if defined(CONFIG_NF_CONNTRACK_MARK)
357 seq_printf(s, "mark=%u ", ct->mark);
9fb9cbb1
YK
358#endif
359
e71456ae 360 ct_show_secctx(s, ct);
deedb590 361 ct_show_zone(s, ct, NF_CT_DEFAULT_ZONE_DIR);
e71456ae
SRRH
362 ct_show_delta_time(s, ct);
363
364 seq_printf(s, "use=%u\n", atomic_read(&ct->ct_general.use));
a992ca2a 365
e71456ae 366 if (seq_has_overflowed(s))
ea781f19 367 goto release;
a5d29264 368
ea781f19
ED
369 ret = 0;
370release:
371 nf_ct_put(ct);
d88d7de0 372 return ret;
9fb9cbb1
YK
373}
374
56b3d975 375static const struct seq_operations ct_seq_ops = {
9fb9cbb1
YK
376 .start = ct_seq_start,
377 .next = ct_seq_next,
378 .stop = ct_seq_stop,
379 .show = ct_seq_show
380};
381
9fb9cbb1
YK
382static void *ct_cpu_seq_start(struct seq_file *seq, loff_t *pos)
383{
8e9df801 384 struct net *net = seq_file_net(seq);
9fb9cbb1
YK
385 int cpu;
386
387 if (*pos == 0)
388 return SEQ_START_TOKEN;
389
0f23174a 390 for (cpu = *pos-1; cpu < nr_cpu_ids; ++cpu) {
9fb9cbb1
YK
391 if (!cpu_possible(cpu))
392 continue;
393 *pos = cpu + 1;
8e9df801 394 return per_cpu_ptr(net->ct.stat, cpu);
9fb9cbb1
YK
395 }
396
397 return NULL;
398}
399
400static void *ct_cpu_seq_next(struct seq_file *seq, void *v, loff_t *pos)
401{
8e9df801 402 struct net *net = seq_file_net(seq);
9fb9cbb1
YK
403 int cpu;
404
0f23174a 405 for (cpu = *pos; cpu < nr_cpu_ids; ++cpu) {
9fb9cbb1
YK
406 if (!cpu_possible(cpu))
407 continue;
408 *pos = cpu + 1;
8e9df801 409 return per_cpu_ptr(net->ct.stat, cpu);
9fb9cbb1
YK
410 }
411
412 return NULL;
413}
414
415static void ct_cpu_seq_stop(struct seq_file *seq, void *v)
416{
417}
418
419static int ct_cpu_seq_show(struct seq_file *seq, void *v)
420{
8e9df801
AD
421 struct net *net = seq_file_net(seq);
422 unsigned int nr_conntracks = atomic_read(&net->ct.count);
32948588 423 const struct ip_conntrack_stat *st = v;
9fb9cbb1
YK
424
425 if (v == SEQ_START_TOKEN) {
cdec2685 426 seq_puts(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");
9fb9cbb1
YK
427 return 0;
428 }
429
430 seq_printf(seq, "%08x %08x %08x %08x %08x %08x %08x %08x "
af740b2c 431 "%08x %08x %08x %08x %08x %08x %08x %08x %08x\n",
9fb9cbb1 432 nr_conntracks,
8e8118f8 433 0,
9fb9cbb1 434 st->found,
8e8118f8 435 0,
9fb9cbb1
YK
436 st->invalid,
437 st->ignore,
8e8118f8
FW
438 0,
439 0,
9fb9cbb1
YK
440 st->insert,
441 st->insert_failed,
442 st->drop,
443 st->early_drop,
444 st->error,
445
446 st->expect_new,
447 st->expect_create,
af740b2c
JDB
448 st->expect_delete,
449 st->search_restart
9fb9cbb1
YK
450 );
451 return 0;
452}
453
56b3d975 454static const struct seq_operations ct_cpu_seq_ops = {
9fb9cbb1
YK
455 .start = ct_cpu_seq_start,
456 .next = ct_cpu_seq_next,
457 .stop = ct_cpu_seq_stop,
458 .show = ct_cpu_seq_show,
459};
460
b2ce2c74 461static int nf_conntrack_standalone_init_proc(struct net *net)
b916f7d4
AD
462{
463 struct proc_dir_entry *pde;
f13f2aee
PW
464 kuid_t root_uid;
465 kgid_t root_gid;
b916f7d4 466
c3506372
CH
467 pde = proc_create_net("nf_conntrack", 0440, net->proc_net, &ct_seq_ops,
468 sizeof(struct ct_iter_state));
b916f7d4
AD
469 if (!pde)
470 goto out_nf_conntrack;
52c0e111 471
f13f2aee
PW
472 root_uid = make_kuid(net->user_ns, 0);
473 root_gid = make_kgid(net->user_ns, 0);
474 if (uid_valid(root_uid) && gid_valid(root_gid))
475 proc_set_user(pde, root_uid, root_gid);
476
c3506372
CH
477 pde = proc_create_net("nf_conntrack", 0444, net->proc_net_stat,
478 &ct_cpu_seq_ops, sizeof(struct seq_net_private));
b916f7d4
AD
479 if (!pde)
480 goto out_stat_nf_conntrack;
b916f7d4
AD
481 return 0;
482
483out_stat_nf_conntrack:
ece31ffd 484 remove_proc_entry("nf_conntrack", net->proc_net);
b916f7d4
AD
485out_nf_conntrack:
486 return -ENOMEM;
487}
488
b2ce2c74 489static void nf_conntrack_standalone_fini_proc(struct net *net)
b916f7d4 490{
b2ce2c74 491 remove_proc_entry("nf_conntrack", net->proc_net_stat);
ece31ffd 492 remove_proc_entry("nf_conntrack", net->proc_net);
b916f7d4
AD
493}
494#else
b2ce2c74 495static int nf_conntrack_standalone_init_proc(struct net *net)
b916f7d4
AD
496{
497 return 0;
498}
499
b2ce2c74 500static void nf_conntrack_standalone_fini_proc(struct net *net)
b916f7d4
AD
501{
502}
54b07dca 503#endif /* CONFIG_NF_CONNTRACK_PROCFS */
9fb9cbb1
YK
504
505/* Sysctl support */
506
507#ifdef CONFIG_SYSCTL
9fb9cbb1 508/* Log invalid packets of a given protocol */
3183ab89
FW
509static int log_invalid_proto_min __read_mostly;
510static int log_invalid_proto_max __read_mostly = 255;
511
512/* size the user *wants to set */
513static unsigned int nf_conntrack_htable_size_user __read_mostly;
514
515static int
516nf_conntrack_hash_sysctl(struct ctl_table *table, int write,
517 void __user *buffer, size_t *lenp, loff_t *ppos)
518{
519 int ret;
520
521 ret = proc_dointvec(table, write, buffer, lenp, ppos);
522 if (ret < 0 || !write)
523 return ret;
524
525 /* update ret, we might not be able to satisfy request */
526 ret = nf_conntrack_hash_resize(nf_conntrack_htable_size_user);
527
528 /* update it to the actual value used by conntrack */
529 nf_conntrack_htable_size_user = nf_conntrack_htable_size;
530 return ret;
531}
9fb9cbb1 532
9714be7d 533static struct ctl_table_header *nf_ct_netfilter_header;
9fb9cbb1 534
4a65798a
FW
535enum nf_ct_sysctl_index {
536 NF_SYSCTL_CT_MAX,
537 NF_SYSCTL_CT_COUNT,
538 NF_SYSCTL_CT_BUCKETS,
539 NF_SYSCTL_CT_CHECKSUM,
540 NF_SYSCTL_CT_LOG_INVALID,
541 NF_SYSCTL_CT_EXPECT_MAX,
d912dec1
FW
542 NF_SYSCTL_CT_ACCT,
543 NF_SYSCTL_CT_HELPER,
4a65798a
FW
544};
545
fe2c6338 546static struct ctl_table nf_ct_sysctl_table[] = {
4a65798a 547 [NF_SYSCTL_CT_MAX] = {
9fb9cbb1
YK
548 .procname = "nf_conntrack_max",
549 .data = &nf_conntrack_max,
550 .maxlen = sizeof(int),
551 .mode = 0644,
6d9f239a 552 .proc_handler = proc_dointvec,
9fb9cbb1 553 },
4a65798a 554 [NF_SYSCTL_CT_COUNT] = {
9fb9cbb1 555 .procname = "nf_conntrack_count",
49ac8713 556 .data = &init_net.ct.count,
9fb9cbb1
YK
557 .maxlen = sizeof(int),
558 .mode = 0444,
6d9f239a 559 .proc_handler = proc_dointvec,
9fb9cbb1 560 },
4a65798a 561 [NF_SYSCTL_CT_BUCKETS] = {
9fb9cbb1 562 .procname = "nf_conntrack_buckets",
3183ab89 563 .data = &nf_conntrack_htable_size_user,
9fb9cbb1 564 .maxlen = sizeof(unsigned int),
3183ab89
FW
565 .mode = 0644,
566 .proc_handler = nf_conntrack_hash_sysctl,
9fb9cbb1 567 },
4a65798a 568 [NF_SYSCTL_CT_CHECKSUM] = {
39a27a35 569 .procname = "nf_conntrack_checksum",
c04d0552 570 .data = &init_net.ct.sysctl_checksum,
39a27a35
PM
571 .maxlen = sizeof(unsigned int),
572 .mode = 0644,
6d9f239a 573 .proc_handler = proc_dointvec,
39a27a35 574 },
4a65798a 575 [NF_SYSCTL_CT_LOG_INVALID] = {
9fb9cbb1 576 .procname = "nf_conntrack_log_invalid",
c2a2c7e0 577 .data = &init_net.ct.sysctl_log_invalid,
9fb9cbb1
YK
578 .maxlen = sizeof(unsigned int),
579 .mode = 0644,
6d9f239a 580 .proc_handler = proc_dointvec_minmax,
9fb9cbb1
YK
581 .extra1 = &log_invalid_proto_min,
582 .extra2 = &log_invalid_proto_max,
583 },
4a65798a 584 [NF_SYSCTL_CT_EXPECT_MAX] = {
f264a7df
PM
585 .procname = "nf_conntrack_expect_max",
586 .data = &nf_ct_expect_max,
587 .maxlen = sizeof(int),
588 .mode = 0644,
6d9f239a 589 .proc_handler = proc_dointvec,
f264a7df 590 },
d912dec1
FW
591 [NF_SYSCTL_CT_ACCT] = {
592 .procname = "nf_conntrack_acct",
593 .data = &init_net.ct.sysctl_acct,
594 .maxlen = sizeof(unsigned int),
595 .mode = 0644,
596 .proc_handler = proc_dointvec,
597 },
598 [NF_SYSCTL_CT_HELPER] = {
599 .procname = "nf_conntrack_helper",
600 .data = &init_net.ct.sysctl_auto_assign_helper,
601 .maxlen = sizeof(unsigned int),
602 .mode = 0644,
603 .proc_handler = proc_dointvec,
604 },
f8572d8f 605 { }
9fb9cbb1
YK
606};
607
fe2c6338 608static struct ctl_table nf_ct_netfilter_table[] = {
9fb9cbb1 609 {
9fb9cbb1
YK
610 .procname = "nf_conntrack_max",
611 .data = &nf_conntrack_max,
612 .maxlen = sizeof(int),
613 .mode = 0644,
6d9f239a 614 .proc_handler = proc_dointvec,
9fb9cbb1 615 },
f8572d8f 616 { }
9fb9cbb1
YK
617};
618
80250707 619static int nf_conntrack_standalone_init_sysctl(struct net *net)
b916f7d4 620{
80250707
AD
621 struct ctl_table *table;
622
80250707
AD
623 table = kmemdup(nf_ct_sysctl_table, sizeof(nf_ct_sysctl_table),
624 GFP_KERNEL);
625 if (!table)
626 goto out_kmemdup;
627
4a65798a
FW
628 table[NF_SYSCTL_CT_COUNT].data = &net->ct.count;
629 table[NF_SYSCTL_CT_CHECKSUM].data = &net->ct.sysctl_checksum;
630 table[NF_SYSCTL_CT_LOG_INVALID].data = &net->ct.sysctl_log_invalid;
80250707 631
464dc801 632 /* Don't export sysctls to unprivileged users */
d912dec1 633 if (net->user_ns != &init_user_ns) {
4a65798a 634 table[NF_SYSCTL_CT_MAX].procname = NULL;
d912dec1
FW
635 table[NF_SYSCTL_CT_ACCT].procname = NULL;
636 table[NF_SYSCTL_CT_HELPER].procname = NULL;
637 }
464dc801 638
3183ab89 639 if (!net_eq(&init_net, net))
4a65798a 640 table[NF_SYSCTL_CT_BUCKETS].mode = 0444;
3183ab89 641
ec8f23ce 642 net->ct.sysctl_header = register_net_sysctl(net, "net/netfilter", table);
80250707 643 if (!net->ct.sysctl_header)
9714be7d
KPO
644 goto out_unregister_netfilter;
645
b916f7d4
AD
646 return 0;
647
9714be7d 648out_unregister_netfilter:
80250707
AD
649 kfree(table);
650out_kmemdup:
9714be7d 651 return -ENOMEM;
b916f7d4
AD
652}
653
80250707 654static void nf_conntrack_standalone_fini_sysctl(struct net *net)
b916f7d4 655{
80250707
AD
656 struct ctl_table *table;
657
80250707
AD
658 table = net->ct.sysctl_header->ctl_table_arg;
659 unregister_net_sysctl_table(net->ct.sysctl_header);
660 kfree(table);
b916f7d4
AD
661}
662#else
80250707 663static int nf_conntrack_standalone_init_sysctl(struct net *net)
b916f7d4
AD
664{
665 return 0;
666}
667
80250707 668static void nf_conntrack_standalone_fini_sysctl(struct net *net)
b916f7d4
AD
669{
670}
9fb9cbb1
YK
671#endif /* CONFIG_SYSCTL */
672
f94161c1 673static int nf_conntrack_pernet_init(struct net *net)
dfdb8d79 674{
b2ce2c74
AD
675 int ret;
676
f94161c1 677 ret = nf_conntrack_init_net(net);
b2ce2c74
AD
678 if (ret < 0)
679 goto out_init;
f94161c1 680
b2ce2c74
AD
681 ret = nf_conntrack_standalone_init_proc(net);
682 if (ret < 0)
683 goto out_proc;
f94161c1 684
c04d0552 685 net->ct.sysctl_checksum = 1;
c2a2c7e0 686 net->ct.sysctl_log_invalid = 0;
80250707
AD
687 ret = nf_conntrack_standalone_init_sysctl(net);
688 if (ret < 0)
689 goto out_sysctl;
f94161c1 690
b2ce2c74
AD
691 return 0;
692
80250707
AD
693out_sysctl:
694 nf_conntrack_standalone_fini_proc(net);
b2ce2c74 695out_proc:
f94161c1 696 nf_conntrack_cleanup_net(net);
b2ce2c74
AD
697out_init:
698 return ret;
dfdb8d79
AD
699}
700
dece40e8 701static void nf_conntrack_pernet_exit(struct list_head *net_exit_list)
dfdb8d79 702{
dece40e8
VD
703 struct net *net;
704
705 list_for_each_entry(net, net_exit_list, exit_list) {
706 nf_conntrack_standalone_fini_sysctl(net);
707 nf_conntrack_standalone_fini_proc(net);
708 }
709 nf_conntrack_cleanup_net_list(net_exit_list);
dfdb8d79
AD
710}
711
712static struct pernet_operations nf_conntrack_net_ops = {
dece40e8
VD
713 .init = nf_conntrack_pernet_init,
714 .exit_batch = nf_conntrack_pernet_exit,
a0ae2562
FW
715 .id = &nf_conntrack_net_id,
716 .size = sizeof(struct nf_conntrack_net),
dfdb8d79
AD
717};
718
65b4b4e8 719static int __init nf_conntrack_standalone_init(void)
9fb9cbb1 720{
f94161c1
G
721 int ret = nf_conntrack_init_start();
722 if (ret < 0)
723 goto out_start;
724
a9e419dc
FW
725 BUILD_BUG_ON(SKB_NFCT_PTRMASK != NFCT_PTRMASK);
726 BUILD_BUG_ON(NFCT_INFOMASK <= IP_CT_NUMBER);
727
5f9f946b 728#ifdef CONFIG_SYSCTL
f94161c1
G
729 nf_ct_netfilter_header =
730 register_net_sysctl(&init_net, "net", nf_ct_netfilter_table);
5f9f946b
PNA
731 if (!nf_ct_netfilter_header) {
732 pr_err("nf_conntrack: can't register to sysctl.\n");
5389090b 733 ret = -ENOMEM;
f94161c1 734 goto out_sysctl;
5f9f946b 735 }
3183ab89
FW
736
737 nf_conntrack_htable_size_user = nf_conntrack_htable_size;
5f9f946b 738#endif
f94161c1
G
739
740 ret = register_pernet_subsys(&nf_conntrack_net_ops);
741 if (ret < 0)
742 goto out_pernet;
743
744 nf_conntrack_init_end();
745 return 0;
746
747out_pernet:
5f9f946b 748#ifdef CONFIG_SYSCTL
f94161c1
G
749 unregister_net_sysctl_table(nf_ct_netfilter_header);
750out_sysctl:
5f9f946b 751#endif
f94161c1
G
752 nf_conntrack_cleanup_end();
753out_start:
754 return ret;
9fb9cbb1
YK
755}
756
65b4b4e8 757static void __exit nf_conntrack_standalone_fini(void)
9fb9cbb1 758{
f94161c1 759 nf_conntrack_cleanup_start();
dfdb8d79 760 unregister_pernet_subsys(&nf_conntrack_net_ops);
5f9f946b 761#ifdef CONFIG_SYSCTL
f94161c1 762 unregister_net_sysctl_table(nf_ct_netfilter_header);
5f9f946b 763#endif
1e47ee83 764 nf_conntrack_cleanup_end();
9fb9cbb1
YK
765}
766
65b4b4e8
AM
767module_init(nf_conntrack_standalone_init);
768module_exit(nf_conntrack_standalone_fini);