Commit | Line | Data |
---|---|---|
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> |
7a3f5b0d RS |
25 | #ifdef CONFIG_LWTUNNEL |
26 | #include <net/netfilter/nf_hooks_lwtunnel.h> | |
27 | #endif | |
0e60ebe0 | 28 | #include <linux/rculist_nulls.h> |
9fb9cbb1 | 29 | |
ba3fbe66 PNA |
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 | ||
a0ae2562 | 34 | unsigned int nf_conntrack_net_id __read_mostly; |
9fb9cbb1 | 35 | |
54b07dca | 36 | #ifdef CONFIG_NF_CONNTRACK_PROCFS |
824f1fbe | 37 | void |
9fb9cbb1 | 38 | print_tuple(struct seq_file *s, const struct nf_conntrack_tuple *tuple, |
32948588 | 39 | const struct nf_conntrack_l4proto *l4proto) |
9fb9cbb1 | 40 | { |
f957be9d | 41 | switch (tuple->src.l3num) { |
91950833 FW |
42 | case NFPROTO_IPV4: |
43 | seq_printf(s, "src=%pI4 dst=%pI4 ", | |
44 | &tuple->src.u3.ip, &tuple->dst.u3.ip); | |
45 | break; | |
46 | case NFPROTO_IPV6: | |
47 | seq_printf(s, "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(s, "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(s, "sport=%hu dport=%hu ", | |
63 | ntohs(tuple->src.u.tcp.port), | |
64 | ntohs(tuple->dst.u.tcp.port)); | |
65 | break; | |
954d8297 | 66 | case IPPROTO_UDPLITE: |
91950833 FW |
67 | case IPPROTO_UDP: |
68 | seq_printf(s, "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(s, "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(s, "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(s, "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(s, "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 | } | |
9fb9cbb1 | 97 | } |
e4bd8bce | 98 | EXPORT_SYMBOL_GPL(print_tuple); |
9fb9cbb1 | 99 | |
9fb9cbb1 | 100 | struct ct_iter_state { |
b2ce2c74 | 101 | struct seq_net_private p; |
64b87639 LZ |
102 | struct hlist_nulls_head *hash; |
103 | unsigned int htable_size; | |
9fb9cbb1 | 104 | unsigned int bucket; |
a992ca2a | 105 | u_int64_t time_now; |
9fb9cbb1 YK |
106 | }; |
107 | ||
ea781f19 | 108 | static struct hlist_nulls_node *ct_get_first(struct seq_file *seq) |
9fb9cbb1 YK |
109 | { |
110 | struct ct_iter_state *st = seq->private; | |
ea781f19 | 111 | struct hlist_nulls_node *n; |
9fb9cbb1 YK |
112 | |
113 | for (st->bucket = 0; | |
64b87639 | 114 | st->bucket < st->htable_size; |
9fb9cbb1 | 115 | st->bucket++) { |
64b87639 LZ |
116 | n = rcu_dereference( |
117 | hlist_nulls_first_rcu(&st->hash[st->bucket])); | |
ea781f19 | 118 | if (!is_a_nulls(n)) |
76507f69 | 119 | return n; |
9fb9cbb1 YK |
120 | } |
121 | return NULL; | |
122 | } | |
123 | ||
ea781f19 ED |
124 | static struct hlist_nulls_node *ct_get_next(struct seq_file *seq, |
125 | struct hlist_nulls_node *head) | |
9fb9cbb1 YK |
126 | { |
127 | struct ct_iter_state *st = seq->private; | |
128 | ||
0e60ebe0 | 129 | head = rcu_dereference(hlist_nulls_next_rcu(head)); |
ea781f19 ED |
130 | while (is_a_nulls(head)) { |
131 | if (likely(get_nulls_value(head) == st->bucket)) { | |
64b87639 | 132 | if (++st->bucket >= st->htable_size) |
ea781f19 ED |
133 | return NULL; |
134 | } | |
0e60ebe0 | 135 | head = rcu_dereference( |
64b87639 | 136 | hlist_nulls_first_rcu(&st->hash[st->bucket])); |
9fb9cbb1 YK |
137 | } |
138 | return head; | |
139 | } | |
140 | ||
ea781f19 | 141 | static struct hlist_nulls_node *ct_get_idx(struct seq_file *seq, loff_t pos) |
9fb9cbb1 | 142 | { |
ea781f19 | 143 | struct hlist_nulls_node *head = ct_get_first(seq); |
9fb9cbb1 YK |
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) | |
76507f69 | 152 | __acquires(RCU) |
9fb9cbb1 | 153 | { |
a992ca2a PNA |
154 | struct ct_iter_state *st = seq->private; |
155 | ||
d2de875c | 156 | st->time_now = ktime_get_real_ns(); |
76507f69 | 157 | rcu_read_lock(); |
64b87639 LZ |
158 | |
159 | nf_conntrack_get_ht(&st->hash, &st->htable_size); | |
9fb9cbb1 YK |
160 | return ct_get_idx(seq, *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(s, v); | |
167 | } | |
168 | ||
169 | static void ct_seq_stop(struct seq_file *s, void *v) | |
76507f69 | 170 | __releases(RCU) |
9fb9cbb1 | 171 | { |
76507f69 | 172 | rcu_read_unlock(); |
9fb9cbb1 YK |
173 | } |
174 | ||
1ae4de0c | 175 | #ifdef CONFIG_NF_CONNTRACK_SECMARK |
e71456ae | 176 | static void ct_show_secctx(struct seq_file *s, const struct nf_conn *ct) |
1ae4de0c EP |
177 | { |
178 | int ret; | |
179 | u32 len; | |
180 | char *secctx; | |
181 | ||
182 | ret = security_secid_to_secctx(ct->secmark, &secctx, &len); | |
183 | if (ret) | |
e71456ae | 184 | return; |
1ae4de0c | 185 | |
e71456ae | 186 | seq_printf(s, "secctx=%s ", secctx); |
1ae4de0c EP |
187 | |
188 | security_release_secctx(secctx, len); | |
1ae4de0c EP |
189 | } |
190 | #else | |
e71456ae | 191 | static inline void ct_show_secctx(struct seq_file *s, const struct nf_conn *ct) |
1ae4de0c | 192 | { |
1ae4de0c EP |
193 | } |
194 | #endif | |
195 | ||
308ac914 | 196 | #ifdef CONFIG_NF_CONNTRACK_ZONES |
deedb590 DB |
197 | static void ct_show_zone(struct seq_file *s, const struct nf_conn *ct, |
198 | int dir) | |
308ac914 | 199 | { |
deedb590 DB |
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(s, "zone=%u ", zone->id); | |
207 | break; | |
208 | case NF_CT_ZONE_DIR_ORIG: | |
209 | seq_printf(s, "zone-orig=%u ", zone->id); | |
210 | break; | |
211 | case NF_CT_ZONE_DIR_REPL: | |
212 | seq_printf(s, "zone-reply=%u ", zone->id); | |
213 | break; | |
214 | default: | |
215 | break; | |
216 | } | |
308ac914 DB |
217 | } |
218 | #else | |
deedb590 DB |
219 | static inline void ct_show_zone(struct seq_file *s, const struct nf_conn *ct, |
220 | int dir) | |
308ac914 DB |
221 | { |
222 | } | |
223 | #endif | |
224 | ||
a992ca2a | 225 | #ifdef CONFIG_NF_CONNTRACK_TIMESTAMP |
e71456ae | 226 | static void ct_show_delta_time(struct seq_file *s, const struct nf_conn *ct) |
a992ca2a | 227 | { |
f5c88f56 | 228 | struct ct_iter_state *st = s->private; |
a992ca2a | 229 | struct nf_conn_tstamp *tstamp; |
f5c88f56 | 230 | s64 delta_time; |
a992ca2a PNA |
231 | |
232 | tstamp = nf_conn_tstamp_find(ct); | |
233 | if (tstamp) { | |
f5c88f56 PM |
234 | delta_time = st->time_now - tstamp->start; |
235 | if (delta_time > 0) | |
236 | delta_time = div_s64(delta_time, NSEC_PER_SEC); | |
237 | else | |
238 | delta_time = 0; | |
239 | ||
e71456ae SRRH |
240 | seq_printf(s, "delta-time=%llu ", |
241 | (unsigned long long)delta_time); | |
a992ca2a | 242 | } |
e71456ae | 243 | return; |
a992ca2a PNA |
244 | } |
245 | #else | |
e71456ae | 246 | static inline void |
a992ca2a PNA |
247 | ct_show_delta_time(struct seq_file *s, const struct nf_conn *ct) |
248 | { | |
a992ca2a PNA |
249 | } |
250 | #endif | |
251 | ||
a3134d53 FW |
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 | ||
09ec82f5 FW |
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"; | |
fbea3180 | 272 | case IPPROTO_ICMPV6: return "icmpv6"; |
09ec82f5 FW |
273 | } |
274 | ||
275 | return "unknown"; | |
276 | } | |
277 | ||
f6477ec6 | 278 | static void |
4b216e21 FW |
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) | |
f6477ec6 | 286 | return; |
4b216e21 FW |
287 | |
288 | counter = acct->counter; | |
289 | seq_printf(s, "packets=%llu bytes=%llu ", | |
290 | (unsigned long long)atomic64_read(&counter[dir].packets), | |
291 | (unsigned long long)atomic64_read(&counter[dir].bytes)); | |
4b216e21 FW |
292 | } |
293 | ||
9fb9cbb1 YK |
294 | /* return 0 on success, 1 in case of error */ |
295 | static int ct_seq_show(struct seq_file *s, void *v) | |
296 | { | |
ea781f19 ED |
297 | struct nf_conntrack_tuple_hash *hash = v; |
298 | struct nf_conn *ct = nf_ct_tuplehash_to_ctrack(hash); | |
32948588 | 299 | const struct nf_conntrack_l4proto *l4proto; |
e77e6ff5 | 300 | struct net *net = seq_file_net(s); |
ea781f19 | 301 | int ret = 0; |
9fb9cbb1 | 302 | |
44d6e2f2 | 303 | WARN_ON(!ct); |
71977437 | 304 | if (unlikely(!refcount_inc_not_zero(&ct->ct_general.use))) |
ea781f19 | 305 | return 0; |
9fb9cbb1 | 306 | |
0ed8f619 FW |
307 | /* load ->status after refcount increase */ |
308 | smp_acquire__after_ctrl_dep(); | |
309 | ||
58e207e4 FW |
310 | if (nf_ct_should_gc(ct)) { |
311 | nf_ct_kill(ct); | |
312 | goto release; | |
313 | } | |
314 | ||
9fb9cbb1 YK |
315 | /* we only want to print DIR_ORIGINAL */ |
316 | if (NF_CT_DIRECTION(hash)) | |
ea781f19 | 317 | goto release; |
9fb9cbb1 | 318 | |
e77e6ff5 LZ |
319 | if (!net_eq(nf_ct_net(ct), net)) |
320 | goto release; | |
321 | ||
4a60dc74 | 322 | l4proto = nf_ct_l4proto_find(nf_ct_protonum(ct)); |
9fb9cbb1 | 323 | |
ea781f19 | 324 | ret = -ENOSPC; |
90964016 | 325 | seq_printf(s, "%-8s %u %-8s %u ", |
f957be9d | 326 | l3proto_name(nf_ct_l3num(ct)), nf_ct_l3num(ct), |
90964016 PNA |
327 | l4proto_name(l4proto->l4proto), nf_ct_protonum(ct)); |
328 | ||
329 | if (!test_bit(IPS_OFFLOAD_BIT, &ct->status)) | |
330 | seq_printf(s, "%ld ", nf_ct_expires(ct) / HZ); | |
9fb9cbb1 | 331 | |
37246a58 SRRH |
332 | if (l4proto->print_conntrack) |
333 | l4proto->print_conntrack(s, ct); | |
9fb9cbb1 | 334 | |
824f1fbe | 335 | print_tuple(s, &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple, |
f957be9d | 336 | l4proto); |
9fb9cbb1 | 337 | |
deedb590 DB |
338 | ct_show_zone(s, ct, NF_CT_ZONE_DIR_ORIG); |
339 | ||
e71456ae SRRH |
340 | if (seq_has_overflowed(s)) |
341 | goto release; | |
342 | ||
f6477ec6 | 343 | seq_print_acct(s, ct, IP_CT_DIR_ORIGINAL); |
9fb9cbb1 | 344 | |
c88130bc | 345 | if (!(test_bit(IPS_SEEN_REPLY_BIT, &ct->status))) |
cdec2685 | 346 | seq_puts(s, "[UNREPLIED] "); |
9fb9cbb1 | 347 | |
f957be9d | 348 | print_tuple(s, &ct->tuplehash[IP_CT_DIR_REPLY].tuple, l4proto); |
9fb9cbb1 | 349 | |
deedb590 DB |
350 | ct_show_zone(s, ct, NF_CT_ZONE_DIR_REPL); |
351 | ||
f6477ec6 | 352 | seq_print_acct(s, ct, IP_CT_DIR_REPLY); |
9fb9cbb1 | 353 | |
74f99482 BW |
354 | if (test_bit(IPS_HW_OFFLOAD_BIT, &ct->status)) |
355 | seq_puts(s, "[HW_OFFLOAD] "); | |
356 | else if (test_bit(IPS_OFFLOAD_BIT, &ct->status)) | |
90964016 PNA |
357 | seq_puts(s, "[OFFLOAD] "); |
358 | else if (test_bit(IPS_ASSURED_BIT, &ct->status)) | |
cdec2685 | 359 | seq_puts(s, "[ASSURED] "); |
9fb9cbb1 | 360 | |
e71456ae | 361 | if (seq_has_overflowed(s)) |
ea781f19 | 362 | goto release; |
e71456ae SRRH |
363 | |
364 | #if defined(CONFIG_NF_CONNTRACK_MARK) | |
52d1aa8b | 365 | seq_printf(s, "mark=%u ", READ_ONCE(ct->mark)); |
9fb9cbb1 YK |
366 | #endif |
367 | ||
e71456ae | 368 | ct_show_secctx(s, ct); |
deedb590 | 369 | ct_show_zone(s, ct, NF_CT_DEFAULT_ZONE_DIR); |
e71456ae SRRH |
370 | ct_show_delta_time(s, ct); |
371 | ||
71977437 | 372 | seq_printf(s, "use=%u\n", refcount_read(&ct->ct_general.use)); |
a992ca2a | 373 | |
e71456ae | 374 | if (seq_has_overflowed(s)) |
ea781f19 | 375 | goto release; |
a5d29264 | 376 | |
ea781f19 ED |
377 | ret = 0; |
378 | release: | |
379 | nf_ct_put(ct); | |
d88d7de0 | 380 | return ret; |
9fb9cbb1 YK |
381 | } |
382 | ||
56b3d975 | 383 | static const struct seq_operations ct_seq_ops = { |
9fb9cbb1 YK |
384 | .start = ct_seq_start, |
385 | .next = ct_seq_next, | |
386 | .stop = ct_seq_stop, | |
387 | .show = ct_seq_show | |
388 | }; | |
389 | ||
9fb9cbb1 YK |
390 | static void *ct_cpu_seq_start(struct seq_file *seq, loff_t *pos) |
391 | { | |
8e9df801 | 392 | struct net *net = seq_file_net(seq); |
9fb9cbb1 YK |
393 | int cpu; |
394 | ||
395 | if (*pos == 0) | |
396 | return SEQ_START_TOKEN; | |
397 | ||
0f23174a | 398 | for (cpu = *pos-1; cpu < nr_cpu_ids; ++cpu) { |
9fb9cbb1 YK |
399 | if (!cpu_possible(cpu)) |
400 | continue; | |
401 | *pos = cpu + 1; | |
8e9df801 | 402 | return per_cpu_ptr(net->ct.stat, cpu); |
9fb9cbb1 YK |
403 | } |
404 | ||
405 | return NULL; | |
406 | } | |
407 | ||
408 | static void *ct_cpu_seq_next(struct seq_file *seq, void *v, loff_t *pos) | |
409 | { | |
8e9df801 | 410 | struct net *net = seq_file_net(seq); |
9fb9cbb1 YK |
411 | int cpu; |
412 | ||
0f23174a | 413 | for (cpu = *pos; cpu < nr_cpu_ids; ++cpu) { |
9fb9cbb1 YK |
414 | if (!cpu_possible(cpu)) |
415 | continue; | |
416 | *pos = cpu + 1; | |
8e9df801 | 417 | return per_cpu_ptr(net->ct.stat, cpu); |
9fb9cbb1 | 418 | } |
dc15af8e | 419 | (*pos)++; |
9fb9cbb1 YK |
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 | { | |
8e9df801 | 429 | struct net *net = seq_file_net(seq); |
32948588 | 430 | const struct ip_conntrack_stat *st = v; |
c53bd0e9 | 431 | unsigned int nr_conntracks; |
9fb9cbb1 YK |
432 | |
433 | if (v == SEQ_START_TOKEN) { | |
d7e7747a | 434 | seq_puts(seq, "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"); |
9fb9cbb1 YK |
435 | return 0; |
436 | } | |
437 | ||
c53bd0e9 FW |
438 | nr_conntracks = nf_conntrack_count(net); |
439 | ||
9fb9cbb1 | 440 | seq_printf(seq, "%08x %08x %08x %08x %08x %08x %08x %08x " |
af740b2c | 441 | "%08x %08x %08x %08x %08x %08x %08x %08x %08x\n", |
9fb9cbb1 | 442 | nr_conntracks, |
1702ad79 | 443 | st->clash_resolve, |
9fb9cbb1 | 444 | st->found, |
8e8118f8 | 445 | 0, |
9fb9cbb1 | 446 | st->invalid, |
4afc41df | 447 | 0, |
8e8118f8 | 448 | 0, |
d7e7747a | 449 | st->chaintoolong, |
9fb9cbb1 YK |
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, | |
af740b2c JDB |
458 | st->expect_delete, |
459 | st->search_restart | |
9fb9cbb1 YK |
460 | ); |
461 | return 0; | |
462 | } | |
463 | ||
56b3d975 | 464 | static const struct seq_operations ct_cpu_seq_ops = { |
9fb9cbb1 YK |
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 | ||
b2ce2c74 | 471 | static int nf_conntrack_standalone_init_proc(struct net *net) |
b916f7d4 AD |
472 | { |
473 | struct proc_dir_entry *pde; | |
f13f2aee PW |
474 | kuid_t root_uid; |
475 | kgid_t root_gid; | |
b916f7d4 | 476 | |
c3506372 CH |
477 | pde = proc_create_net("nf_conntrack", 0440, net->proc_net, &ct_seq_ops, |
478 | sizeof(struct ct_iter_state)); | |
b916f7d4 AD |
479 | if (!pde) |
480 | goto out_nf_conntrack; | |
52c0e111 | 481 | |
f13f2aee PW |
482 | root_uid = make_kuid(net->user_ns, 0); |
483 | root_gid = make_kgid(net->user_ns, 0); | |
484 | if (uid_valid(root_uid) && gid_valid(root_gid)) | |
485 | proc_set_user(pde, root_uid, root_gid); | |
486 | ||
c3506372 CH |
487 | pde = proc_create_net("nf_conntrack", 0444, net->proc_net_stat, |
488 | &ct_cpu_seq_ops, sizeof(struct seq_net_private)); | |
b916f7d4 AD |
489 | if (!pde) |
490 | goto out_stat_nf_conntrack; | |
b916f7d4 AD |
491 | return 0; |
492 | ||
493 | out_stat_nf_conntrack: | |
ece31ffd | 494 | remove_proc_entry("nf_conntrack", net->proc_net); |
b916f7d4 AD |
495 | out_nf_conntrack: |
496 | return -ENOMEM; | |
497 | } | |
498 | ||
b2ce2c74 | 499 | static void nf_conntrack_standalone_fini_proc(struct net *net) |
b916f7d4 | 500 | { |
b2ce2c74 | 501 | remove_proc_entry("nf_conntrack", net->proc_net_stat); |
ece31ffd | 502 | remove_proc_entry("nf_conntrack", net->proc_net); |
b916f7d4 AD |
503 | } |
504 | #else | |
b2ce2c74 | 505 | static int nf_conntrack_standalone_init_proc(struct net *net) |
b916f7d4 AD |
506 | { |
507 | return 0; | |
508 | } | |
509 | ||
b2ce2c74 | 510 | static void nf_conntrack_standalone_fini_proc(struct net *net) |
b916f7d4 AD |
511 | { |
512 | } | |
54b07dca | 513 | #endif /* CONFIG_NF_CONNTRACK_PROCFS */ |
9fb9cbb1 | 514 | |
c53bd0e9 FW |
515 | u32 nf_conntrack_count(const struct net *net) |
516 | { | |
0418b989 | 517 | const struct nf_conntrack_net *cnet = nf_ct_pernet(net); |
c53bd0e9 FW |
518 | |
519 | return atomic_read(&cnet->count); | |
520 | } | |
521 | EXPORT_SYMBOL_GPL(nf_conntrack_count); | |
522 | ||
9fb9cbb1 YK |
523 | /* Sysctl support */ |
524 | ||
525 | #ifdef CONFIG_SYSCTL | |
3183ab89 FW |
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, | |
32927393 | 531 | void *buffer, size_t *lenp, loff_t *ppos) |
3183ab89 FW |
532 | { |
533 | int ret; | |
534 | ||
f6351c3f JDB |
535 | /* module_param hashsize could have changed value */ |
536 | nf_conntrack_htable_size_user = nf_conntrack_htable_size; | |
537 | ||
3183ab89 FW |
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(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 | } | |
9fb9cbb1 | 549 | |
9714be7d | 550 | static struct ctl_table_header *nf_ct_netfilter_header; |
9fb9cbb1 | 551 | |
4a65798a FW |
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, | |
d912dec1 | 559 | NF_SYSCTL_CT_ACCT, |
cb2833ed FW |
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 | |
b884fa46 FW |
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, | |
ef8ed5ea OS |
577 | #if IS_ENABLED(CONFIG_NF_FLOW_TABLE) |
578 | NF_SYSCTL_CT_PROTO_TIMEOUT_TCP_OFFLOAD, | |
ef8ed5ea | 579 | #endif |
b884fa46 FW |
580 | NF_SYSCTL_CT_PROTO_TCP_LOOSE, |
581 | NF_SYSCTL_CT_PROTO_TCP_LIBERAL, | |
1da4cd82 | 582 | NF_SYSCTL_CT_PROTO_TCP_IGNORE_INVALID_RST, |
b884fa46 FW |
583 | NF_SYSCTL_CT_PROTO_TCP_MAX_RETRANS, |
584 | NF_SYSCTL_CT_PROTO_TIMEOUT_UDP, | |
585 | NF_SYSCTL_CT_PROTO_TIMEOUT_UDP_STREAM, | |
975c5750 OS |
586 | #if IS_ENABLED(CONFIG_NF_FLOW_TABLE) |
587 | NF_SYSCTL_CT_PROTO_TIMEOUT_UDP_OFFLOAD, | |
975c5750 | 588 | #endif |
b884fa46 FW |
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, | |
b884fa46 FW |
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 | |
7a3f5b0d RS |
615 | #ifdef CONFIG_LWTUNNEL |
616 | NF_SYSCTL_CT_LWTUNNEL, | |
617 | #endif | |
b884fa46 FW |
618 | |
619 | __NF_SYSCTL_CT_LAST_SYSCTL, | |
4a65798a FW |
620 | }; |
621 | ||
b884fa46 FW |
622 | #define NF_SYSCTL_CT_LAST_SYSCTL (__NF_SYSCTL_CT_LAST_SYSCTL + 1) |
623 | ||
fe2c6338 | 624 | static struct ctl_table nf_ct_sysctl_table[] = { |
4a65798a | 625 | [NF_SYSCTL_CT_MAX] = { |
9fb9cbb1 YK |
626 | .procname = "nf_conntrack_max", |
627 | .data = &nf_conntrack_max, | |
628 | .maxlen = sizeof(int), | |
629 | .mode = 0644, | |
6d9f239a | 630 | .proc_handler = proc_dointvec, |
9fb9cbb1 | 631 | }, |
4a65798a | 632 | [NF_SYSCTL_CT_COUNT] = { |
9fb9cbb1 | 633 | .procname = "nf_conntrack_count", |
9fb9cbb1 YK |
634 | .maxlen = sizeof(int), |
635 | .mode = 0444, | |
6d9f239a | 636 | .proc_handler = proc_dointvec, |
9fb9cbb1 | 637 | }, |
4a65798a | 638 | [NF_SYSCTL_CT_BUCKETS] = { |
9fb9cbb1 | 639 | .procname = "nf_conntrack_buckets", |
3183ab89 | 640 | .data = &nf_conntrack_htable_size_user, |
9fb9cbb1 | 641 | .maxlen = sizeof(unsigned int), |
3183ab89 FW |
642 | .mode = 0644, |
643 | .proc_handler = nf_conntrack_hash_sysctl, | |
9fb9cbb1 | 644 | }, |
4a65798a | 645 | [NF_SYSCTL_CT_CHECKSUM] = { |
39a27a35 | 646 | .procname = "nf_conntrack_checksum", |
c04d0552 | 647 | .data = &init_net.ct.sysctl_checksum, |
9b1a4d0f | 648 | .maxlen = sizeof(u8), |
39a27a35 | 649 | .mode = 0644, |
9b1a4d0f | 650 | .proc_handler = proc_dou8vec_minmax, |
e84fb4b3 MC |
651 | .extra1 = SYSCTL_ZERO, |
652 | .extra2 = SYSCTL_ONE, | |
39a27a35 | 653 | }, |
4a65798a | 654 | [NF_SYSCTL_CT_LOG_INVALID] = { |
9fb9cbb1 | 655 | .procname = "nf_conntrack_log_invalid", |
c2a2c7e0 | 656 | .data = &init_net.ct.sysctl_log_invalid, |
9b1a4d0f | 657 | .maxlen = sizeof(u8), |
9fb9cbb1 | 658 | .mode = 0644, |
9b1a4d0f | 659 | .proc_handler = proc_dou8vec_minmax, |
9fb9cbb1 | 660 | }, |
4a65798a | 661 | [NF_SYSCTL_CT_EXPECT_MAX] = { |
f264a7df PM |
662 | .procname = "nf_conntrack_expect_max", |
663 | .data = &nf_ct_expect_max, | |
664 | .maxlen = sizeof(int), | |
665 | .mode = 0644, | |
6d9f239a | 666 | .proc_handler = proc_dointvec, |
f264a7df | 667 | }, |
d912dec1 FW |
668 | [NF_SYSCTL_CT_ACCT] = { |
669 | .procname = "nf_conntrack_acct", | |
670 | .data = &init_net.ct.sysctl_acct, | |
9b1a4d0f | 671 | .maxlen = sizeof(u8), |
d912dec1 | 672 | .mode = 0644, |
9b1a4d0f | 673 | .proc_handler = proc_dou8vec_minmax, |
e84fb4b3 MC |
674 | .extra1 = SYSCTL_ZERO, |
675 | .extra2 = SYSCTL_ONE, | |
d912dec1 | 676 | }, |
cb2833ed FW |
677 | #ifdef CONFIG_NF_CONNTRACK_EVENTS |
678 | [NF_SYSCTL_CT_EVENTS] = { | |
679 | .procname = "nf_conntrack_events", | |
680 | .data = &init_net.ct.sysctl_events, | |
9b1a4d0f | 681 | .maxlen = sizeof(u8), |
cb2833ed | 682 | .mode = 0644, |
9b1a4d0f | 683 | .proc_handler = proc_dou8vec_minmax, |
e84fb4b3 | 684 | .extra1 = SYSCTL_ZERO, |
90d1daa4 | 685 | .extra2 = SYSCTL_TWO, |
cb2833ed FW |
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, | |
9b1a4d0f | 692 | .maxlen = sizeof(u8), |
cb2833ed | 693 | .mode = 0644, |
9b1a4d0f | 694 | .proc_handler = proc_dou8vec_minmax, |
e84fb4b3 MC |
695 | .extra1 = SYSCTL_ZERO, |
696 | .extra2 = SYSCTL_ONE, | |
cb2833ed FW |
697 | }, |
698 | #endif | |
b884fa46 FW |
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 | }, | |
ef8ed5ea OS |
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 | }, | |
ef8ed5ea | 772 | #endif |
b884fa46 FW |
773 | [NF_SYSCTL_CT_PROTO_TCP_LOOSE] = { |
774 | .procname = "nf_conntrack_tcp_loose", | |
9b1a4d0f | 775 | .maxlen = sizeof(u8), |
b884fa46 | 776 | .mode = 0644, |
9b1a4d0f | 777 | .proc_handler = proc_dou8vec_minmax, |
e84fb4b3 MC |
778 | .extra1 = SYSCTL_ZERO, |
779 | .extra2 = SYSCTL_ONE, | |
b884fa46 FW |
780 | }, |
781 | [NF_SYSCTL_CT_PROTO_TCP_LIBERAL] = { | |
782 | .procname = "nf_conntrack_tcp_be_liberal", | |
9b1a4d0f | 783 | .maxlen = sizeof(u8), |
b884fa46 | 784 | .mode = 0644, |
9b1a4d0f | 785 | .proc_handler = proc_dou8vec_minmax, |
e84fb4b3 MC |
786 | .extra1 = SYSCTL_ZERO, |
787 | .extra2 = SYSCTL_ONE, | |
b884fa46 | 788 | }, |
1da4cd82 AA |
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 | }, | |
b884fa46 FW |
797 | [NF_SYSCTL_CT_PROTO_TCP_MAX_RETRANS] = { |
798 | .procname = "nf_conntrack_tcp_max_retrans", | |
9b1a4d0f | 799 | .maxlen = sizeof(u8), |
b884fa46 | 800 | .mode = 0644, |
9b1a4d0f | 801 | .proc_handler = proc_dou8vec_minmax, |
b884fa46 FW |
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 | }, | |
626873c4 | 815 | #if IS_ENABLED(CONFIG_NF_FLOW_TABLE) |
975c5750 OS |
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 | }, | |
975c5750 | 822 | #endif |
b884fa46 FW |
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 | }, | |
b884fa46 FW |
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", | |
9b1a4d0f | 930 | .maxlen = sizeof(u8), |
b884fa46 | 931 | .mode = 0644, |
9b1a4d0f | 932 | .proc_handler = proc_dou8vec_minmax, |
e84fb4b3 MC |
933 | .extra1 = SYSCTL_ZERO, |
934 | .extra2 = SYSCTL_ONE, | |
b884fa46 FW |
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 | }, | |
7a3f5b0d RS |
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 | }, | |
b884fa46 FW |
959 | #endif |
960 | {} | |
9fb9cbb1 YK |
961 | }; |
962 | ||
fe2c6338 | 963 | static struct ctl_table nf_ct_netfilter_table[] = { |
9fb9cbb1 | 964 | { |
9fb9cbb1 YK |
965 | .procname = "nf_conntrack_max", |
966 | .data = &nf_conntrack_max, | |
967 | .maxlen = sizeof(int), | |
968 | .mode = 0644, | |
6d9f239a | 969 | .proc_handler = proc_dointvec, |
9fb9cbb1 | 970 | }, |
f8572d8f | 971 | { } |
9fb9cbb1 YK |
972 | }; |
973 | ||
b884fa46 FW |
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); | |
1da4cd82 | 1000 | XASSIGN(IGNORE_INVALID_RST, &tn->tcp_ignore_invalid_rst); |
b884fa46 | 1001 | #undef XASSIGN |
ef8ed5ea OS |
1002 | |
1003 | #if IS_ENABLED(CONFIG_NF_FLOW_TABLE) | |
1004 | table[NF_SYSCTL_CT_PROTO_TIMEOUT_TCP_OFFLOAD].data = &tn->offload_timeout; | |
ef8ed5ea OS |
1005 | #endif |
1006 | ||
b884fa46 FW |
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); | |
b884fa46 FW |
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 | ||
80250707 | 1065 | static int nf_conntrack_standalone_init_sysctl(struct net *net) |
b916f7d4 | 1066 | { |
0418b989 | 1067 | struct nf_conntrack_net *cnet = nf_ct_pernet(net); |
b884fa46 | 1068 | struct nf_udp_net *un = nf_udp_pernet(net); |
80250707 AD |
1069 | struct ctl_table *table; |
1070 | ||
b884fa46 FW |
1071 | BUILD_BUG_ON(ARRAY_SIZE(nf_ct_sysctl_table) != NF_SYSCTL_CT_LAST_SYSCTL); |
1072 | ||
80250707 AD |
1073 | table = kmemdup(nf_ct_sysctl_table, sizeof(nf_ct_sysctl_table), |
1074 | GFP_KERNEL); | |
1075 | if (!table) | |
b884fa46 | 1076 | return -ENOMEM; |
80250707 | 1077 | |
c53bd0e9 | 1078 | table[NF_SYSCTL_CT_COUNT].data = &cnet->count; |
4a65798a FW |
1079 | table[NF_SYSCTL_CT_CHECKSUM].data = &net->ct.sysctl_checksum; |
1080 | table[NF_SYSCTL_CT_LOG_INVALID].data = &net->ct.sysctl_log_invalid; | |
478553fd | 1081 | table[NF_SYSCTL_CT_ACCT].data = &net->ct.sysctl_acct; |
cb2833ed FW |
1082 | #ifdef CONFIG_NF_CONNTRACK_EVENTS |
1083 | table[NF_SYSCTL_CT_EVENTS].data = &net->ct.sysctl_events; | |
478553fd FW |
1084 | #endif |
1085 | #ifdef CONFIG_NF_CONNTRACK_TIMESTAMP | |
1086 | table[NF_SYSCTL_CT_TIMESTAMP].data = &net->ct.sysctl_tstamp; | |
cb2833ed | 1087 | #endif |
b884fa46 FW |
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]; | |
975c5750 OS |
1093 | #if IS_ENABLED(CONFIG_NF_FLOW_TABLE) |
1094 | table[NF_SYSCTL_CT_PROTO_TIMEOUT_UDP_OFFLOAD].data = &un->offload_timeout; | |
975c5750 | 1095 | #endif |
b884fa46 FW |
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); | |
80250707 | 1101 | |
2671fa4d JR |
1102 | /* Don't allow non-init_net ns to alter global sysctls */ |
1103 | if (!net_eq(&init_net, net)) { | |
d0febd81 FW |
1104 | table[NF_SYSCTL_CT_MAX].mode = 0444; |
1105 | table[NF_SYSCTL_CT_EXPECT_MAX].mode = 0444; | |
d0febd81 FW |
1106 | table[NF_SYSCTL_CT_BUCKETS].mode = 0444; |
1107 | } | |
3183ab89 | 1108 | |
385a5dc9 JG |
1109 | cnet->sysctl_header = register_net_sysctl_sz(net, "net/netfilter", |
1110 | table, | |
1111 | ARRAY_SIZE(nf_ct_sysctl_table)); | |
7b597470 | 1112 | if (!cnet->sysctl_header) |
9714be7d KPO |
1113 | goto out_unregister_netfilter; |
1114 | ||
b916f7d4 AD |
1115 | return 0; |
1116 | ||
9714be7d | 1117 | out_unregister_netfilter: |
80250707 | 1118 | kfree(table); |
9714be7d | 1119 | return -ENOMEM; |
b916f7d4 AD |
1120 | } |
1121 | ||
80250707 | 1122 | static void nf_conntrack_standalone_fini_sysctl(struct net *net) |
b916f7d4 | 1123 | { |
0418b989 | 1124 | struct nf_conntrack_net *cnet = nf_ct_pernet(net); |
80250707 AD |
1125 | struct ctl_table *table; |
1126 | ||
7b597470 FW |
1127 | table = cnet->sysctl_header->ctl_table_arg; |
1128 | unregister_net_sysctl_table(cnet->sysctl_header); | |
80250707 | 1129 | kfree(table); |
b916f7d4 AD |
1130 | } |
1131 | #else | |
80250707 | 1132 | static int nf_conntrack_standalone_init_sysctl(struct net *net) |
b916f7d4 AD |
1133 | { |
1134 | return 0; | |
1135 | } | |
1136 | ||
80250707 | 1137 | static void nf_conntrack_standalone_fini_sysctl(struct net *net) |
b916f7d4 AD |
1138 | { |
1139 | } | |
9fb9cbb1 YK |
1140 | #endif /* CONFIG_SYSCTL */ |
1141 | ||
ba3fbe66 PNA |
1142 | static void nf_conntrack_fini_net(struct net *net) |
1143 | { | |
1144 | if (enable_hooks) | |
1145 | nf_ct_netns_put(net, NFPROTO_INET); | |
1146 | ||
1147 | nf_conntrack_standalone_fini_proc(net); | |
1148 | nf_conntrack_standalone_fini_sysctl(net); | |
1149 | } | |
1150 | ||
f94161c1 | 1151 | static int nf_conntrack_pernet_init(struct net *net) |
dfdb8d79 | 1152 | { |
b2ce2c74 AD |
1153 | int ret; |
1154 | ||
b884fa46 FW |
1155 | net->ct.sysctl_checksum = 1; |
1156 | ||
1157 | ret = nf_conntrack_standalone_init_sysctl(net); | |
b2ce2c74 | 1158 | if (ret < 0) |
b884fa46 | 1159 | return ret; |
f94161c1 | 1160 | |
b2ce2c74 AD |
1161 | ret = nf_conntrack_standalone_init_proc(net); |
1162 | if (ret < 0) | |
1163 | goto out_proc; | |
f94161c1 | 1164 | |
b884fa46 | 1165 | ret = nf_conntrack_init_net(net); |
80250707 | 1166 | if (ret < 0) |
b884fa46 | 1167 | goto out_init_net; |
f94161c1 | 1168 | |
ba3fbe66 PNA |
1169 | if (enable_hooks) { |
1170 | ret = nf_ct_netns_get(net, NFPROTO_INET); | |
1171 | if (ret < 0) | |
1172 | goto out_hooks; | |
1173 | } | |
1174 | ||
b2ce2c74 AD |
1175 | return 0; |
1176 | ||
ba3fbe66 | 1177 | out_hooks: |
ac088a88 | 1178 | nf_conntrack_cleanup_net(net); |
b884fa46 | 1179 | out_init_net: |
80250707 | 1180 | nf_conntrack_standalone_fini_proc(net); |
b2ce2c74 | 1181 | out_proc: |
ac088a88 | 1182 | nf_conntrack_standalone_fini_sysctl(net); |
b2ce2c74 | 1183 | return ret; |
dfdb8d79 AD |
1184 | } |
1185 | ||
dece40e8 | 1186 | static void nf_conntrack_pernet_exit(struct list_head *net_exit_list) |
dfdb8d79 | 1187 | { |
dece40e8 VD |
1188 | struct net *net; |
1189 | ||
ba3fbe66 PNA |
1190 | list_for_each_entry(net, net_exit_list, exit_list) |
1191 | nf_conntrack_fini_net(net); | |
1192 | ||
dece40e8 | 1193 | nf_conntrack_cleanup_net_list(net_exit_list); |
dfdb8d79 AD |
1194 | } |
1195 | ||
1196 | static struct pernet_operations nf_conntrack_net_ops = { | |
dece40e8 VD |
1197 | .init = nf_conntrack_pernet_init, |
1198 | .exit_batch = nf_conntrack_pernet_exit, | |
a0ae2562 FW |
1199 | .id = &nf_conntrack_net_id, |
1200 | .size = sizeof(struct nf_conntrack_net), | |
dfdb8d79 AD |
1201 | }; |
1202 | ||
65b4b4e8 | 1203 | static int __init nf_conntrack_standalone_init(void) |
9fb9cbb1 | 1204 | { |
f94161c1 G |
1205 | int ret = nf_conntrack_init_start(); |
1206 | if (ret < 0) | |
1207 | goto out_start; | |
1208 | ||
a9e419dc FW |
1209 | BUILD_BUG_ON(NFCT_INFOMASK <= IP_CT_NUMBER); |
1210 | ||
5f9f946b | 1211 | #ifdef CONFIG_SYSCTL |
f94161c1 G |
1212 | nf_ct_netfilter_header = |
1213 | register_net_sysctl(&init_net, "net", nf_ct_netfilter_table); | |
5f9f946b PNA |
1214 | if (!nf_ct_netfilter_header) { |
1215 | pr_err("nf_conntrack: can't register to sysctl.\n"); | |
5389090b | 1216 | ret = -ENOMEM; |
f94161c1 | 1217 | goto out_sysctl; |
5f9f946b | 1218 | } |
3183ab89 FW |
1219 | |
1220 | nf_conntrack_htable_size_user = nf_conntrack_htable_size; | |
5f9f946b | 1221 | #endif |
f94161c1 | 1222 | |
e72eeab5 FW |
1223 | nf_conntrack_init_end(); |
1224 | ||
f94161c1 G |
1225 | ret = register_pernet_subsys(&nf_conntrack_net_ops); |
1226 | if (ret < 0) | |
1227 | goto out_pernet; | |
1228 | ||
f94161c1 G |
1229 | return 0; |
1230 | ||
1231 | out_pernet: | |
5f9f946b | 1232 | #ifdef CONFIG_SYSCTL |
f94161c1 G |
1233 | unregister_net_sysctl_table(nf_ct_netfilter_header); |
1234 | out_sysctl: | |
5f9f946b | 1235 | #endif |
f94161c1 G |
1236 | nf_conntrack_cleanup_end(); |
1237 | out_start: | |
1238 | return ret; | |
9fb9cbb1 YK |
1239 | } |
1240 | ||
65b4b4e8 | 1241 | static void __exit nf_conntrack_standalone_fini(void) |
9fb9cbb1 | 1242 | { |
f94161c1 | 1243 | nf_conntrack_cleanup_start(); |
dfdb8d79 | 1244 | unregister_pernet_subsys(&nf_conntrack_net_ops); |
5f9f946b | 1245 | #ifdef CONFIG_SYSCTL |
f94161c1 | 1246 | unregister_net_sysctl_table(nf_ct_netfilter_header); |
5f9f946b | 1247 | #endif |
1e47ee83 | 1248 | nf_conntrack_cleanup_end(); |
9fb9cbb1 YK |
1249 | } |
1250 | ||
65b4b4e8 AM |
1251 | module_init(nf_conntrack_standalone_init); |
1252 | module_exit(nf_conntrack_standalone_fini); |