1 | // SPDX-License-Identifier: GPL-2.0 |
2 | #include <linux/types.h> |
3 | #include <linux/netfilter.h> |
4 | #include <linux/slab.h> |
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> |
11 | #include <linux/security.h> |
12 | #include <net/net_namespace.h> |
13 | #ifdef CONFIG_SYSCTL |
14 | #include <linux/sysctl.h> |
15 | #endif |
16 | |
17 | #include <net/netfilter/nf_conntrack.h> |
18 | #include <net/netfilter/nf_conntrack_core.h> |
19 | #include <net/netfilter/nf_conntrack_l4proto.h> |
20 | #include <net/netfilter/nf_conntrack_expect.h> |
21 | #include <net/netfilter/nf_conntrack_helper.h> |
22 | #include <net/netfilter/nf_conntrack_acct.h> |
23 | #include <net/netfilter/nf_conntrack_zones.h> |
24 | #include <net/netfilter/nf_conntrack_timestamp.h> |
25 | #ifdef CONFIG_LWTUNNEL |
26 | #include <net/netfilter/nf_hooks_lwtunnel.h> |
27 | #endif |
28 | #include <linux/rculist_nulls.h> |
29 | |
30 | static bool enable_hooks __read_mostly; |
31 | MODULE_PARM_DESC(enable_hooks, "Always enable conntrack hooks" ); |
32 | module_param(enable_hooks, bool, 0000); |
33 | |
34 | unsigned int nf_conntrack_net_id __read_mostly; |
35 | |
36 | #ifdef CONFIG_NF_CONNTRACK_PROCFS |
37 | void |
38 | print_tuple(struct seq_file *s, const struct nf_conntrack_tuple *tuple, |
39 | const struct nf_conntrack_l4proto *l4proto) |
40 | { |
41 | switch (tuple->src.l3num) { |
42 | case NFPROTO_IPV4: |
43 | seq_printf(m: s, fmt: "src=%pI4 dst=%pI4 " , |
44 | &tuple->src.u3.ip, &tuple->dst.u3.ip); |
45 | break; |
46 | case NFPROTO_IPV6: |
47 | seq_printf(m: s, fmt: "src=%pI6 dst=%pI6 " , |
48 | tuple->src.u3.ip6, tuple->dst.u3.ip6); |
49 | break; |
50 | default: |
51 | break; |
52 | } |
53 | |
54 | switch (l4proto->l4proto) { |
55 | case IPPROTO_ICMP: |
56 | seq_printf(m: s, fmt: "type=%u code=%u id=%u " , |
57 | tuple->dst.u.icmp.type, |
58 | tuple->dst.u.icmp.code, |
59 | ntohs(tuple->src.u.icmp.id)); |
60 | break; |
61 | case IPPROTO_TCP: |
62 | seq_printf(m: s, fmt: "sport=%hu dport=%hu " , |
63 | ntohs(tuple->src.u.tcp.port), |
64 | ntohs(tuple->dst.u.tcp.port)); |
65 | break; |
66 | case IPPROTO_UDPLITE: |
67 | case IPPROTO_UDP: |
68 | seq_printf(m: s, fmt: "sport=%hu dport=%hu " , |
69 | ntohs(tuple->src.u.udp.port), |
70 | ntohs(tuple->dst.u.udp.port)); |
71 | |
72 | break; |
73 | case IPPROTO_DCCP: |
74 | seq_printf(m: s, fmt: "sport=%hu dport=%hu " , |
75 | ntohs(tuple->src.u.dccp.port), |
76 | ntohs(tuple->dst.u.dccp.port)); |
77 | break; |
78 | case IPPROTO_SCTP: |
79 | seq_printf(m: s, fmt: "sport=%hu dport=%hu " , |
80 | ntohs(tuple->src.u.sctp.port), |
81 | ntohs(tuple->dst.u.sctp.port)); |
82 | break; |
83 | case IPPROTO_ICMPV6: |
84 | seq_printf(m: s, fmt: "type=%u code=%u id=%u " , |
85 | tuple->dst.u.icmp.type, |
86 | tuple->dst.u.icmp.code, |
87 | ntohs(tuple->src.u.icmp.id)); |
88 | break; |
89 | case IPPROTO_GRE: |
90 | seq_printf(m: s, fmt: "srckey=0x%x dstkey=0x%x " , |
91 | ntohs(tuple->src.u.gre.key), |
92 | ntohs(tuple->dst.u.gre.key)); |
93 | break; |
94 | default: |
95 | break; |
96 | } |
97 | } |
98 | EXPORT_SYMBOL_GPL(print_tuple); |
99 | |
100 | struct ct_iter_state { |
101 | struct seq_net_private p; |
102 | struct hlist_nulls_head *hash; |
103 | unsigned int htable_size; |
104 | unsigned int bucket; |
105 | u_int64_t time_now; |
106 | }; |
107 | |
108 | static struct hlist_nulls_node *ct_get_first(struct seq_file *seq) |
109 | { |
110 | struct ct_iter_state *st = seq->private; |
111 | struct hlist_nulls_node *n; |
112 | |
113 | for (st->bucket = 0; |
114 | st->bucket < st->htable_size; |
115 | st->bucket++) { |
116 | n = rcu_dereference( |
117 | hlist_nulls_first_rcu(&st->hash[st->bucket])); |
118 | if (!is_a_nulls(ptr: n)) |
119 | return n; |
120 | } |
121 | return NULL; |
122 | } |
123 | |
124 | static struct hlist_nulls_node *ct_get_next(struct seq_file *seq, |
125 | struct hlist_nulls_node *head) |
126 | { |
127 | struct ct_iter_state *st = seq->private; |
128 | |
129 | head = rcu_dereference(hlist_nulls_next_rcu(head)); |
130 | while (is_a_nulls(ptr: head)) { |
131 | if (likely(get_nulls_value(head) == st->bucket)) { |
132 | if (++st->bucket >= st->htable_size) |
133 | return NULL; |
134 | } |
135 | head = rcu_dereference( |
136 | hlist_nulls_first_rcu(&st->hash[st->bucket])); |
137 | } |
138 | return head; |
139 | } |
140 | |
141 | static struct hlist_nulls_node *ct_get_idx(struct seq_file *seq, loff_t pos) |
142 | { |
143 | struct hlist_nulls_node *head = ct_get_first(seq); |
144 | |
145 | if (head) |
146 | while (pos && (head = ct_get_next(seq, head))) |
147 | pos--; |
148 | return pos ? NULL : head; |
149 | } |
150 | |
151 | static void *ct_seq_start(struct seq_file *seq, loff_t *pos) |
152 | __acquires(RCU) |
153 | { |
154 | struct ct_iter_state *st = seq->private; |
155 | |
156 | st->time_now = ktime_get_real_ns(); |
157 | rcu_read_lock(); |
158 | |
159 | nf_conntrack_get_ht(hash: &st->hash, hsize: &st->htable_size); |
160 | return ct_get_idx(seq, pos: *pos); |
161 | } |
162 | |
163 | static void *ct_seq_next(struct seq_file *s, void *v, loff_t *pos) |
164 | { |
165 | (*pos)++; |
166 | return ct_get_next(seq: s, head: v); |
167 | } |
168 | |
169 | static void ct_seq_stop(struct seq_file *s, void *v) |
170 | __releases(RCU) |
171 | { |
172 | rcu_read_unlock(); |
173 | } |
174 | |
175 | #ifdef CONFIG_NF_CONNTRACK_SECMARK |
176 | static void ct_show_secctx(struct seq_file *s, const struct nf_conn *ct) |
177 | { |
178 | int ret; |
179 | u32 len; |
180 | char *secctx; |
181 | |
182 | ret = security_secid_to_secctx(secid: ct->secmark, secdata: &secctx, seclen: &len); |
183 | if (ret) |
184 | return; |
185 | |
186 | seq_printf(m: s, fmt: "secctx=%s " , secctx); |
187 | |
188 | security_release_secctx(secdata: secctx, seclen: len); |
189 | } |
190 | #else |
191 | static inline void ct_show_secctx(struct seq_file *s, const struct nf_conn *ct) |
192 | { |
193 | } |
194 | #endif |
195 | |
196 | #ifdef CONFIG_NF_CONNTRACK_ZONES |
197 | static void ct_show_zone(struct seq_file *s, const struct nf_conn *ct, |
198 | int dir) |
199 | { |
200 | const struct nf_conntrack_zone *zone = nf_ct_zone(ct); |
201 | |
202 | if (zone->dir != dir) |
203 | return; |
204 | switch (zone->dir) { |
205 | case NF_CT_DEFAULT_ZONE_DIR: |
206 | seq_printf(m: s, fmt: "zone=%u " , zone->id); |
207 | break; |
208 | case NF_CT_ZONE_DIR_ORIG: |
209 | seq_printf(m: s, fmt: "zone-orig=%u " , zone->id); |
210 | break; |
211 | case NF_CT_ZONE_DIR_REPL: |
212 | seq_printf(m: s, fmt: "zone-reply=%u " , zone->id); |
213 | break; |
214 | default: |
215 | break; |
216 | } |
217 | } |
218 | #else |
219 | static inline void ct_show_zone(struct seq_file *s, const struct nf_conn *ct, |
220 | int dir) |
221 | { |
222 | } |
223 | #endif |
224 | |
225 | #ifdef CONFIG_NF_CONNTRACK_TIMESTAMP |
226 | static void ct_show_delta_time(struct seq_file *s, const struct nf_conn *ct) |
227 | { |
228 | struct ct_iter_state *st = s->private; |
229 | struct nf_conn_tstamp *tstamp; |
230 | s64 delta_time; |
231 | |
232 | tstamp = nf_conn_tstamp_find(ct); |
233 | if (tstamp) { |
234 | delta_time = st->time_now - tstamp->start; |
235 | if (delta_time > 0) |
236 | delta_time = div_s64(dividend: delta_time, NSEC_PER_SEC); |
237 | else |
238 | delta_time = 0; |
239 | |
240 | seq_printf(m: s, fmt: "delta-time=%llu " , |
241 | (unsigned long long)delta_time); |
242 | } |
243 | return; |
244 | } |
245 | #else |
246 | static inline void |
247 | ct_show_delta_time(struct seq_file *s, const struct nf_conn *ct) |
248 | { |
249 | } |
250 | #endif |
251 | |
252 | static const char* l3proto_name(u16 proto) |
253 | { |
254 | switch (proto) { |
255 | case AF_INET: return "ipv4" ; |
256 | case AF_INET6: return "ipv6" ; |
257 | } |
258 | |
259 | return "unknown" ; |
260 | } |
261 | |
262 | static const char* l4proto_name(u16 proto) |
263 | { |
264 | switch (proto) { |
265 | case IPPROTO_ICMP: return "icmp" ; |
266 | case IPPROTO_TCP: return "tcp" ; |
267 | case IPPROTO_UDP: return "udp" ; |
268 | case IPPROTO_DCCP: return "dccp" ; |
269 | case IPPROTO_GRE: return "gre" ; |
270 | case IPPROTO_SCTP: return "sctp" ; |
271 | case IPPROTO_UDPLITE: return "udplite" ; |
272 | case IPPROTO_ICMPV6: return "icmpv6" ; |
273 | } |
274 | |
275 | return "unknown" ; |
276 | } |
277 | |
278 | static void |
279 | seq_print_acct(struct seq_file *s, const struct nf_conn *ct, int dir) |
280 | { |
281 | struct nf_conn_acct *acct; |
282 | struct nf_conn_counter *counter; |
283 | |
284 | acct = nf_conn_acct_find(ct); |
285 | if (!acct) |
286 | return; |
287 | |
288 | counter = acct->counter; |
289 | seq_printf(m: s, fmt: "packets=%llu bytes=%llu " , |
290 | (unsigned long long)atomic64_read(v: &counter[dir].packets), |
291 | (unsigned long long)atomic64_read(v: &counter[dir].bytes)); |
292 | } |
293 | |
294 | /* return 0 on success, 1 in case of error */ |
295 | static int ct_seq_show(struct seq_file *s, void *v) |
296 | { |
297 | struct nf_conntrack_tuple_hash *hash = v; |
298 | struct nf_conn *ct = nf_ct_tuplehash_to_ctrack(hash); |
299 | const struct nf_conntrack_l4proto *l4proto; |
300 | struct net *net = seq_file_net(seq: s); |
301 | int ret = 0; |
302 | |
303 | WARN_ON(!ct); |
304 | if (unlikely(!refcount_inc_not_zero(&ct->ct_general.use))) |
305 | return 0; |
306 | |
307 | /* load ->status after refcount increase */ |
308 | smp_acquire__after_ctrl_dep(); |
309 | |
310 | if (nf_ct_should_gc(ct)) { |
311 | nf_ct_kill(ct); |
312 | goto release; |
313 | } |
314 | |
315 | /* we only want to print DIR_ORIGINAL */ |
316 | if (NF_CT_DIRECTION(hash)) |
317 | goto release; |
318 | |
319 | if (!net_eq(net1: nf_ct_net(ct), net2: net)) |
320 | goto release; |
321 | |
322 | l4proto = nf_ct_l4proto_find(l4proto: nf_ct_protonum(ct)); |
323 | |
324 | ret = -ENOSPC; |
325 | seq_printf(m: s, fmt: "%-8s %u %-8s %u " , |
326 | l3proto_name(proto: nf_ct_l3num(ct)), nf_ct_l3num(ct), |
327 | l4proto_name(proto: l4proto->l4proto), nf_ct_protonum(ct)); |
328 | |
329 | if (!test_bit(IPS_OFFLOAD_BIT, &ct->status)) |
330 | seq_printf(m: s, fmt: "%ld " , nf_ct_expires(ct) / HZ); |
331 | |
332 | if (l4proto->print_conntrack) |
333 | l4proto->print_conntrack(s, ct); |
334 | |
335 | print_tuple(s, &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple, |
336 | l4proto); |
337 | |
338 | ct_show_zone(s, ct, NF_CT_ZONE_DIR_ORIG); |
339 | |
340 | if (seq_has_overflowed(m: s)) |
341 | goto release; |
342 | |
343 | seq_print_acct(s, ct, dir: IP_CT_DIR_ORIGINAL); |
344 | |
345 | if (!(test_bit(IPS_SEEN_REPLY_BIT, &ct->status))) |
346 | seq_puts(m: s, s: "[UNREPLIED] " ); |
347 | |
348 | print_tuple(s, &ct->tuplehash[IP_CT_DIR_REPLY].tuple, l4proto); |
349 | |
350 | ct_show_zone(s, ct, NF_CT_ZONE_DIR_REPL); |
351 | |
352 | seq_print_acct(s, ct, dir: IP_CT_DIR_REPLY); |
353 | |
354 | if (test_bit(IPS_HW_OFFLOAD_BIT, &ct->status)) |
355 | seq_puts(m: s, s: "[HW_OFFLOAD] " ); |
356 | else if (test_bit(IPS_OFFLOAD_BIT, &ct->status)) |
357 | seq_puts(m: s, s: "[OFFLOAD] " ); |
358 | else if (test_bit(IPS_ASSURED_BIT, &ct->status)) |
359 | seq_puts(m: s, s: "[ASSURED] " ); |
360 | |
361 | if (seq_has_overflowed(m: s)) |
362 | goto release; |
363 | |
364 | #if defined(CONFIG_NF_CONNTRACK_MARK) |
365 | seq_printf(m: s, fmt: "mark=%u " , READ_ONCE(ct->mark)); |
366 | #endif |
367 | |
368 | ct_show_secctx(s, ct); |
369 | ct_show_zone(s, ct, NF_CT_DEFAULT_ZONE_DIR); |
370 | ct_show_delta_time(s, ct); |
371 | |
372 | seq_printf(m: s, fmt: "use=%u\n" , refcount_read(r: &ct->ct_general.use)); |
373 | |
374 | if (seq_has_overflowed(m: s)) |
375 | goto release; |
376 | |
377 | ret = 0; |
378 | release: |
379 | nf_ct_put(ct); |
380 | return ret; |
381 | } |
382 | |
383 | static const struct seq_operations ct_seq_ops = { |
384 | .start = ct_seq_start, |
385 | .next = ct_seq_next, |
386 | .stop = ct_seq_stop, |
387 | .show = ct_seq_show |
388 | }; |
389 | |
390 | static void *ct_cpu_seq_start(struct seq_file *seq, loff_t *pos) |
391 | { |
392 | struct net *net = seq_file_net(seq); |
393 | int cpu; |
394 | |
395 | if (*pos == 0) |
396 | return SEQ_START_TOKEN; |
397 | |
398 | for (cpu = *pos-1; cpu < nr_cpu_ids; ++cpu) { |
399 | if (!cpu_possible(cpu)) |
400 | continue; |
401 | *pos = cpu + 1; |
402 | return per_cpu_ptr(net->ct.stat, cpu); |
403 | } |
404 | |
405 | return NULL; |
406 | } |
407 | |
408 | static void *ct_cpu_seq_next(struct seq_file *seq, void *v, loff_t *pos) |
409 | { |
410 | struct net *net = seq_file_net(seq); |
411 | int cpu; |
412 | |
413 | for (cpu = *pos; cpu < nr_cpu_ids; ++cpu) { |
414 | if (!cpu_possible(cpu)) |
415 | continue; |
416 | *pos = cpu + 1; |
417 | return per_cpu_ptr(net->ct.stat, cpu); |
418 | } |
419 | (*pos)++; |
420 | return NULL; |
421 | } |
422 | |
423 | static void ct_cpu_seq_stop(struct seq_file *seq, void *v) |
424 | { |
425 | } |
426 | |
427 | static int ct_cpu_seq_show(struct seq_file *seq, void *v) |
428 | { |
429 | struct net *net = seq_file_net(seq); |
430 | const struct ip_conntrack_stat *st = v; |
431 | unsigned int nr_conntracks; |
432 | |
433 | if (v == SEQ_START_TOKEN) { |
434 | seq_puts(m: seq, s: "entries clashres found new invalid ignore delete chainlength insert insert_failed drop early_drop icmp_error expect_new expect_create expect_delete search_restart\n" ); |
435 | return 0; |
436 | } |
437 | |
438 | nr_conntracks = nf_conntrack_count(net); |
439 | |
440 | seq_printf(m: seq, fmt: "%08x %08x %08x %08x %08x %08x %08x %08x " |
441 | "%08x %08x %08x %08x %08x %08x %08x %08x %08x\n" , |
442 | nr_conntracks, |
443 | st->clash_resolve, |
444 | st->found, |
445 | 0, |
446 | st->invalid, |
447 | 0, |
448 | 0, |
449 | st->chaintoolong, |
450 | st->insert, |
451 | st->insert_failed, |
452 | st->drop, |
453 | st->early_drop, |
454 | st->error, |
455 | |
456 | st->expect_new, |
457 | st->expect_create, |
458 | st->expect_delete, |
459 | st->search_restart |
460 | ); |
461 | return 0; |
462 | } |
463 | |
464 | static const struct seq_operations ct_cpu_seq_ops = { |
465 | .start = ct_cpu_seq_start, |
466 | .next = ct_cpu_seq_next, |
467 | .stop = ct_cpu_seq_stop, |
468 | .show = ct_cpu_seq_show, |
469 | }; |
470 | |
471 | static int nf_conntrack_standalone_init_proc(struct net *net) |
472 | { |
473 | struct proc_dir_entry *pde; |
474 | kuid_t root_uid; |
475 | kgid_t root_gid; |
476 | |
477 | pde = proc_create_net("nf_conntrack" , 0440, net->proc_net, &ct_seq_ops, |
478 | sizeof(struct ct_iter_state)); |
479 | if (!pde) |
480 | goto out_nf_conntrack; |
481 | |
482 | root_uid = make_kuid(from: net->user_ns, uid: 0); |
483 | root_gid = make_kgid(from: net->user_ns, gid: 0); |
484 | if (uid_valid(uid: root_uid) && gid_valid(gid: root_gid)) |
485 | proc_set_user(pde, root_uid, root_gid); |
486 | |
487 | pde = proc_create_net("nf_conntrack" , 0444, net->proc_net_stat, |
488 | &ct_cpu_seq_ops, sizeof(struct seq_net_private)); |
489 | if (!pde) |
490 | goto out_stat_nf_conntrack; |
491 | return 0; |
492 | |
493 | out_stat_nf_conntrack: |
494 | remove_proc_entry("nf_conntrack" , net->proc_net); |
495 | out_nf_conntrack: |
496 | return -ENOMEM; |
497 | } |
498 | |
499 | static void nf_conntrack_standalone_fini_proc(struct net *net) |
500 | { |
501 | remove_proc_entry("nf_conntrack" , net->proc_net_stat); |
502 | remove_proc_entry("nf_conntrack" , net->proc_net); |
503 | } |
504 | #else |
505 | static int nf_conntrack_standalone_init_proc(struct net *net) |
506 | { |
507 | return 0; |
508 | } |
509 | |
510 | static void nf_conntrack_standalone_fini_proc(struct net *net) |
511 | { |
512 | } |
513 | #endif /* CONFIG_NF_CONNTRACK_PROCFS */ |
514 | |
515 | u32 nf_conntrack_count(const struct net *net) |
516 | { |
517 | const struct nf_conntrack_net *cnet = nf_ct_pernet(net); |
518 | |
519 | return atomic_read(v: &cnet->count); |
520 | } |
521 | EXPORT_SYMBOL_GPL(nf_conntrack_count); |
522 | |
523 | /* Sysctl support */ |
524 | |
525 | #ifdef CONFIG_SYSCTL |
526 | /* size the user *wants to set */ |
527 | static unsigned int nf_conntrack_htable_size_user __read_mostly; |
528 | |
529 | static int |
530 | nf_conntrack_hash_sysctl(struct ctl_table *table, int write, |
531 | void *buffer, size_t *lenp, loff_t *ppos) |
532 | { |
533 | int ret; |
534 | |
535 | /* module_param hashsize could have changed value */ |
536 | nf_conntrack_htable_size_user = nf_conntrack_htable_size; |
537 | |
538 | ret = proc_dointvec(table, write, buffer, lenp, ppos); |
539 | if (ret < 0 || !write) |
540 | return ret; |
541 | |
542 | /* update ret, we might not be able to satisfy request */ |
543 | ret = nf_conntrack_hash_resize(hashsize: nf_conntrack_htable_size_user); |
544 | |
545 | /* update it to the actual value used by conntrack */ |
546 | nf_conntrack_htable_size_user = nf_conntrack_htable_size; |
547 | return ret; |
548 | } |
549 | |
550 | static struct ctl_table_header *; |
551 | |
552 | enum nf_ct_sysctl_index { |
553 | NF_SYSCTL_CT_MAX, |
554 | NF_SYSCTL_CT_COUNT, |
555 | NF_SYSCTL_CT_BUCKETS, |
556 | NF_SYSCTL_CT_CHECKSUM, |
557 | NF_SYSCTL_CT_LOG_INVALID, |
558 | NF_SYSCTL_CT_EXPECT_MAX, |
559 | NF_SYSCTL_CT_ACCT, |
560 | #ifdef CONFIG_NF_CONNTRACK_EVENTS |
561 | NF_SYSCTL_CT_EVENTS, |
562 | #endif |
563 | #ifdef CONFIG_NF_CONNTRACK_TIMESTAMP |
564 | NF_SYSCTL_CT_TIMESTAMP, |
565 | #endif |
566 | NF_SYSCTL_CT_PROTO_TIMEOUT_GENERIC, |
567 | NF_SYSCTL_CT_PROTO_TIMEOUT_TCP_SYN_SENT, |
568 | NF_SYSCTL_CT_PROTO_TIMEOUT_TCP_SYN_RECV, |
569 | NF_SYSCTL_CT_PROTO_TIMEOUT_TCP_ESTABLISHED, |
570 | NF_SYSCTL_CT_PROTO_TIMEOUT_TCP_FIN_WAIT, |
571 | NF_SYSCTL_CT_PROTO_TIMEOUT_TCP_CLOSE_WAIT, |
572 | NF_SYSCTL_CT_PROTO_TIMEOUT_TCP_LAST_ACK, |
573 | NF_SYSCTL_CT_PROTO_TIMEOUT_TCP_TIME_WAIT, |
574 | NF_SYSCTL_CT_PROTO_TIMEOUT_TCP_CLOSE, |
575 | NF_SYSCTL_CT_PROTO_TIMEOUT_TCP_RETRANS, |
576 | NF_SYSCTL_CT_PROTO_TIMEOUT_TCP_UNACK, |
577 | #if IS_ENABLED(CONFIG_NF_FLOW_TABLE) |
578 | NF_SYSCTL_CT_PROTO_TIMEOUT_TCP_OFFLOAD, |
579 | #endif |
580 | NF_SYSCTL_CT_PROTO_TCP_LOOSE, |
581 | NF_SYSCTL_CT_PROTO_TCP_LIBERAL, |
582 | NF_SYSCTL_CT_PROTO_TCP_IGNORE_INVALID_RST, |
583 | NF_SYSCTL_CT_PROTO_TCP_MAX_RETRANS, |
584 | NF_SYSCTL_CT_PROTO_TIMEOUT_UDP, |
585 | NF_SYSCTL_CT_PROTO_TIMEOUT_UDP_STREAM, |
586 | #if IS_ENABLED(CONFIG_NF_FLOW_TABLE) |
587 | NF_SYSCTL_CT_PROTO_TIMEOUT_UDP_OFFLOAD, |
588 | #endif |
589 | NF_SYSCTL_CT_PROTO_TIMEOUT_ICMP, |
590 | NF_SYSCTL_CT_PROTO_TIMEOUT_ICMPV6, |
591 | #ifdef CONFIG_NF_CT_PROTO_SCTP |
592 | NF_SYSCTL_CT_PROTO_TIMEOUT_SCTP_CLOSED, |
593 | NF_SYSCTL_CT_PROTO_TIMEOUT_SCTP_COOKIE_WAIT, |
594 | NF_SYSCTL_CT_PROTO_TIMEOUT_SCTP_COOKIE_ECHOED, |
595 | NF_SYSCTL_CT_PROTO_TIMEOUT_SCTP_ESTABLISHED, |
596 | NF_SYSCTL_CT_PROTO_TIMEOUT_SCTP_SHUTDOWN_SENT, |
597 | NF_SYSCTL_CT_PROTO_TIMEOUT_SCTP_SHUTDOWN_RECD, |
598 | NF_SYSCTL_CT_PROTO_TIMEOUT_SCTP_SHUTDOWN_ACK_SENT, |
599 | NF_SYSCTL_CT_PROTO_TIMEOUT_SCTP_HEARTBEAT_SENT, |
600 | #endif |
601 | #ifdef CONFIG_NF_CT_PROTO_DCCP |
602 | NF_SYSCTL_CT_PROTO_TIMEOUT_DCCP_REQUEST, |
603 | NF_SYSCTL_CT_PROTO_TIMEOUT_DCCP_RESPOND, |
604 | NF_SYSCTL_CT_PROTO_TIMEOUT_DCCP_PARTOPEN, |
605 | NF_SYSCTL_CT_PROTO_TIMEOUT_DCCP_OPEN, |
606 | NF_SYSCTL_CT_PROTO_TIMEOUT_DCCP_CLOSEREQ, |
607 | NF_SYSCTL_CT_PROTO_TIMEOUT_DCCP_CLOSING, |
608 | NF_SYSCTL_CT_PROTO_TIMEOUT_DCCP_TIMEWAIT, |
609 | NF_SYSCTL_CT_PROTO_DCCP_LOOSE, |
610 | #endif |
611 | #ifdef CONFIG_NF_CT_PROTO_GRE |
612 | NF_SYSCTL_CT_PROTO_TIMEOUT_GRE, |
613 | NF_SYSCTL_CT_PROTO_TIMEOUT_GRE_STREAM, |
614 | #endif |
615 | #ifdef CONFIG_LWTUNNEL |
616 | NF_SYSCTL_CT_LWTUNNEL, |
617 | #endif |
618 | |
619 | __NF_SYSCTL_CT_LAST_SYSCTL, |
620 | }; |
621 | |
622 | #define NF_SYSCTL_CT_LAST_SYSCTL (__NF_SYSCTL_CT_LAST_SYSCTL + 1) |
623 | |
624 | static struct ctl_table nf_ct_sysctl_table[] = { |
625 | [NF_SYSCTL_CT_MAX] = { |
626 | .procname = "nf_conntrack_max" , |
627 | .data = &nf_conntrack_max, |
628 | .maxlen = sizeof(int), |
629 | .mode = 0644, |
630 | .proc_handler = proc_dointvec, |
631 | }, |
632 | [NF_SYSCTL_CT_COUNT] = { |
633 | .procname = "nf_conntrack_count" , |
634 | .maxlen = sizeof(int), |
635 | .mode = 0444, |
636 | .proc_handler = proc_dointvec, |
637 | }, |
638 | [NF_SYSCTL_CT_BUCKETS] = { |
639 | .procname = "nf_conntrack_buckets" , |
640 | .data = &nf_conntrack_htable_size_user, |
641 | .maxlen = sizeof(unsigned int), |
642 | .mode = 0644, |
643 | .proc_handler = nf_conntrack_hash_sysctl, |
644 | }, |
645 | [NF_SYSCTL_CT_CHECKSUM] = { |
646 | .procname = "nf_conntrack_checksum" , |
647 | .data = &init_net.ct.sysctl_checksum, |
648 | .maxlen = sizeof(u8), |
649 | .mode = 0644, |
650 | .proc_handler = proc_dou8vec_minmax, |
651 | .extra1 = SYSCTL_ZERO, |
652 | .extra2 = SYSCTL_ONE, |
653 | }, |
654 | [NF_SYSCTL_CT_LOG_INVALID] = { |
655 | .procname = "nf_conntrack_log_invalid" , |
656 | .data = &init_net.ct.sysctl_log_invalid, |
657 | .maxlen = sizeof(u8), |
658 | .mode = 0644, |
659 | .proc_handler = proc_dou8vec_minmax, |
660 | }, |
661 | [NF_SYSCTL_CT_EXPECT_MAX] = { |
662 | .procname = "nf_conntrack_expect_max" , |
663 | .data = &nf_ct_expect_max, |
664 | .maxlen = sizeof(int), |
665 | .mode = 0644, |
666 | .proc_handler = proc_dointvec, |
667 | }, |
668 | [NF_SYSCTL_CT_ACCT] = { |
669 | .procname = "nf_conntrack_acct" , |
670 | .data = &init_net.ct.sysctl_acct, |
671 | .maxlen = sizeof(u8), |
672 | .mode = 0644, |
673 | .proc_handler = proc_dou8vec_minmax, |
674 | .extra1 = SYSCTL_ZERO, |
675 | .extra2 = SYSCTL_ONE, |
676 | }, |
677 | #ifdef CONFIG_NF_CONNTRACK_EVENTS |
678 | [NF_SYSCTL_CT_EVENTS] = { |
679 | .procname = "nf_conntrack_events" , |
680 | .data = &init_net.ct.sysctl_events, |
681 | .maxlen = sizeof(u8), |
682 | .mode = 0644, |
683 | .proc_handler = proc_dou8vec_minmax, |
684 | .extra1 = SYSCTL_ZERO, |
685 | .extra2 = SYSCTL_TWO, |
686 | }, |
687 | #endif |
688 | #ifdef CONFIG_NF_CONNTRACK_TIMESTAMP |
689 | [NF_SYSCTL_CT_TIMESTAMP] = { |
690 | .procname = "nf_conntrack_timestamp" , |
691 | .data = &init_net.ct.sysctl_tstamp, |
692 | .maxlen = sizeof(u8), |
693 | .mode = 0644, |
694 | .proc_handler = proc_dou8vec_minmax, |
695 | .extra1 = SYSCTL_ZERO, |
696 | .extra2 = SYSCTL_ONE, |
697 | }, |
698 | #endif |
699 | [NF_SYSCTL_CT_PROTO_TIMEOUT_GENERIC] = { |
700 | .procname = "nf_conntrack_generic_timeout" , |
701 | .maxlen = sizeof(unsigned int), |
702 | .mode = 0644, |
703 | .proc_handler = proc_dointvec_jiffies, |
704 | }, |
705 | [NF_SYSCTL_CT_PROTO_TIMEOUT_TCP_SYN_SENT] = { |
706 | .procname = "nf_conntrack_tcp_timeout_syn_sent" , |
707 | .maxlen = sizeof(unsigned int), |
708 | .mode = 0644, |
709 | .proc_handler = proc_dointvec_jiffies, |
710 | }, |
711 | [NF_SYSCTL_CT_PROTO_TIMEOUT_TCP_SYN_RECV] = { |
712 | .procname = "nf_conntrack_tcp_timeout_syn_recv" , |
713 | .maxlen = sizeof(unsigned int), |
714 | .mode = 0644, |
715 | .proc_handler = proc_dointvec_jiffies, |
716 | }, |
717 | [NF_SYSCTL_CT_PROTO_TIMEOUT_TCP_ESTABLISHED] = { |
718 | .procname = "nf_conntrack_tcp_timeout_established" , |
719 | .maxlen = sizeof(unsigned int), |
720 | .mode = 0644, |
721 | .proc_handler = proc_dointvec_jiffies, |
722 | }, |
723 | [NF_SYSCTL_CT_PROTO_TIMEOUT_TCP_FIN_WAIT] = { |
724 | .procname = "nf_conntrack_tcp_timeout_fin_wait" , |
725 | .maxlen = sizeof(unsigned int), |
726 | .mode = 0644, |
727 | .proc_handler = proc_dointvec_jiffies, |
728 | }, |
729 | [NF_SYSCTL_CT_PROTO_TIMEOUT_TCP_CLOSE_WAIT] = { |
730 | .procname = "nf_conntrack_tcp_timeout_close_wait" , |
731 | .maxlen = sizeof(unsigned int), |
732 | .mode = 0644, |
733 | .proc_handler = proc_dointvec_jiffies, |
734 | }, |
735 | [NF_SYSCTL_CT_PROTO_TIMEOUT_TCP_LAST_ACK] = { |
736 | .procname = "nf_conntrack_tcp_timeout_last_ack" , |
737 | .maxlen = sizeof(unsigned int), |
738 | .mode = 0644, |
739 | .proc_handler = proc_dointvec_jiffies, |
740 | }, |
741 | [NF_SYSCTL_CT_PROTO_TIMEOUT_TCP_TIME_WAIT] = { |
742 | .procname = "nf_conntrack_tcp_timeout_time_wait" , |
743 | .maxlen = sizeof(unsigned int), |
744 | .mode = 0644, |
745 | .proc_handler = proc_dointvec_jiffies, |
746 | }, |
747 | [NF_SYSCTL_CT_PROTO_TIMEOUT_TCP_CLOSE] = { |
748 | .procname = "nf_conntrack_tcp_timeout_close" , |
749 | .maxlen = sizeof(unsigned int), |
750 | .mode = 0644, |
751 | .proc_handler = proc_dointvec_jiffies, |
752 | }, |
753 | [NF_SYSCTL_CT_PROTO_TIMEOUT_TCP_RETRANS] = { |
754 | .procname = "nf_conntrack_tcp_timeout_max_retrans" , |
755 | .maxlen = sizeof(unsigned int), |
756 | .mode = 0644, |
757 | .proc_handler = proc_dointvec_jiffies, |
758 | }, |
759 | [NF_SYSCTL_CT_PROTO_TIMEOUT_TCP_UNACK] = { |
760 | .procname = "nf_conntrack_tcp_timeout_unacknowledged" , |
761 | .maxlen = sizeof(unsigned int), |
762 | .mode = 0644, |
763 | .proc_handler = proc_dointvec_jiffies, |
764 | }, |
765 | #if IS_ENABLED(CONFIG_NF_FLOW_TABLE) |
766 | [NF_SYSCTL_CT_PROTO_TIMEOUT_TCP_OFFLOAD] = { |
767 | .procname = "nf_flowtable_tcp_timeout" , |
768 | .maxlen = sizeof(unsigned int), |
769 | .mode = 0644, |
770 | .proc_handler = proc_dointvec_jiffies, |
771 | }, |
772 | #endif |
773 | [NF_SYSCTL_CT_PROTO_TCP_LOOSE] = { |
774 | .procname = "nf_conntrack_tcp_loose" , |
775 | .maxlen = sizeof(u8), |
776 | .mode = 0644, |
777 | .proc_handler = proc_dou8vec_minmax, |
778 | .extra1 = SYSCTL_ZERO, |
779 | .extra2 = SYSCTL_ONE, |
780 | }, |
781 | [NF_SYSCTL_CT_PROTO_TCP_LIBERAL] = { |
782 | .procname = "nf_conntrack_tcp_be_liberal" , |
783 | .maxlen = sizeof(u8), |
784 | .mode = 0644, |
785 | .proc_handler = proc_dou8vec_minmax, |
786 | .extra1 = SYSCTL_ZERO, |
787 | .extra2 = SYSCTL_ONE, |
788 | }, |
789 | [NF_SYSCTL_CT_PROTO_TCP_IGNORE_INVALID_RST] = { |
790 | .procname = "nf_conntrack_tcp_ignore_invalid_rst" , |
791 | .maxlen = sizeof(u8), |
792 | .mode = 0644, |
793 | .proc_handler = proc_dou8vec_minmax, |
794 | .extra1 = SYSCTL_ZERO, |
795 | .extra2 = SYSCTL_ONE, |
796 | }, |
797 | [NF_SYSCTL_CT_PROTO_TCP_MAX_RETRANS] = { |
798 | .procname = "nf_conntrack_tcp_max_retrans" , |
799 | .maxlen = sizeof(u8), |
800 | .mode = 0644, |
801 | .proc_handler = proc_dou8vec_minmax, |
802 | }, |
803 | [NF_SYSCTL_CT_PROTO_TIMEOUT_UDP] = { |
804 | .procname = "nf_conntrack_udp_timeout" , |
805 | .maxlen = sizeof(unsigned int), |
806 | .mode = 0644, |
807 | .proc_handler = proc_dointvec_jiffies, |
808 | }, |
809 | [NF_SYSCTL_CT_PROTO_TIMEOUT_UDP_STREAM] = { |
810 | .procname = "nf_conntrack_udp_timeout_stream" , |
811 | .maxlen = sizeof(unsigned int), |
812 | .mode = 0644, |
813 | .proc_handler = proc_dointvec_jiffies, |
814 | }, |
815 | #if IS_ENABLED(CONFIG_NF_FLOW_TABLE) |
816 | [NF_SYSCTL_CT_PROTO_TIMEOUT_UDP_OFFLOAD] = { |
817 | .procname = "nf_flowtable_udp_timeout" , |
818 | .maxlen = sizeof(unsigned int), |
819 | .mode = 0644, |
820 | .proc_handler = proc_dointvec_jiffies, |
821 | }, |
822 | #endif |
823 | [NF_SYSCTL_CT_PROTO_TIMEOUT_ICMP] = { |
824 | .procname = "nf_conntrack_icmp_timeout" , |
825 | .maxlen = sizeof(unsigned int), |
826 | .mode = 0644, |
827 | .proc_handler = proc_dointvec_jiffies, |
828 | }, |
829 | [NF_SYSCTL_CT_PROTO_TIMEOUT_ICMPV6] = { |
830 | .procname = "nf_conntrack_icmpv6_timeout" , |
831 | .maxlen = sizeof(unsigned int), |
832 | .mode = 0644, |
833 | .proc_handler = proc_dointvec_jiffies, |
834 | }, |
835 | #ifdef CONFIG_NF_CT_PROTO_SCTP |
836 | [NF_SYSCTL_CT_PROTO_TIMEOUT_SCTP_CLOSED] = { |
837 | .procname = "nf_conntrack_sctp_timeout_closed" , |
838 | .maxlen = sizeof(unsigned int), |
839 | .mode = 0644, |
840 | .proc_handler = proc_dointvec_jiffies, |
841 | }, |
842 | [NF_SYSCTL_CT_PROTO_TIMEOUT_SCTP_COOKIE_WAIT] = { |
843 | .procname = "nf_conntrack_sctp_timeout_cookie_wait" , |
844 | .maxlen = sizeof(unsigned int), |
845 | .mode = 0644, |
846 | .proc_handler = proc_dointvec_jiffies, |
847 | }, |
848 | [NF_SYSCTL_CT_PROTO_TIMEOUT_SCTP_COOKIE_ECHOED] = { |
849 | .procname = "nf_conntrack_sctp_timeout_cookie_echoed" , |
850 | .maxlen = sizeof(unsigned int), |
851 | .mode = 0644, |
852 | .proc_handler = proc_dointvec_jiffies, |
853 | }, |
854 | [NF_SYSCTL_CT_PROTO_TIMEOUT_SCTP_ESTABLISHED] = { |
855 | .procname = "nf_conntrack_sctp_timeout_established" , |
856 | .maxlen = sizeof(unsigned int), |
857 | .mode = 0644, |
858 | .proc_handler = proc_dointvec_jiffies, |
859 | }, |
860 | [NF_SYSCTL_CT_PROTO_TIMEOUT_SCTP_SHUTDOWN_SENT] = { |
861 | .procname = "nf_conntrack_sctp_timeout_shutdown_sent" , |
862 | .maxlen = sizeof(unsigned int), |
863 | .mode = 0644, |
864 | .proc_handler = proc_dointvec_jiffies, |
865 | }, |
866 | [NF_SYSCTL_CT_PROTO_TIMEOUT_SCTP_SHUTDOWN_RECD] = { |
867 | .procname = "nf_conntrack_sctp_timeout_shutdown_recd" , |
868 | .maxlen = sizeof(unsigned int), |
869 | .mode = 0644, |
870 | .proc_handler = proc_dointvec_jiffies, |
871 | }, |
872 | [NF_SYSCTL_CT_PROTO_TIMEOUT_SCTP_SHUTDOWN_ACK_SENT] = { |
873 | .procname = "nf_conntrack_sctp_timeout_shutdown_ack_sent" , |
874 | .maxlen = sizeof(unsigned int), |
875 | .mode = 0644, |
876 | .proc_handler = proc_dointvec_jiffies, |
877 | }, |
878 | [NF_SYSCTL_CT_PROTO_TIMEOUT_SCTP_HEARTBEAT_SENT] = { |
879 | .procname = "nf_conntrack_sctp_timeout_heartbeat_sent" , |
880 | .maxlen = sizeof(unsigned int), |
881 | .mode = 0644, |
882 | .proc_handler = proc_dointvec_jiffies, |
883 | }, |
884 | #endif |
885 | #ifdef CONFIG_NF_CT_PROTO_DCCP |
886 | [NF_SYSCTL_CT_PROTO_TIMEOUT_DCCP_REQUEST] = { |
887 | .procname = "nf_conntrack_dccp_timeout_request" , |
888 | .maxlen = sizeof(unsigned int), |
889 | .mode = 0644, |
890 | .proc_handler = proc_dointvec_jiffies, |
891 | }, |
892 | [NF_SYSCTL_CT_PROTO_TIMEOUT_DCCP_RESPOND] = { |
893 | .procname = "nf_conntrack_dccp_timeout_respond" , |
894 | .maxlen = sizeof(unsigned int), |
895 | .mode = 0644, |
896 | .proc_handler = proc_dointvec_jiffies, |
897 | }, |
898 | [NF_SYSCTL_CT_PROTO_TIMEOUT_DCCP_PARTOPEN] = { |
899 | .procname = "nf_conntrack_dccp_timeout_partopen" , |
900 | .maxlen = sizeof(unsigned int), |
901 | .mode = 0644, |
902 | .proc_handler = proc_dointvec_jiffies, |
903 | }, |
904 | [NF_SYSCTL_CT_PROTO_TIMEOUT_DCCP_OPEN] = { |
905 | .procname = "nf_conntrack_dccp_timeout_open" , |
906 | .maxlen = sizeof(unsigned int), |
907 | .mode = 0644, |
908 | .proc_handler = proc_dointvec_jiffies, |
909 | }, |
910 | [NF_SYSCTL_CT_PROTO_TIMEOUT_DCCP_CLOSEREQ] = { |
911 | .procname = "nf_conntrack_dccp_timeout_closereq" , |
912 | .maxlen = sizeof(unsigned int), |
913 | .mode = 0644, |
914 | .proc_handler = proc_dointvec_jiffies, |
915 | }, |
916 | [NF_SYSCTL_CT_PROTO_TIMEOUT_DCCP_CLOSING] = { |
917 | .procname = "nf_conntrack_dccp_timeout_closing" , |
918 | .maxlen = sizeof(unsigned int), |
919 | .mode = 0644, |
920 | .proc_handler = proc_dointvec_jiffies, |
921 | }, |
922 | [NF_SYSCTL_CT_PROTO_TIMEOUT_DCCP_TIMEWAIT] = { |
923 | .procname = "nf_conntrack_dccp_timeout_timewait" , |
924 | .maxlen = sizeof(unsigned int), |
925 | .mode = 0644, |
926 | .proc_handler = proc_dointvec_jiffies, |
927 | }, |
928 | [NF_SYSCTL_CT_PROTO_DCCP_LOOSE] = { |
929 | .procname = "nf_conntrack_dccp_loose" , |
930 | .maxlen = sizeof(u8), |
931 | .mode = 0644, |
932 | .proc_handler = proc_dou8vec_minmax, |
933 | .extra1 = SYSCTL_ZERO, |
934 | .extra2 = SYSCTL_ONE, |
935 | }, |
936 | #endif |
937 | #ifdef CONFIG_NF_CT_PROTO_GRE |
938 | [NF_SYSCTL_CT_PROTO_TIMEOUT_GRE] = { |
939 | .procname = "nf_conntrack_gre_timeout" , |
940 | .maxlen = sizeof(unsigned int), |
941 | .mode = 0644, |
942 | .proc_handler = proc_dointvec_jiffies, |
943 | }, |
944 | [NF_SYSCTL_CT_PROTO_TIMEOUT_GRE_STREAM] = { |
945 | .procname = "nf_conntrack_gre_timeout_stream" , |
946 | .maxlen = sizeof(unsigned int), |
947 | .mode = 0644, |
948 | .proc_handler = proc_dointvec_jiffies, |
949 | }, |
950 | #endif |
951 | #ifdef CONFIG_LWTUNNEL |
952 | [NF_SYSCTL_CT_LWTUNNEL] = { |
953 | .procname = "nf_hooks_lwtunnel" , |
954 | .data = NULL, |
955 | .maxlen = sizeof(int), |
956 | .mode = 0644, |
957 | .proc_handler = nf_hooks_lwtunnel_sysctl_handler, |
958 | }, |
959 | #endif |
960 | {} |
961 | }; |
962 | |
963 | static struct ctl_table nf_ct_netfilter_table[] = { |
964 | { |
965 | .procname = "nf_conntrack_max" , |
966 | .data = &nf_conntrack_max, |
967 | .maxlen = sizeof(int), |
968 | .mode = 0644, |
969 | .proc_handler = proc_dointvec, |
970 | }, |
971 | { } |
972 | }; |
973 | |
974 | static void nf_conntrack_standalone_init_tcp_sysctl(struct net *net, |
975 | struct ctl_table *table) |
976 | { |
977 | struct nf_tcp_net *tn = nf_tcp_pernet(net); |
978 | |
979 | #define XASSIGN(XNAME, tn) \ |
980 | table[NF_SYSCTL_CT_PROTO_TIMEOUT_TCP_ ## XNAME].data = \ |
981 | &(tn)->timeouts[TCP_CONNTRACK_ ## XNAME] |
982 | |
983 | XASSIGN(SYN_SENT, tn); |
984 | XASSIGN(SYN_RECV, tn); |
985 | XASSIGN(ESTABLISHED, tn); |
986 | XASSIGN(FIN_WAIT, tn); |
987 | XASSIGN(CLOSE_WAIT, tn); |
988 | XASSIGN(LAST_ACK, tn); |
989 | XASSIGN(TIME_WAIT, tn); |
990 | XASSIGN(CLOSE, tn); |
991 | XASSIGN(RETRANS, tn); |
992 | XASSIGN(UNACK, tn); |
993 | #undef XASSIGN |
994 | #define XASSIGN(XNAME, rval) \ |
995 | table[NF_SYSCTL_CT_PROTO_TCP_ ## XNAME].data = (rval) |
996 | |
997 | XASSIGN(LOOSE, &tn->tcp_loose); |
998 | XASSIGN(LIBERAL, &tn->tcp_be_liberal); |
999 | XASSIGN(MAX_RETRANS, &tn->tcp_max_retrans); |
1000 | XASSIGN(IGNORE_INVALID_RST, &tn->tcp_ignore_invalid_rst); |
1001 | #undef XASSIGN |
1002 | |
1003 | #if IS_ENABLED(CONFIG_NF_FLOW_TABLE) |
1004 | table[NF_SYSCTL_CT_PROTO_TIMEOUT_TCP_OFFLOAD].data = &tn->offload_timeout; |
1005 | #endif |
1006 | |
1007 | } |
1008 | |
1009 | static void nf_conntrack_standalone_init_sctp_sysctl(struct net *net, |
1010 | struct ctl_table *table) |
1011 | { |
1012 | #ifdef CONFIG_NF_CT_PROTO_SCTP |
1013 | struct nf_sctp_net *sn = nf_sctp_pernet(net); |
1014 | |
1015 | #define XASSIGN(XNAME, sn) \ |
1016 | table[NF_SYSCTL_CT_PROTO_TIMEOUT_SCTP_ ## XNAME].data = \ |
1017 | &(sn)->timeouts[SCTP_CONNTRACK_ ## XNAME] |
1018 | |
1019 | XASSIGN(CLOSED, sn); |
1020 | XASSIGN(COOKIE_WAIT, sn); |
1021 | XASSIGN(COOKIE_ECHOED, sn); |
1022 | XASSIGN(ESTABLISHED, sn); |
1023 | XASSIGN(SHUTDOWN_SENT, sn); |
1024 | XASSIGN(SHUTDOWN_RECD, sn); |
1025 | XASSIGN(SHUTDOWN_ACK_SENT, sn); |
1026 | XASSIGN(HEARTBEAT_SENT, sn); |
1027 | #undef XASSIGN |
1028 | #endif |
1029 | } |
1030 | |
1031 | static void nf_conntrack_standalone_init_dccp_sysctl(struct net *net, |
1032 | struct ctl_table *table) |
1033 | { |
1034 | #ifdef CONFIG_NF_CT_PROTO_DCCP |
1035 | struct nf_dccp_net *dn = nf_dccp_pernet(net); |
1036 | |
1037 | #define XASSIGN(XNAME, dn) \ |
1038 | table[NF_SYSCTL_CT_PROTO_TIMEOUT_DCCP_ ## XNAME].data = \ |
1039 | &(dn)->dccp_timeout[CT_DCCP_ ## XNAME] |
1040 | |
1041 | XASSIGN(REQUEST, dn); |
1042 | XASSIGN(RESPOND, dn); |
1043 | XASSIGN(PARTOPEN, dn); |
1044 | XASSIGN(OPEN, dn); |
1045 | XASSIGN(CLOSEREQ, dn); |
1046 | XASSIGN(CLOSING, dn); |
1047 | XASSIGN(TIMEWAIT, dn); |
1048 | #undef XASSIGN |
1049 | |
1050 | table[NF_SYSCTL_CT_PROTO_DCCP_LOOSE].data = &dn->dccp_loose; |
1051 | #endif |
1052 | } |
1053 | |
1054 | static void nf_conntrack_standalone_init_gre_sysctl(struct net *net, |
1055 | struct ctl_table *table) |
1056 | { |
1057 | #ifdef CONFIG_NF_CT_PROTO_GRE |
1058 | struct nf_gre_net *gn = nf_gre_pernet(net); |
1059 | |
1060 | table[NF_SYSCTL_CT_PROTO_TIMEOUT_GRE].data = &gn->timeouts[GRE_CT_UNREPLIED]; |
1061 | table[NF_SYSCTL_CT_PROTO_TIMEOUT_GRE_STREAM].data = &gn->timeouts[GRE_CT_REPLIED]; |
1062 | #endif |
1063 | } |
1064 | |
1065 | static int nf_conntrack_standalone_init_sysctl(struct net *net) |
1066 | { |
1067 | struct nf_conntrack_net *cnet = nf_ct_pernet(net); |
1068 | struct nf_udp_net *un = nf_udp_pernet(net); |
1069 | struct ctl_table *table; |
1070 | |
1071 | BUILD_BUG_ON(ARRAY_SIZE(nf_ct_sysctl_table) != NF_SYSCTL_CT_LAST_SYSCTL); |
1072 | |
1073 | table = kmemdup(p: nf_ct_sysctl_table, size: sizeof(nf_ct_sysctl_table), |
1074 | GFP_KERNEL); |
1075 | if (!table) |
1076 | return -ENOMEM; |
1077 | |
1078 | table[NF_SYSCTL_CT_COUNT].data = &cnet->count; |
1079 | table[NF_SYSCTL_CT_CHECKSUM].data = &net->ct.sysctl_checksum; |
1080 | table[NF_SYSCTL_CT_LOG_INVALID].data = &net->ct.sysctl_log_invalid; |
1081 | table[NF_SYSCTL_CT_ACCT].data = &net->ct.sysctl_acct; |
1082 | #ifdef CONFIG_NF_CONNTRACK_EVENTS |
1083 | table[NF_SYSCTL_CT_EVENTS].data = &net->ct.sysctl_events; |
1084 | #endif |
1085 | #ifdef CONFIG_NF_CONNTRACK_TIMESTAMP |
1086 | table[NF_SYSCTL_CT_TIMESTAMP].data = &net->ct.sysctl_tstamp; |
1087 | #endif |
1088 | table[NF_SYSCTL_CT_PROTO_TIMEOUT_GENERIC].data = &nf_generic_pernet(net)->timeout; |
1089 | table[NF_SYSCTL_CT_PROTO_TIMEOUT_ICMP].data = &nf_icmp_pernet(net)->timeout; |
1090 | table[NF_SYSCTL_CT_PROTO_TIMEOUT_ICMPV6].data = &nf_icmpv6_pernet(net)->timeout; |
1091 | table[NF_SYSCTL_CT_PROTO_TIMEOUT_UDP].data = &un->timeouts[UDP_CT_UNREPLIED]; |
1092 | table[NF_SYSCTL_CT_PROTO_TIMEOUT_UDP_STREAM].data = &un->timeouts[UDP_CT_REPLIED]; |
1093 | #if IS_ENABLED(CONFIG_NF_FLOW_TABLE) |
1094 | table[NF_SYSCTL_CT_PROTO_TIMEOUT_UDP_OFFLOAD].data = &un->offload_timeout; |
1095 | #endif |
1096 | |
1097 | nf_conntrack_standalone_init_tcp_sysctl(net, table); |
1098 | nf_conntrack_standalone_init_sctp_sysctl(net, table); |
1099 | nf_conntrack_standalone_init_dccp_sysctl(net, table); |
1100 | nf_conntrack_standalone_init_gre_sysctl(net, table); |
1101 | |
1102 | /* Don't allow non-init_net ns to alter global sysctls */ |
1103 | if (!net_eq(net1: &init_net, net2: net)) { |
1104 | table[NF_SYSCTL_CT_MAX].mode = 0444; |
1105 | table[NF_SYSCTL_CT_EXPECT_MAX].mode = 0444; |
1106 | table[NF_SYSCTL_CT_BUCKETS].mode = 0444; |
1107 | } |
1108 | |
1109 | cnet->sysctl_header = register_net_sysctl_sz(net, path: "net/netfilter" , |
1110 | table, |
1111 | ARRAY_SIZE(nf_ct_sysctl_table)); |
1112 | if (!cnet->sysctl_header) |
1113 | goto out_unregister_netfilter; |
1114 | |
1115 | return 0; |
1116 | |
1117 | out_unregister_netfilter: |
1118 | kfree(objp: table); |
1119 | return -ENOMEM; |
1120 | } |
1121 | |
1122 | static void nf_conntrack_standalone_fini_sysctl(struct net *net) |
1123 | { |
1124 | struct nf_conntrack_net *cnet = nf_ct_pernet(net); |
1125 | struct ctl_table *table; |
1126 | |
1127 | table = cnet->sysctl_header->ctl_table_arg; |
1128 | unregister_net_sysctl_table(header: cnet->sysctl_header); |
1129 | kfree(objp: table); |
1130 | } |
1131 | #else |
1132 | static int nf_conntrack_standalone_init_sysctl(struct net *net) |
1133 | { |
1134 | return 0; |
1135 | } |
1136 | |
1137 | static void nf_conntrack_standalone_fini_sysctl(struct net *net) |
1138 | { |
1139 | } |
1140 | #endif /* CONFIG_SYSCTL */ |
1141 | |
1142 | static void nf_conntrack_fini_net(struct net *net) |
1143 | { |
1144 | if (enable_hooks) |
1145 | nf_ct_netns_put(net, nfproto: NFPROTO_INET); |
1146 | |
1147 | nf_conntrack_standalone_fini_proc(net); |
1148 | nf_conntrack_standalone_fini_sysctl(net); |
1149 | } |
1150 | |
1151 | static int nf_conntrack_pernet_init(struct net *net) |
1152 | { |
1153 | int ret; |
1154 | |
1155 | net->ct.sysctl_checksum = 1; |
1156 | |
1157 | ret = nf_conntrack_standalone_init_sysctl(net); |
1158 | if (ret < 0) |
1159 | return ret; |
1160 | |
1161 | ret = nf_conntrack_standalone_init_proc(net); |
1162 | if (ret < 0) |
1163 | goto out_proc; |
1164 | |
1165 | ret = nf_conntrack_init_net(net); |
1166 | if (ret < 0) |
1167 | goto out_init_net; |
1168 | |
1169 | if (enable_hooks) { |
1170 | ret = nf_ct_netns_get(net, nfproto: NFPROTO_INET); |
1171 | if (ret < 0) |
1172 | goto out_hooks; |
1173 | } |
1174 | |
1175 | return 0; |
1176 | |
1177 | out_hooks: |
1178 | nf_conntrack_cleanup_net(net); |
1179 | out_init_net: |
1180 | nf_conntrack_standalone_fini_proc(net); |
1181 | out_proc: |
1182 | nf_conntrack_standalone_fini_sysctl(net); |
1183 | return ret; |
1184 | } |
1185 | |
1186 | static void nf_conntrack_pernet_exit(struct list_head *net_exit_list) |
1187 | { |
1188 | struct net *net; |
1189 | |
1190 | list_for_each_entry(net, net_exit_list, exit_list) |
1191 | nf_conntrack_fini_net(net); |
1192 | |
1193 | nf_conntrack_cleanup_net_list(net_exit_list); |
1194 | } |
1195 | |
1196 | static struct pernet_operations nf_conntrack_net_ops = { |
1197 | .init = nf_conntrack_pernet_init, |
1198 | .exit_batch = nf_conntrack_pernet_exit, |
1199 | .id = &nf_conntrack_net_id, |
1200 | .size = sizeof(struct nf_conntrack_net), |
1201 | }; |
1202 | |
1203 | static int __init nf_conntrack_standalone_init(void) |
1204 | { |
1205 | int ret = nf_conntrack_init_start(); |
1206 | if (ret < 0) |
1207 | goto out_start; |
1208 | |
1209 | BUILD_BUG_ON(NFCT_INFOMASK <= IP_CT_NUMBER); |
1210 | |
1211 | #ifdef CONFIG_SYSCTL |
1212 | nf_ct_netfilter_header = |
1213 | register_net_sysctl(&init_net, "net" , nf_ct_netfilter_table); |
1214 | if (!nf_ct_netfilter_header) { |
1215 | pr_err("nf_conntrack: can't register to sysctl.\n" ); |
1216 | ret = -ENOMEM; |
1217 | goto out_sysctl; |
1218 | } |
1219 | |
1220 | nf_conntrack_htable_size_user = nf_conntrack_htable_size; |
1221 | #endif |
1222 | |
1223 | nf_conntrack_init_end(); |
1224 | |
1225 | ret = register_pernet_subsys(&nf_conntrack_net_ops); |
1226 | if (ret < 0) |
1227 | goto out_pernet; |
1228 | |
1229 | return 0; |
1230 | |
1231 | out_pernet: |
1232 | #ifdef CONFIG_SYSCTL |
1233 | unregister_net_sysctl_table(header: nf_ct_netfilter_header); |
1234 | out_sysctl: |
1235 | #endif |
1236 | nf_conntrack_cleanup_end(); |
1237 | out_start: |
1238 | return ret; |
1239 | } |
1240 | |
1241 | static void __exit nf_conntrack_standalone_fini(void) |
1242 | { |
1243 | nf_conntrack_cleanup_start(); |
1244 | unregister_pernet_subsys(&nf_conntrack_net_ops); |
1245 | #ifdef CONFIG_SYSCTL |
1246 | unregister_net_sysctl_table(header: nf_ct_netfilter_header); |
1247 | #endif |
1248 | nf_conntrack_cleanup_end(); |
1249 | } |
1250 | |
1251 | module_init(nf_conntrack_standalone_init); |
1252 | module_exit(nf_conntrack_standalone_fini); |
1253 | |