diff options
-rw-r--r-- | include/linux/netfilter/Kbuild | 1 | ||||
-rw-r--r-- | include/linux/netfilter/nfnetlink.h | 3 | ||||
-rw-r--r-- | include/linux/netfilter/nfnetlink_cttimeout.h | 114 | ||||
-rw-r--r-- | include/net/netfilter/nf_conntrack_l4proto.h | 11 | ||||
-rw-r--r-- | net/ipv4/netfilter/nf_conntrack_proto_icmp.c | 47 | ||||
-rw-r--r-- | net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c | 47 | ||||
-rw-r--r-- | net/netfilter/Kconfig | 11 | ||||
-rw-r--r-- | net/netfilter/Makefile | 1 | ||||
-rw-r--r-- | net/netfilter/nf_conntrack_proto_dccp.c | 70 | ||||
-rw-r--r-- | net/netfilter/nf_conntrack_proto_generic.c | 48 | ||||
-rw-r--r-- | net/netfilter/nf_conntrack_proto_gre.c | 55 | ||||
-rw-r--r-- | net/netfilter/nf_conntrack_proto_sctp.c | 69 | ||||
-rw-r--r-- | net/netfilter/nf_conntrack_proto_tcp.c | 127 | ||||
-rw-r--r-- | net/netfilter/nf_conntrack_proto_udp.c | 64 | ||||
-rw-r--r-- | net/netfilter/nf_conntrack_proto_udplite.c | 66 | ||||
-rw-r--r-- | net/netfilter/nfnetlink_cttimeout.c | 398 |
16 files changed, 1131 insertions, 1 deletions
diff --git a/include/linux/netfilter/Kbuild b/include/linux/netfilter/Kbuild index aaa72aaa21de..1697036336b6 100644 --- a/include/linux/netfilter/Kbuild +++ b/include/linux/netfilter/Kbuild | |||
@@ -10,6 +10,7 @@ header-y += nfnetlink.h | |||
10 | header-y += nfnetlink_acct.h | 10 | header-y += nfnetlink_acct.h |
11 | header-y += nfnetlink_compat.h | 11 | header-y += nfnetlink_compat.h |
12 | header-y += nfnetlink_conntrack.h | 12 | header-y += nfnetlink_conntrack.h |
13 | header-y += nfnetlink_cttimeout.h | ||
13 | header-y += nfnetlink_log.h | 14 | header-y += nfnetlink_log.h |
14 | header-y += nfnetlink_queue.h | 15 | header-y += nfnetlink_queue.h |
15 | header-y += x_tables.h | 16 | header-y += x_tables.h |
diff --git a/include/linux/netfilter/nfnetlink.h b/include/linux/netfilter/nfnetlink.h index b64454c2f79f..6fd1f0d07e64 100644 --- a/include/linux/netfilter/nfnetlink.h +++ b/include/linux/netfilter/nfnetlink.h | |||
@@ -49,7 +49,8 @@ struct nfgenmsg { | |||
49 | #define NFNL_SUBSYS_OSF 5 | 49 | #define NFNL_SUBSYS_OSF 5 |
50 | #define NFNL_SUBSYS_IPSET 6 | 50 | #define NFNL_SUBSYS_IPSET 6 |
51 | #define NFNL_SUBSYS_ACCT 7 | 51 | #define NFNL_SUBSYS_ACCT 7 |
52 | #define NFNL_SUBSYS_COUNT 8 | 52 | #define NFNL_SUBSYS_CTNETLINK_TIMEOUT 8 |
53 | #define NFNL_SUBSYS_COUNT 9 | ||
53 | 54 | ||
54 | #ifdef __KERNEL__ | 55 | #ifdef __KERNEL__ |
55 | 56 | ||
diff --git a/include/linux/netfilter/nfnetlink_cttimeout.h b/include/linux/netfilter/nfnetlink_cttimeout.h new file mode 100644 index 000000000000..a2810a7c5e30 --- /dev/null +++ b/include/linux/netfilter/nfnetlink_cttimeout.h | |||
@@ -0,0 +1,114 @@ | |||
1 | #ifndef _CTTIMEOUT_NETLINK_H | ||
2 | #define _CTTIMEOUT_NETLINK_H | ||
3 | #include <linux/netfilter/nfnetlink.h> | ||
4 | |||
5 | enum ctnl_timeout_msg_types { | ||
6 | IPCTNL_MSG_TIMEOUT_NEW, | ||
7 | IPCTNL_MSG_TIMEOUT_GET, | ||
8 | IPCTNL_MSG_TIMEOUT_DELETE, | ||
9 | |||
10 | IPCTNL_MSG_TIMEOUT_MAX | ||
11 | }; | ||
12 | |||
13 | enum ctattr_timeout { | ||
14 | CTA_TIMEOUT_UNSPEC, | ||
15 | CTA_TIMEOUT_NAME, | ||
16 | CTA_TIMEOUT_L3PROTO, | ||
17 | CTA_TIMEOUT_L4PROTO, | ||
18 | CTA_TIMEOUT_DATA, | ||
19 | CTA_TIMEOUT_USE, | ||
20 | __CTA_TIMEOUT_MAX | ||
21 | }; | ||
22 | #define CTA_TIMEOUT_MAX (__CTA_TIMEOUT_MAX - 1) | ||
23 | |||
24 | enum ctattr_timeout_generic { | ||
25 | CTA_TIMEOUT_GENERIC_UNSPEC, | ||
26 | CTA_TIMEOUT_GENERIC_TIMEOUT, | ||
27 | __CTA_TIMEOUT_GENERIC_MAX | ||
28 | }; | ||
29 | #define CTA_TIMEOUT_GENERIC_MAX (__CTA_TIMEOUT_GENERIC_MAX - 1) | ||
30 | |||
31 | enum ctattr_timeout_tcp { | ||
32 | CTA_TIMEOUT_TCP_UNSPEC, | ||
33 | CTA_TIMEOUT_TCP_SYN_SENT, | ||
34 | CTA_TIMEOUT_TCP_SYN_RECV, | ||
35 | CTA_TIMEOUT_TCP_ESTABLISHED, | ||
36 | CTA_TIMEOUT_TCP_FIN_WAIT, | ||
37 | CTA_TIMEOUT_TCP_CLOSE_WAIT, | ||
38 | CTA_TIMEOUT_TCP_LAST_ACK, | ||
39 | CTA_TIMEOUT_TCP_TIME_WAIT, | ||
40 | CTA_TIMEOUT_TCP_CLOSE, | ||
41 | CTA_TIMEOUT_TCP_SYN_SENT2, | ||
42 | CTA_TIMEOUT_TCP_RETRANS, | ||
43 | CTA_TIMEOUT_TCP_UNACK, | ||
44 | __CTA_TIMEOUT_TCP_MAX | ||
45 | }; | ||
46 | #define CTA_TIMEOUT_TCP_MAX (__CTA_TIMEOUT_TCP_MAX - 1) | ||
47 | |||
48 | enum ctattr_timeout_udp { | ||
49 | CTA_TIMEOUT_UDP_UNSPEC, | ||
50 | CTA_TIMEOUT_UDP_UNREPLIED, | ||
51 | CTA_TIMEOUT_UDP_REPLIED, | ||
52 | __CTA_TIMEOUT_UDP_MAX | ||
53 | }; | ||
54 | #define CTA_TIMEOUT_UDP_MAX (__CTA_TIMEOUT_UDP_MAX - 1) | ||
55 | |||
56 | enum ctattr_timeout_udplite { | ||
57 | CTA_TIMEOUT_UDPLITE_UNSPEC, | ||
58 | CTA_TIMEOUT_UDPLITE_UNREPLIED, | ||
59 | CTA_TIMEOUT_UDPLITE_REPLIED, | ||
60 | __CTA_TIMEOUT_UDPLITE_MAX | ||
61 | }; | ||
62 | #define CTA_TIMEOUT_UDPLITE_MAX (__CTA_TIMEOUT_UDPLITE_MAX - 1) | ||
63 | |||
64 | enum ctattr_timeout_icmp { | ||
65 | CTA_TIMEOUT_ICMP_UNSPEC, | ||
66 | CTA_TIMEOUT_ICMP_TIMEOUT, | ||
67 | __CTA_TIMEOUT_ICMP_MAX | ||
68 | }; | ||
69 | #define CTA_TIMEOUT_ICMP_MAX (__CTA_TIMEOUT_ICMP_MAX - 1) | ||
70 | |||
71 | enum ctattr_timeout_dccp { | ||
72 | CTA_TIMEOUT_DCCP_UNSPEC, | ||
73 | CTA_TIMEOUT_DCCP_REQUEST, | ||
74 | CTA_TIMEOUT_DCCP_RESPOND, | ||
75 | CTA_TIMEOUT_DCCP_PARTOPEN, | ||
76 | CTA_TIMEOUT_DCCP_OPEN, | ||
77 | CTA_TIMEOUT_DCCP_CLOSEREQ, | ||
78 | CTA_TIMEOUT_DCCP_CLOSING, | ||
79 | CTA_TIMEOUT_DCCP_TIMEWAIT, | ||
80 | __CTA_TIMEOUT_DCCP_MAX | ||
81 | }; | ||
82 | #define CTA_TIMEOUT_DCCP_MAX (__CTA_TIMEOUT_DCCP_MAX - 1) | ||
83 | |||
84 | enum ctattr_timeout_sctp { | ||
85 | CTA_TIMEOUT_SCTP_UNSPEC, | ||
86 | CTA_TIMEOUT_SCTP_CLOSED, | ||
87 | CTA_TIMEOUT_SCTP_COOKIE_WAIT, | ||
88 | CTA_TIMEOUT_SCTP_COOKIE_ECHOED, | ||
89 | CTA_TIMEOUT_SCTP_ESTABLISHED, | ||
90 | CTA_TIMEOUT_SCTP_SHUTDOWN_SENT, | ||
91 | CTA_TIMEOUT_SCTP_SHUTDOWN_RECD, | ||
92 | CTA_TIMEOUT_SCTP_SHUTDOWN_ACK_SENT, | ||
93 | __CTA_TIMEOUT_SCTP_MAX | ||
94 | }; | ||
95 | #define CTA_TIMEOUT_SCTP_MAX (__CTA_TIMEOUT_SCTP_MAX - 1) | ||
96 | |||
97 | enum ctattr_timeout_icmpv6 { | ||
98 | CTA_TIMEOUT_ICMPV6_UNSPEC, | ||
99 | CTA_TIMEOUT_ICMPV6_TIMEOUT, | ||
100 | __CTA_TIMEOUT_ICMPV6_MAX | ||
101 | }; | ||
102 | #define CTA_TIMEOUT_ICMPV6_MAX (__CTA_TIMEOUT_ICMPV6_MAX - 1) | ||
103 | |||
104 | enum ctattr_timeout_gre { | ||
105 | CTA_TIMEOUT_GRE_UNSPEC, | ||
106 | CTA_TIMEOUT_GRE_UNREPLIED, | ||
107 | CTA_TIMEOUT_GRE_REPLIED, | ||
108 | __CTA_TIMEOUT_GRE_MAX | ||
109 | }; | ||
110 | #define CTA_TIMEOUT_GRE_MAX (__CTA_TIMEOUT_GRE_MAX - 1) | ||
111 | |||
112 | #define CTNL_TIMEOUT_NAME_MAX 32 | ||
113 | |||
114 | #endif | ||
diff --git a/include/net/netfilter/nf_conntrack_l4proto.h b/include/net/netfilter/nf_conntrack_l4proto.h index c48b67405aa0..90c67c7db7e9 100644 --- a/include/net/netfilter/nf_conntrack_l4proto.h +++ b/include/net/netfilter/nf_conntrack_l4proto.h | |||
@@ -83,6 +83,17 @@ struct nf_conntrack_l4proto { | |||
83 | 83 | ||
84 | size_t nla_size; | 84 | size_t nla_size; |
85 | 85 | ||
86 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT) | ||
87 | struct { | ||
88 | size_t obj_size; | ||
89 | int (*nlattr_to_obj)(struct nlattr *tb[], void *data); | ||
90 | int (*obj_to_nlattr)(struct sk_buff *skb, const void *data); | ||
91 | |||
92 | unsigned int nlattr_max; | ||
93 | const struct nla_policy *nla_policy; | ||
94 | } ctnl_timeout; | ||
95 | #endif | ||
96 | |||
86 | #ifdef CONFIG_SYSCTL | 97 | #ifdef CONFIG_SYSCTL |
87 | struct ctl_table_header **ctl_table_header; | 98 | struct ctl_table_header **ctl_table_header; |
88 | struct ctl_table *ctl_table; | 99 | struct ctl_table *ctl_table; |
diff --git a/net/ipv4/netfilter/nf_conntrack_proto_icmp.c b/net/ipv4/netfilter/nf_conntrack_proto_icmp.c index 6b801124b31f..7cbe9cb261c2 100644 --- a/net/ipv4/netfilter/nf_conntrack_proto_icmp.c +++ b/net/ipv4/netfilter/nf_conntrack_proto_icmp.c | |||
@@ -269,6 +269,44 @@ static int icmp_nlattr_tuple_size(void) | |||
269 | } | 269 | } |
270 | #endif | 270 | #endif |
271 | 271 | ||
272 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT) | ||
273 | |||
274 | #include <linux/netfilter/nfnetlink.h> | ||
275 | #include <linux/netfilter/nfnetlink_cttimeout.h> | ||
276 | |||
277 | static int icmp_timeout_nlattr_to_obj(struct nlattr *tb[], void *data) | ||
278 | { | ||
279 | unsigned int *timeout = data; | ||
280 | |||
281 | if (tb[CTA_TIMEOUT_ICMP_TIMEOUT]) { | ||
282 | *timeout = | ||
283 | ntohl(nla_get_be32(tb[CTA_TIMEOUT_ICMP_TIMEOUT])) * HZ; | ||
284 | } else { | ||
285 | /* Set default ICMP timeout. */ | ||
286 | *timeout = nf_ct_icmp_timeout; | ||
287 | } | ||
288 | return 0; | ||
289 | } | ||
290 | |||
291 | static int | ||
292 | icmp_timeout_obj_to_nlattr(struct sk_buff *skb, const void *data) | ||
293 | { | ||
294 | const unsigned int *timeout = data; | ||
295 | |||
296 | NLA_PUT_BE32(skb, CTA_TIMEOUT_ICMP_TIMEOUT, htonl(*timeout / HZ)); | ||
297 | |||
298 | return 0; | ||
299 | |||
300 | nla_put_failure: | ||
301 | return -ENOSPC; | ||
302 | } | ||
303 | |||
304 | static const struct nla_policy | ||
305 | icmp_timeout_nla_policy[CTA_TIMEOUT_ICMP_MAX+1] = { | ||
306 | [CTA_TIMEOUT_ICMP_TIMEOUT] = { .type = NLA_U32 }, | ||
307 | }; | ||
308 | #endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */ | ||
309 | |||
272 | #ifdef CONFIG_SYSCTL | 310 | #ifdef CONFIG_SYSCTL |
273 | static struct ctl_table_header *icmp_sysctl_header; | 311 | static struct ctl_table_header *icmp_sysctl_header; |
274 | static struct ctl_table icmp_sysctl_table[] = { | 312 | static struct ctl_table icmp_sysctl_table[] = { |
@@ -315,6 +353,15 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_icmp __read_mostly = | |||
315 | .nlattr_to_tuple = icmp_nlattr_to_tuple, | 353 | .nlattr_to_tuple = icmp_nlattr_to_tuple, |
316 | .nla_policy = icmp_nla_policy, | 354 | .nla_policy = icmp_nla_policy, |
317 | #endif | 355 | #endif |
356 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT) | ||
357 | .ctnl_timeout = { | ||
358 | .nlattr_to_obj = icmp_timeout_nlattr_to_obj, | ||
359 | .obj_to_nlattr = icmp_timeout_obj_to_nlattr, | ||
360 | .nlattr_max = CTA_TIMEOUT_ICMP_MAX, | ||
361 | .obj_size = sizeof(unsigned int), | ||
362 | .nla_policy = icmp_timeout_nla_policy, | ||
363 | }, | ||
364 | #endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */ | ||
318 | #ifdef CONFIG_SYSCTL | 365 | #ifdef CONFIG_SYSCTL |
319 | .ctl_table_header = &icmp_sysctl_header, | 366 | .ctl_table_header = &icmp_sysctl_header, |
320 | .ctl_table = icmp_sysctl_table, | 367 | .ctl_table = icmp_sysctl_table, |
diff --git a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c index 2eb9751eb7a8..92cc9f2931ae 100644 --- a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c +++ b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c | |||
@@ -276,6 +276,44 @@ static int icmpv6_nlattr_tuple_size(void) | |||
276 | } | 276 | } |
277 | #endif | 277 | #endif |
278 | 278 | ||
279 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT) | ||
280 | |||
281 | #include <linux/netfilter/nfnetlink.h> | ||
282 | #include <linux/netfilter/nfnetlink_cttimeout.h> | ||
283 | |||
284 | static int icmpv6_timeout_nlattr_to_obj(struct nlattr *tb[], void *data) | ||
285 | { | ||
286 | unsigned int *timeout = data; | ||
287 | |||
288 | if (tb[CTA_TIMEOUT_ICMPV6_TIMEOUT]) { | ||
289 | *timeout = | ||
290 | ntohl(nla_get_be32(tb[CTA_TIMEOUT_ICMPV6_TIMEOUT])) * HZ; | ||
291 | } else { | ||
292 | /* Set default ICMPv6 timeout. */ | ||
293 | *timeout = nf_ct_icmpv6_timeout; | ||
294 | } | ||
295 | return 0; | ||
296 | } | ||
297 | |||
298 | static int | ||
299 | icmpv6_timeout_obj_to_nlattr(struct sk_buff *skb, const void *data) | ||
300 | { | ||
301 | const unsigned int *timeout = data; | ||
302 | |||
303 | NLA_PUT_BE32(skb, CTA_TIMEOUT_ICMPV6_TIMEOUT, htonl(*timeout / HZ)); | ||
304 | |||
305 | return 0; | ||
306 | |||
307 | nla_put_failure: | ||
308 | return -ENOSPC; | ||
309 | } | ||
310 | |||
311 | static const struct nla_policy | ||
312 | icmpv6_timeout_nla_policy[CTA_TIMEOUT_ICMPV6_MAX+1] = { | ||
313 | [CTA_TIMEOUT_ICMPV6_TIMEOUT] = { .type = NLA_U32 }, | ||
314 | }; | ||
315 | #endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */ | ||
316 | |||
279 | #ifdef CONFIG_SYSCTL | 317 | #ifdef CONFIG_SYSCTL |
280 | static struct ctl_table_header *icmpv6_sysctl_header; | 318 | static struct ctl_table_header *icmpv6_sysctl_header; |
281 | static struct ctl_table icmpv6_sysctl_table[] = { | 319 | static struct ctl_table icmpv6_sysctl_table[] = { |
@@ -308,6 +346,15 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_icmpv6 __read_mostly = | |||
308 | .nlattr_to_tuple = icmpv6_nlattr_to_tuple, | 346 | .nlattr_to_tuple = icmpv6_nlattr_to_tuple, |
309 | .nla_policy = icmpv6_nla_policy, | 347 | .nla_policy = icmpv6_nla_policy, |
310 | #endif | 348 | #endif |
349 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT) | ||
350 | .ctnl_timeout = { | ||
351 | .nlattr_to_obj = icmpv6_timeout_nlattr_to_obj, | ||
352 | .obj_to_nlattr = icmpv6_timeout_obj_to_nlattr, | ||
353 | .nlattr_max = CTA_TIMEOUT_ICMP_MAX, | ||
354 | .obj_size = sizeof(unsigned int), | ||
355 | .nla_policy = icmpv6_timeout_nla_policy, | ||
356 | }, | ||
357 | #endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */ | ||
311 | #ifdef CONFIG_SYSCTL | 358 | #ifdef CONFIG_SYSCTL |
312 | .ctl_table_header = &icmpv6_sysctl_header, | 359 | .ctl_table_header = &icmpv6_sysctl_header, |
313 | .ctl_table = icmpv6_sysctl_table, | 360 | .ctl_table = icmpv6_sysctl_table, |
diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig index b895d8b13215..f3efb6570dd9 100644 --- a/net/netfilter/Kconfig +++ b/net/netfilter/Kconfig | |||
@@ -314,6 +314,17 @@ config NF_CT_NETLINK | |||
314 | help | 314 | help |
315 | This option enables support for a netlink-based userspace interface | 315 | This option enables support for a netlink-based userspace interface |
316 | 316 | ||
317 | config NF_CT_NETLINK_TIMEOUT | ||
318 | tristate 'Connection tracking timeout tuning via Netlink' | ||
319 | select NETFILTER_NETLINK | ||
320 | depends on NETFILTER_ADVANCED | ||
321 | help | ||
322 | This option enables support for connection tracking timeout | ||
323 | fine-grain tuning. This allows you to attach specific timeout | ||
324 | policies to flows, instead of using the global timeout policy. | ||
325 | |||
326 | If unsure, say `N'. | ||
327 | |||
317 | endif # NF_CONNTRACK | 328 | endif # NF_CONNTRACK |
318 | 329 | ||
319 | # transparent proxy support | 330 | # transparent proxy support |
diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile index a28c2a6563f8..cf7cdd630bdd 100644 --- a/net/netfilter/Makefile +++ b/net/netfilter/Makefile | |||
@@ -22,6 +22,7 @@ obj-$(CONFIG_NF_CT_PROTO_UDPLITE) += nf_conntrack_proto_udplite.o | |||
22 | 22 | ||
23 | # netlink interface for nf_conntrack | 23 | # netlink interface for nf_conntrack |
24 | obj-$(CONFIG_NF_CT_NETLINK) += nf_conntrack_netlink.o | 24 | obj-$(CONFIG_NF_CT_NETLINK) += nf_conntrack_netlink.o |
25 | obj-$(CONFIG_NF_CT_NETLINK_TIMEOUT) += nfnetlink_cttimeout.o | ||
25 | 26 | ||
26 | # connection tracking helpers | 27 | # connection tracking helpers |
27 | nf_conntrack_h323-objs := nf_conntrack_h323_main.o nf_conntrack_h323_asn1.o | 28 | nf_conntrack_h323-objs := nf_conntrack_h323_main.o nf_conntrack_h323_asn1.o |
diff --git a/net/netfilter/nf_conntrack_proto_dccp.c b/net/netfilter/nf_conntrack_proto_dccp.c index 8ea33598a0a7..24fdce256cb0 100644 --- a/net/netfilter/nf_conntrack_proto_dccp.c +++ b/net/netfilter/nf_conntrack_proto_dccp.c | |||
@@ -706,8 +706,60 @@ static int dccp_nlattr_size(void) | |||
706 | return nla_total_size(0) /* CTA_PROTOINFO_DCCP */ | 706 | return nla_total_size(0) /* CTA_PROTOINFO_DCCP */ |
707 | + nla_policy_len(dccp_nla_policy, CTA_PROTOINFO_DCCP_MAX + 1); | 707 | + nla_policy_len(dccp_nla_policy, CTA_PROTOINFO_DCCP_MAX + 1); |
708 | } | 708 | } |
709 | |||
709 | #endif | 710 | #endif |
710 | 711 | ||
712 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT) | ||
713 | |||
714 | #include <linux/netfilter/nfnetlink.h> | ||
715 | #include <linux/netfilter/nfnetlink_cttimeout.h> | ||
716 | |||
717 | static int dccp_timeout_nlattr_to_obj(struct nlattr *tb[], void *data) | ||
718 | { | ||
719 | struct dccp_net *dn = dccp_pernet(&init_net); | ||
720 | unsigned int *timeouts = data; | ||
721 | int i; | ||
722 | |||
723 | /* set default DCCP timeouts. */ | ||
724 | for (i=0; i<CT_DCCP_MAX; i++) | ||
725 | timeouts[i] = dn->dccp_timeout[i]; | ||
726 | |||
727 | /* there's a 1:1 mapping between attributes and protocol states. */ | ||
728 | for (i=CTA_TIMEOUT_DCCP_UNSPEC+1; i<CTA_TIMEOUT_DCCP_MAX+1; i++) { | ||
729 | if (tb[i]) { | ||
730 | timeouts[i] = ntohl(nla_get_be32(tb[i])) * HZ; | ||
731 | } | ||
732 | } | ||
733 | return 0; | ||
734 | } | ||
735 | |||
736 | static int | ||
737 | dccp_timeout_obj_to_nlattr(struct sk_buff *skb, const void *data) | ||
738 | { | ||
739 | const unsigned int *timeouts = data; | ||
740 | int i; | ||
741 | |||
742 | for (i=CTA_TIMEOUT_DCCP_UNSPEC+1; i<CTA_TIMEOUT_DCCP_MAX+1; i++) | ||
743 | NLA_PUT_BE32(skb, i, htonl(timeouts[i] / HZ)); | ||
744 | |||
745 | return 0; | ||
746 | |||
747 | nla_put_failure: | ||
748 | return -ENOSPC; | ||
749 | } | ||
750 | |||
751 | static const struct nla_policy | ||
752 | dccp_timeout_nla_policy[CTA_TIMEOUT_DCCP_MAX+1] = { | ||
753 | [CTA_TIMEOUT_DCCP_REQUEST] = { .type = NLA_U32 }, | ||
754 | [CTA_TIMEOUT_DCCP_RESPOND] = { .type = NLA_U32 }, | ||
755 | [CTA_TIMEOUT_DCCP_PARTOPEN] = { .type = NLA_U32 }, | ||
756 | [CTA_TIMEOUT_DCCP_OPEN] = { .type = NLA_U32 }, | ||
757 | [CTA_TIMEOUT_DCCP_CLOSEREQ] = { .type = NLA_U32 }, | ||
758 | [CTA_TIMEOUT_DCCP_CLOSING] = { .type = NLA_U32 }, | ||
759 | [CTA_TIMEOUT_DCCP_TIMEWAIT] = { .type = NLA_U32 }, | ||
760 | }; | ||
761 | #endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */ | ||
762 | |||
711 | #ifdef CONFIG_SYSCTL | 763 | #ifdef CONFIG_SYSCTL |
712 | /* template, data assigned later */ | 764 | /* template, data assigned later */ |
713 | static struct ctl_table dccp_sysctl_table[] = { | 765 | static struct ctl_table dccp_sysctl_table[] = { |
@@ -784,6 +836,15 @@ static struct nf_conntrack_l4proto dccp_proto4 __read_mostly = { | |||
784 | .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, | 836 | .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, |
785 | .nla_policy = nf_ct_port_nla_policy, | 837 | .nla_policy = nf_ct_port_nla_policy, |
786 | #endif | 838 | #endif |
839 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT) | ||
840 | .ctnl_timeout = { | ||
841 | .nlattr_to_obj = dccp_timeout_nlattr_to_obj, | ||
842 | .obj_to_nlattr = dccp_timeout_obj_to_nlattr, | ||
843 | .nlattr_max = CTA_TIMEOUT_DCCP_MAX, | ||
844 | .obj_size = sizeof(unsigned int) * CT_DCCP_MAX, | ||
845 | .nla_policy = dccp_timeout_nla_policy, | ||
846 | }, | ||
847 | #endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */ | ||
787 | }; | 848 | }; |
788 | 849 | ||
789 | static struct nf_conntrack_l4proto dccp_proto6 __read_mostly = { | 850 | static struct nf_conntrack_l4proto dccp_proto6 __read_mostly = { |
@@ -807,6 +868,15 @@ static struct nf_conntrack_l4proto dccp_proto6 __read_mostly = { | |||
807 | .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, | 868 | .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, |
808 | .nla_policy = nf_ct_port_nla_policy, | 869 | .nla_policy = nf_ct_port_nla_policy, |
809 | #endif | 870 | #endif |
871 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT) | ||
872 | .ctnl_timeout = { | ||
873 | .nlattr_to_obj = dccp_timeout_nlattr_to_obj, | ||
874 | .obj_to_nlattr = dccp_timeout_obj_to_nlattr, | ||
875 | .nlattr_max = CTA_TIMEOUT_DCCP_MAX, | ||
876 | .obj_size = sizeof(unsigned int) * CT_DCCP_MAX, | ||
877 | .nla_policy = dccp_timeout_nla_policy, | ||
878 | }, | ||
879 | #endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */ | ||
810 | }; | 880 | }; |
811 | 881 | ||
812 | static __net_init int dccp_net_init(struct net *net) | 882 | static __net_init int dccp_net_init(struct net *net) |
diff --git a/net/netfilter/nf_conntrack_proto_generic.c b/net/netfilter/nf_conntrack_proto_generic.c index 0e6c5451db80..835e24c58f0d 100644 --- a/net/netfilter/nf_conntrack_proto_generic.c +++ b/net/netfilter/nf_conntrack_proto_generic.c | |||
@@ -65,6 +65,45 @@ static bool generic_new(struct nf_conn *ct, const struct sk_buff *skb, | |||
65 | return true; | 65 | return true; |
66 | } | 66 | } |
67 | 67 | ||
68 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT) | ||
69 | |||
70 | #include <linux/netfilter/nfnetlink.h> | ||
71 | #include <linux/netfilter/nfnetlink_cttimeout.h> | ||
72 | |||
73 | static int generic_timeout_nlattr_to_obj(struct nlattr *tb[], void *data) | ||
74 | { | ||
75 | unsigned int *timeout = data; | ||
76 | |||
77 | if (tb[CTA_TIMEOUT_GENERIC_TIMEOUT]) | ||
78 | *timeout = | ||
79 | ntohl(nla_get_be32(tb[CTA_TIMEOUT_GENERIC_TIMEOUT])) * HZ; | ||
80 | else { | ||
81 | /* Set default generic timeout. */ | ||
82 | *timeout = nf_ct_generic_timeout; | ||
83 | } | ||
84 | |||
85 | return 0; | ||
86 | } | ||
87 | |||
88 | static int | ||
89 | generic_timeout_obj_to_nlattr(struct sk_buff *skb, const void *data) | ||
90 | { | ||
91 | const unsigned int *timeout = data; | ||
92 | |||
93 | NLA_PUT_BE32(skb, CTA_TIMEOUT_GENERIC_TIMEOUT, htonl(*timeout / HZ)); | ||
94 | |||
95 | return 0; | ||
96 | |||
97 | nla_put_failure: | ||
98 | return -ENOSPC; | ||
99 | } | ||
100 | |||
101 | static const struct nla_policy | ||
102 | generic_timeout_nla_policy[CTA_TIMEOUT_GENERIC_MAX+1] = { | ||
103 | [CTA_TIMEOUT_GENERIC_TIMEOUT] = { .type = NLA_U32 }, | ||
104 | }; | ||
105 | #endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */ | ||
106 | |||
68 | #ifdef CONFIG_SYSCTL | 107 | #ifdef CONFIG_SYSCTL |
69 | static struct ctl_table_header *generic_sysctl_header; | 108 | static struct ctl_table_header *generic_sysctl_header; |
70 | static struct ctl_table generic_sysctl_table[] = { | 109 | static struct ctl_table generic_sysctl_table[] = { |
@@ -102,6 +141,15 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_generic __read_mostly = | |||
102 | .packet = generic_packet, | 141 | .packet = generic_packet, |
103 | .get_timeouts = generic_get_timeouts, | 142 | .get_timeouts = generic_get_timeouts, |
104 | .new = generic_new, | 143 | .new = generic_new, |
144 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT) | ||
145 | .ctnl_timeout = { | ||
146 | .nlattr_to_obj = generic_timeout_nlattr_to_obj, | ||
147 | .obj_to_nlattr = generic_timeout_obj_to_nlattr, | ||
148 | .nlattr_max = CTA_TIMEOUT_GENERIC_MAX, | ||
149 | .obj_size = sizeof(unsigned int), | ||
150 | .nla_policy = generic_timeout_nla_policy, | ||
151 | }, | ||
152 | #endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */ | ||
105 | #ifdef CONFIG_SYSCTL | 153 | #ifdef CONFIG_SYSCTL |
106 | .ctl_table_header = &generic_sysctl_header, | 154 | .ctl_table_header = &generic_sysctl_header, |
107 | .ctl_table = generic_sysctl_table, | 155 | .ctl_table = generic_sysctl_table, |
diff --git a/net/netfilter/nf_conntrack_proto_gre.c b/net/netfilter/nf_conntrack_proto_gre.c index 1bf01c95658b..659648c4b14a 100644 --- a/net/netfilter/nf_conntrack_proto_gre.c +++ b/net/netfilter/nf_conntrack_proto_gre.c | |||
@@ -292,6 +292,52 @@ static void gre_destroy(struct nf_conn *ct) | |||
292 | nf_ct_gre_keymap_destroy(master); | 292 | nf_ct_gre_keymap_destroy(master); |
293 | } | 293 | } |
294 | 294 | ||
295 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT) | ||
296 | |||
297 | #include <linux/netfilter/nfnetlink.h> | ||
298 | #include <linux/netfilter/nfnetlink_cttimeout.h> | ||
299 | |||
300 | static int gre_timeout_nlattr_to_obj(struct nlattr *tb[], void *data) | ||
301 | { | ||
302 | unsigned int *timeouts = data; | ||
303 | |||
304 | /* set default timeouts for GRE. */ | ||
305 | timeouts[GRE_CT_UNREPLIED] = gre_timeouts[GRE_CT_UNREPLIED]; | ||
306 | timeouts[GRE_CT_REPLIED] = gre_timeouts[GRE_CT_REPLIED]; | ||
307 | |||
308 | if (tb[CTA_TIMEOUT_GRE_UNREPLIED]) { | ||
309 | timeouts[GRE_CT_UNREPLIED] = | ||
310 | ntohl(nla_get_be32(tb[CTA_TIMEOUT_GRE_UNREPLIED])) * HZ; | ||
311 | } | ||
312 | if (tb[CTA_TIMEOUT_GRE_REPLIED]) { | ||
313 | timeouts[GRE_CT_REPLIED] = | ||
314 | ntohl(nla_get_be32(tb[CTA_TIMEOUT_GRE_REPLIED])) * HZ; | ||
315 | } | ||
316 | return 0; | ||
317 | } | ||
318 | |||
319 | static int | ||
320 | gre_timeout_obj_to_nlattr(struct sk_buff *skb, const void *data) | ||
321 | { | ||
322 | const unsigned int *timeouts = data; | ||
323 | |||
324 | NLA_PUT_BE32(skb, CTA_TIMEOUT_GRE_UNREPLIED, | ||
325 | htonl(timeouts[GRE_CT_UNREPLIED] / HZ)); | ||
326 | NLA_PUT_BE32(skb, CTA_TIMEOUT_GRE_REPLIED, | ||
327 | htonl(timeouts[GRE_CT_REPLIED] / HZ)); | ||
328 | return 0; | ||
329 | |||
330 | nla_put_failure: | ||
331 | return -ENOSPC; | ||
332 | } | ||
333 | |||
334 | static const struct nla_policy | ||
335 | gre_timeout_nla_policy[CTA_TIMEOUT_GRE_MAX+1] = { | ||
336 | [CTA_TIMEOUT_GRE_UNREPLIED] = { .type = NLA_U32 }, | ||
337 | [CTA_TIMEOUT_GRE_REPLIED] = { .type = NLA_U32 }, | ||
338 | }; | ||
339 | #endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */ | ||
340 | |||
295 | /* protocol helper struct */ | 341 | /* protocol helper struct */ |
296 | static struct nf_conntrack_l4proto nf_conntrack_l4proto_gre4 __read_mostly = { | 342 | static struct nf_conntrack_l4proto nf_conntrack_l4proto_gre4 __read_mostly = { |
297 | .l3proto = AF_INET, | 343 | .l3proto = AF_INET, |
@@ -312,6 +358,15 @@ static struct nf_conntrack_l4proto nf_conntrack_l4proto_gre4 __read_mostly = { | |||
312 | .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, | 358 | .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, |
313 | .nla_policy = nf_ct_port_nla_policy, | 359 | .nla_policy = nf_ct_port_nla_policy, |
314 | #endif | 360 | #endif |
361 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT) | ||
362 | .ctnl_timeout = { | ||
363 | .nlattr_to_obj = gre_timeout_nlattr_to_obj, | ||
364 | .obj_to_nlattr = gre_timeout_obj_to_nlattr, | ||
365 | .nlattr_max = CTA_TIMEOUT_GRE_MAX, | ||
366 | .obj_size = sizeof(unsigned int) * GRE_CT_MAX, | ||
367 | .nla_policy = gre_timeout_nla_policy, | ||
368 | }, | ||
369 | #endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */ | ||
315 | }; | 370 | }; |
316 | 371 | ||
317 | static int proto_gre_net_init(struct net *net) | 372 | static int proto_gre_net_init(struct net *net) |
diff --git a/net/netfilter/nf_conntrack_proto_sctp.c b/net/netfilter/nf_conntrack_proto_sctp.c index 2a0703371e24..72b5088592dc 100644 --- a/net/netfilter/nf_conntrack_proto_sctp.c +++ b/net/netfilter/nf_conntrack_proto_sctp.c | |||
@@ -549,6 +549,57 @@ static int sctp_nlattr_size(void) | |||
549 | } | 549 | } |
550 | #endif | 550 | #endif |
551 | 551 | ||
552 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT) | ||
553 | |||
554 | #include <linux/netfilter/nfnetlink.h> | ||
555 | #include <linux/netfilter/nfnetlink_cttimeout.h> | ||
556 | |||
557 | static int sctp_timeout_nlattr_to_obj(struct nlattr *tb[], void *data) | ||
558 | { | ||
559 | unsigned int *timeouts = data; | ||
560 | int i; | ||
561 | |||
562 | /* set default SCTP timeouts. */ | ||
563 | for (i=0; i<SCTP_CONNTRACK_MAX; i++) | ||
564 | timeouts[i] = sctp_timeouts[i]; | ||
565 | |||
566 | /* there's a 1:1 mapping between attributes and protocol states. */ | ||
567 | for (i=CTA_TIMEOUT_SCTP_UNSPEC+1; i<CTA_TIMEOUT_SCTP_MAX+1; i++) { | ||
568 | if (tb[i]) { | ||
569 | timeouts[i] = ntohl(nla_get_be32(tb[i])) * HZ; | ||
570 | } | ||
571 | } | ||
572 | return 0; | ||
573 | } | ||
574 | |||
575 | static int | ||
576 | sctp_timeout_obj_to_nlattr(struct sk_buff *skb, const void *data) | ||
577 | { | ||
578 | const unsigned int *timeouts = data; | ||
579 | int i; | ||
580 | |||
581 | for (i=CTA_TIMEOUT_SCTP_UNSPEC+1; i<CTA_TIMEOUT_SCTP_MAX+1; i++) | ||
582 | NLA_PUT_BE32(skb, i, htonl(timeouts[i] / HZ)); | ||
583 | |||
584 | return 0; | ||
585 | |||
586 | nla_put_failure: | ||
587 | return -ENOSPC; | ||
588 | } | ||
589 | |||
590 | static const struct nla_policy | ||
591 | sctp_timeout_nla_policy[CTA_TIMEOUT_SCTP_MAX+1] = { | ||
592 | [CTA_TIMEOUT_SCTP_CLOSED] = { .type = NLA_U32 }, | ||
593 | [CTA_TIMEOUT_SCTP_COOKIE_WAIT] = { .type = NLA_U32 }, | ||
594 | [CTA_TIMEOUT_SCTP_COOKIE_ECHOED] = { .type = NLA_U32 }, | ||
595 | [CTA_TIMEOUT_SCTP_ESTABLISHED] = { .type = NLA_U32 }, | ||
596 | [CTA_TIMEOUT_SCTP_SHUTDOWN_SENT] = { .type = NLA_U32 }, | ||
597 | [CTA_TIMEOUT_SCTP_SHUTDOWN_RECD] = { .type = NLA_U32 }, | ||
598 | [CTA_TIMEOUT_SCTP_SHUTDOWN_ACK_SENT] = { .type = NLA_U32 }, | ||
599 | }; | ||
600 | #endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */ | ||
601 | |||
602 | |||
552 | #ifdef CONFIG_SYSCTL | 603 | #ifdef CONFIG_SYSCTL |
553 | static unsigned int sctp_sysctl_table_users; | 604 | static unsigned int sctp_sysctl_table_users; |
554 | static struct ctl_table_header *sctp_sysctl_header; | 605 | static struct ctl_table_header *sctp_sysctl_header; |
@@ -682,6 +733,15 @@ static struct nf_conntrack_l4proto nf_conntrack_l4proto_sctp4 __read_mostly = { | |||
682 | .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, | 733 | .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, |
683 | .nla_policy = nf_ct_port_nla_policy, | 734 | .nla_policy = nf_ct_port_nla_policy, |
684 | #endif | 735 | #endif |
736 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT) | ||
737 | .ctnl_timeout = { | ||
738 | .nlattr_to_obj = sctp_timeout_nlattr_to_obj, | ||
739 | .obj_to_nlattr = sctp_timeout_obj_to_nlattr, | ||
740 | .nlattr_max = CTA_TIMEOUT_SCTP_MAX, | ||
741 | .obj_size = sizeof(unsigned int) * SCTP_CONNTRACK_MAX, | ||
742 | .nla_policy = sctp_timeout_nla_policy, | ||
743 | }, | ||
744 | #endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */ | ||
685 | #ifdef CONFIG_SYSCTL | 745 | #ifdef CONFIG_SYSCTL |
686 | .ctl_table_users = &sctp_sysctl_table_users, | 746 | .ctl_table_users = &sctp_sysctl_table_users, |
687 | .ctl_table_header = &sctp_sysctl_header, | 747 | .ctl_table_header = &sctp_sysctl_header, |
@@ -712,6 +772,15 @@ static struct nf_conntrack_l4proto nf_conntrack_l4proto_sctp6 __read_mostly = { | |||
712 | .nlattr_tuple_size = nf_ct_port_nlattr_tuple_size, | 772 | .nlattr_tuple_size = nf_ct_port_nlattr_tuple_size, |
713 | .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, | 773 | .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, |
714 | .nla_policy = nf_ct_port_nla_policy, | 774 | .nla_policy = nf_ct_port_nla_policy, |
775 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT) | ||
776 | .ctnl_timeout = { | ||
777 | .nlattr_to_obj = sctp_timeout_nlattr_to_obj, | ||
778 | .obj_to_nlattr = sctp_timeout_obj_to_nlattr, | ||
779 | .nlattr_max = CTA_TIMEOUT_SCTP_MAX, | ||
780 | .obj_size = sizeof(unsigned int) * SCTP_CONNTRACK_MAX, | ||
781 | .nla_policy = sctp_timeout_nla_policy, | ||
782 | }, | ||
783 | #endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */ | ||
715 | #endif | 784 | #endif |
716 | #ifdef CONFIG_SYSCTL | 785 | #ifdef CONFIG_SYSCTL |
717 | .ctl_table_users = &sctp_sysctl_table_users, | 786 | .ctl_table_users = &sctp_sysctl_table_users, |
diff --git a/net/netfilter/nf_conntrack_proto_tcp.c b/net/netfilter/nf_conntrack_proto_tcp.c index 8372bb43feb0..361eade62a09 100644 --- a/net/netfilter/nf_conntrack_proto_tcp.c +++ b/net/netfilter/nf_conntrack_proto_tcp.c | |||
@@ -1244,6 +1244,113 @@ static int tcp_nlattr_tuple_size(void) | |||
1244 | } | 1244 | } |
1245 | #endif | 1245 | #endif |
1246 | 1246 | ||
1247 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT) | ||
1248 | |||
1249 | #include <linux/netfilter/nfnetlink.h> | ||
1250 | #include <linux/netfilter/nfnetlink_cttimeout.h> | ||
1251 | |||
1252 | static int tcp_timeout_nlattr_to_obj(struct nlattr *tb[], void *data) | ||
1253 | { | ||
1254 | unsigned int *timeouts = data; | ||
1255 | int i; | ||
1256 | |||
1257 | /* set default TCP timeouts. */ | ||
1258 | for (i=0; i<TCP_CONNTRACK_TIMEOUT_MAX; i++) | ||
1259 | timeouts[i] = tcp_timeouts[i]; | ||
1260 | |||
1261 | if (tb[CTA_TIMEOUT_TCP_SYN_SENT]) { | ||
1262 | timeouts[TCP_CONNTRACK_SYN_SENT] = | ||
1263 | ntohl(nla_get_be32(tb[CTA_TIMEOUT_TCP_SYN_SENT]))*HZ; | ||
1264 | } | ||
1265 | if (tb[CTA_TIMEOUT_TCP_SYN_RECV]) { | ||
1266 | timeouts[TCP_CONNTRACK_SYN_RECV] = | ||
1267 | ntohl(nla_get_be32(tb[CTA_TIMEOUT_TCP_SYN_RECV]))*HZ; | ||
1268 | } | ||
1269 | if (tb[CTA_TIMEOUT_TCP_ESTABLISHED]) { | ||
1270 | timeouts[TCP_CONNTRACK_ESTABLISHED] = | ||
1271 | ntohl(nla_get_be32(tb[CTA_TIMEOUT_TCP_ESTABLISHED]))*HZ; | ||
1272 | } | ||
1273 | if (tb[CTA_TIMEOUT_TCP_FIN_WAIT]) { | ||
1274 | timeouts[TCP_CONNTRACK_FIN_WAIT] = | ||
1275 | ntohl(nla_get_be32(tb[CTA_TIMEOUT_TCP_FIN_WAIT]))*HZ; | ||
1276 | } | ||
1277 | if (tb[CTA_TIMEOUT_TCP_CLOSE_WAIT]) { | ||
1278 | timeouts[TCP_CONNTRACK_CLOSE_WAIT] = | ||
1279 | ntohl(nla_get_be32(tb[CTA_TIMEOUT_TCP_CLOSE_WAIT]))*HZ; | ||
1280 | } | ||
1281 | if (tb[CTA_TIMEOUT_TCP_LAST_ACK]) { | ||
1282 | timeouts[TCP_CONNTRACK_LAST_ACK] = | ||
1283 | ntohl(nla_get_be32(tb[CTA_TIMEOUT_TCP_LAST_ACK]))*HZ; | ||
1284 | } | ||
1285 | if (tb[CTA_TIMEOUT_TCP_TIME_WAIT]) { | ||
1286 | timeouts[TCP_CONNTRACK_TIME_WAIT] = | ||
1287 | ntohl(nla_get_be32(tb[CTA_TIMEOUT_TCP_TIME_WAIT]))*HZ; | ||
1288 | } | ||
1289 | if (tb[CTA_TIMEOUT_TCP_CLOSE]) { | ||
1290 | timeouts[TCP_CONNTRACK_CLOSE] = | ||
1291 | ntohl(nla_get_be32(tb[CTA_TIMEOUT_TCP_CLOSE]))*HZ; | ||
1292 | } | ||
1293 | if (tb[CTA_TIMEOUT_TCP_SYN_SENT2]) { | ||
1294 | timeouts[TCP_CONNTRACK_SYN_SENT2] = | ||
1295 | ntohl(nla_get_be32(tb[CTA_TIMEOUT_TCP_SYN_SENT2]))*HZ; | ||
1296 | } | ||
1297 | if (tb[CTA_TIMEOUT_TCP_RETRANS]) { | ||
1298 | timeouts[TCP_CONNTRACK_RETRANS] = | ||
1299 | ntohl(nla_get_be32(tb[CTA_TIMEOUT_TCP_RETRANS]))*HZ; | ||
1300 | } | ||
1301 | if (tb[CTA_TIMEOUT_TCP_UNACK]) { | ||
1302 | timeouts[TCP_CONNTRACK_UNACK] = | ||
1303 | ntohl(nla_get_be32(tb[CTA_TIMEOUT_TCP_UNACK]))*HZ; | ||
1304 | } | ||
1305 | return 0; | ||
1306 | } | ||
1307 | |||
1308 | static int | ||
1309 | tcp_timeout_obj_to_nlattr(struct sk_buff *skb, const void *data) | ||
1310 | { | ||
1311 | const unsigned int *timeouts = data; | ||
1312 | |||
1313 | NLA_PUT_BE32(skb, CTA_TIMEOUT_TCP_SYN_SENT, | ||
1314 | htonl(timeouts[TCP_CONNTRACK_SYN_SENT] / HZ)); | ||
1315 | NLA_PUT_BE32(skb, CTA_TIMEOUT_TCP_SYN_RECV, | ||
1316 | htonl(timeouts[TCP_CONNTRACK_SYN_RECV] / HZ)); | ||
1317 | NLA_PUT_BE32(skb, CTA_TIMEOUT_TCP_ESTABLISHED, | ||
1318 | htonl(timeouts[TCP_CONNTRACK_ESTABLISHED] / HZ)); | ||
1319 | NLA_PUT_BE32(skb, CTA_TIMEOUT_TCP_FIN_WAIT, | ||
1320 | htonl(timeouts[TCP_CONNTRACK_FIN_WAIT] / HZ)); | ||
1321 | NLA_PUT_BE32(skb, CTA_TIMEOUT_TCP_CLOSE_WAIT, | ||
1322 | htonl(timeouts[TCP_CONNTRACK_CLOSE_WAIT] / HZ)); | ||
1323 | NLA_PUT_BE32(skb, CTA_TIMEOUT_TCP_LAST_ACK, | ||
1324 | htonl(timeouts[TCP_CONNTRACK_LAST_ACK] / HZ)); | ||
1325 | NLA_PUT_BE32(skb, CTA_TIMEOUT_TCP_TIME_WAIT, | ||
1326 | htonl(timeouts[TCP_CONNTRACK_TIME_WAIT] / HZ)); | ||
1327 | NLA_PUT_BE32(skb, CTA_TIMEOUT_TCP_CLOSE, | ||
1328 | htonl(timeouts[TCP_CONNTRACK_CLOSE] / HZ)); | ||
1329 | NLA_PUT_BE32(skb, CTA_TIMEOUT_TCP_SYN_SENT2, | ||
1330 | htonl(timeouts[TCP_CONNTRACK_SYN_SENT2] / HZ)); | ||
1331 | NLA_PUT_BE32(skb, CTA_TIMEOUT_TCP_RETRANS, | ||
1332 | htonl(timeouts[TCP_CONNTRACK_RETRANS] / HZ)); | ||
1333 | NLA_PUT_BE32(skb, CTA_TIMEOUT_TCP_UNACK, | ||
1334 | htonl(timeouts[TCP_CONNTRACK_UNACK] / HZ)); | ||
1335 | return 0; | ||
1336 | |||
1337 | nla_put_failure: | ||
1338 | return -ENOSPC; | ||
1339 | } | ||
1340 | |||
1341 | static const struct nla_policy tcp_timeout_nla_policy[CTA_TIMEOUT_TCP_MAX+1] = { | ||
1342 | [CTA_TIMEOUT_TCP_SYN_SENT] = { .type = NLA_U32 }, | ||
1343 | [CTA_TIMEOUT_TCP_SYN_RECV] = { .type = NLA_U32 }, | ||
1344 | [CTA_TIMEOUT_TCP_ESTABLISHED] = { .type = NLA_U32 }, | ||
1345 | [CTA_TIMEOUT_TCP_FIN_WAIT] = { .type = NLA_U32 }, | ||
1346 | [CTA_TIMEOUT_TCP_CLOSE_WAIT] = { .type = NLA_U32 }, | ||
1347 | [CTA_TIMEOUT_TCP_LAST_ACK] = { .type = NLA_U32 }, | ||
1348 | [CTA_TIMEOUT_TCP_TIME_WAIT] = { .type = NLA_U32 }, | ||
1349 | [CTA_TIMEOUT_TCP_CLOSE] = { .type = NLA_U32 }, | ||
1350 | [CTA_TIMEOUT_TCP_SYN_SENT2] = { .type = NLA_U32 }, | ||
1351 | }; | ||
1352 | #endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */ | ||
1353 | |||
1247 | #ifdef CONFIG_SYSCTL | 1354 | #ifdef CONFIG_SYSCTL |
1248 | static unsigned int tcp_sysctl_table_users; | 1355 | static unsigned int tcp_sysctl_table_users; |
1249 | static struct ctl_table_header *tcp_sysctl_header; | 1356 | static struct ctl_table_header *tcp_sysctl_header; |
@@ -1462,6 +1569,16 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_tcp4 __read_mostly = | |||
1462 | .nlattr_tuple_size = tcp_nlattr_tuple_size, | 1569 | .nlattr_tuple_size = tcp_nlattr_tuple_size, |
1463 | .nla_policy = nf_ct_port_nla_policy, | 1570 | .nla_policy = nf_ct_port_nla_policy, |
1464 | #endif | 1571 | #endif |
1572 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT) | ||
1573 | .ctnl_timeout = { | ||
1574 | .nlattr_to_obj = tcp_timeout_nlattr_to_obj, | ||
1575 | .obj_to_nlattr = tcp_timeout_obj_to_nlattr, | ||
1576 | .nlattr_max = CTA_TIMEOUT_TCP_MAX, | ||
1577 | .obj_size = sizeof(unsigned int) * | ||
1578 | TCP_CONNTRACK_TIMEOUT_MAX, | ||
1579 | .nla_policy = tcp_timeout_nla_policy, | ||
1580 | }, | ||
1581 | #endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */ | ||
1465 | #ifdef CONFIG_SYSCTL | 1582 | #ifdef CONFIG_SYSCTL |
1466 | .ctl_table_users = &tcp_sysctl_table_users, | 1583 | .ctl_table_users = &tcp_sysctl_table_users, |
1467 | .ctl_table_header = &tcp_sysctl_header, | 1584 | .ctl_table_header = &tcp_sysctl_header, |
@@ -1495,6 +1612,16 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_tcp6 __read_mostly = | |||
1495 | .nlattr_tuple_size = tcp_nlattr_tuple_size, | 1612 | .nlattr_tuple_size = tcp_nlattr_tuple_size, |
1496 | .nla_policy = nf_ct_port_nla_policy, | 1613 | .nla_policy = nf_ct_port_nla_policy, |
1497 | #endif | 1614 | #endif |
1615 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT) | ||
1616 | .ctnl_timeout = { | ||
1617 | .nlattr_to_obj = tcp_timeout_nlattr_to_obj, | ||
1618 | .obj_to_nlattr = tcp_timeout_obj_to_nlattr, | ||
1619 | .nlattr_max = CTA_TIMEOUT_TCP_MAX, | ||
1620 | .obj_size = sizeof(unsigned int) * | ||
1621 | TCP_CONNTRACK_TIMEOUT_MAX, | ||
1622 | .nla_policy = tcp_timeout_nla_policy, | ||
1623 | }, | ||
1624 | #endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */ | ||
1498 | #ifdef CONFIG_SYSCTL | 1625 | #ifdef CONFIG_SYSCTL |
1499 | .ctl_table_users = &tcp_sysctl_table_users, | 1626 | .ctl_table_users = &tcp_sysctl_table_users, |
1500 | .ctl_table_header = &tcp_sysctl_header, | 1627 | .ctl_table_header = &tcp_sysctl_header, |
diff --git a/net/netfilter/nf_conntrack_proto_udp.c b/net/netfilter/nf_conntrack_proto_udp.c index 70e005992d5b..a9073dc1548d 100644 --- a/net/netfilter/nf_conntrack_proto_udp.c +++ b/net/netfilter/nf_conntrack_proto_udp.c | |||
@@ -152,6 +152,52 @@ static int udp_error(struct net *net, struct nf_conn *tmpl, struct sk_buff *skb, | |||
152 | return NF_ACCEPT; | 152 | return NF_ACCEPT; |
153 | } | 153 | } |
154 | 154 | ||
155 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT) | ||
156 | |||
157 | #include <linux/netfilter/nfnetlink.h> | ||
158 | #include <linux/netfilter/nfnetlink_cttimeout.h> | ||
159 | |||
160 | static int udp_timeout_nlattr_to_obj(struct nlattr *tb[], void *data) | ||
161 | { | ||
162 | unsigned int *timeouts = data; | ||
163 | |||
164 | /* set default timeouts for UDP. */ | ||
165 | timeouts[UDP_CT_UNREPLIED] = udp_timeouts[UDP_CT_UNREPLIED]; | ||
166 | timeouts[UDP_CT_REPLIED] = udp_timeouts[UDP_CT_REPLIED]; | ||
167 | |||
168 | if (tb[CTA_TIMEOUT_UDP_UNREPLIED]) { | ||
169 | timeouts[UDP_CT_UNREPLIED] = | ||
170 | ntohl(nla_get_be32(tb[CTA_TIMEOUT_UDP_UNREPLIED])) * HZ; | ||
171 | } | ||
172 | if (tb[CTA_TIMEOUT_UDP_REPLIED]) { | ||
173 | timeouts[UDP_CT_REPLIED] = | ||
174 | ntohl(nla_get_be32(tb[CTA_TIMEOUT_UDP_REPLIED])) * HZ; | ||
175 | } | ||
176 | return 0; | ||
177 | } | ||
178 | |||
179 | static int | ||
180 | udp_timeout_obj_to_nlattr(struct sk_buff *skb, const void *data) | ||
181 | { | ||
182 | const unsigned int *timeouts = data; | ||
183 | |||
184 | NLA_PUT_BE32(skb, CTA_TIMEOUT_UDP_UNREPLIED, | ||
185 | htonl(timeouts[UDP_CT_UNREPLIED] / HZ)); | ||
186 | NLA_PUT_BE32(skb, CTA_TIMEOUT_UDP_REPLIED, | ||
187 | htonl(timeouts[UDP_CT_REPLIED] / HZ)); | ||
188 | return 0; | ||
189 | |||
190 | nla_put_failure: | ||
191 | return -ENOSPC; | ||
192 | } | ||
193 | |||
194 | static const struct nla_policy | ||
195 | udp_timeout_nla_policy[CTA_TIMEOUT_UDP_MAX+1] = { | ||
196 | [CTA_TIMEOUT_UDP_UNREPLIED] = { .type = NLA_U32 }, | ||
197 | [CTA_TIMEOUT_UDP_REPLIED] = { .type = NLA_U32 }, | ||
198 | }; | ||
199 | #endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */ | ||
200 | |||
155 | #ifdef CONFIG_SYSCTL | 201 | #ifdef CONFIG_SYSCTL |
156 | static unsigned int udp_sysctl_table_users; | 202 | static unsigned int udp_sysctl_table_users; |
157 | static struct ctl_table_header *udp_sysctl_header; | 203 | static struct ctl_table_header *udp_sysctl_header; |
@@ -211,6 +257,15 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_udp4 __read_mostly = | |||
211 | .nlattr_tuple_size = nf_ct_port_nlattr_tuple_size, | 257 | .nlattr_tuple_size = nf_ct_port_nlattr_tuple_size, |
212 | .nla_policy = nf_ct_port_nla_policy, | 258 | .nla_policy = nf_ct_port_nla_policy, |
213 | #endif | 259 | #endif |
260 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT) | ||
261 | .ctnl_timeout = { | ||
262 | .nlattr_to_obj = udp_timeout_nlattr_to_obj, | ||
263 | .obj_to_nlattr = udp_timeout_obj_to_nlattr, | ||
264 | .nlattr_max = CTA_TIMEOUT_UDP_MAX, | ||
265 | .obj_size = sizeof(unsigned int) * CTA_TIMEOUT_UDP_MAX, | ||
266 | .nla_policy = udp_timeout_nla_policy, | ||
267 | }, | ||
268 | #endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */ | ||
214 | #ifdef CONFIG_SYSCTL | 269 | #ifdef CONFIG_SYSCTL |
215 | .ctl_table_users = &udp_sysctl_table_users, | 270 | .ctl_table_users = &udp_sysctl_table_users, |
216 | .ctl_table_header = &udp_sysctl_header, | 271 | .ctl_table_header = &udp_sysctl_header, |
@@ -240,6 +295,15 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_udp6 __read_mostly = | |||
240 | .nlattr_tuple_size = nf_ct_port_nlattr_tuple_size, | 295 | .nlattr_tuple_size = nf_ct_port_nlattr_tuple_size, |
241 | .nla_policy = nf_ct_port_nla_policy, | 296 | .nla_policy = nf_ct_port_nla_policy, |
242 | #endif | 297 | #endif |
298 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT) | ||
299 | .ctnl_timeout = { | ||
300 | .nlattr_to_obj = udp_timeout_nlattr_to_obj, | ||
301 | .obj_to_nlattr = udp_timeout_obj_to_nlattr, | ||
302 | .nlattr_max = CTA_TIMEOUT_UDP_MAX, | ||
303 | .obj_size = sizeof(unsigned int) * CTA_TIMEOUT_UDP_MAX, | ||
304 | .nla_policy = udp_timeout_nla_policy, | ||
305 | }, | ||
306 | #endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */ | ||
243 | #ifdef CONFIG_SYSCTL | 307 | #ifdef CONFIG_SYSCTL |
244 | .ctl_table_users = &udp_sysctl_table_users, | 308 | .ctl_table_users = &udp_sysctl_table_users, |
245 | .ctl_table_header = &udp_sysctl_header, | 309 | .ctl_table_header = &udp_sysctl_header, |
diff --git a/net/netfilter/nf_conntrack_proto_udplite.c b/net/netfilter/nf_conntrack_proto_udplite.c index 0b32ccb1d515..e0606392cda0 100644 --- a/net/netfilter/nf_conntrack_proto_udplite.c +++ b/net/netfilter/nf_conntrack_proto_udplite.c | |||
@@ -156,6 +156,52 @@ static int udplite_error(struct net *net, struct nf_conn *tmpl, | |||
156 | return NF_ACCEPT; | 156 | return NF_ACCEPT; |
157 | } | 157 | } |
158 | 158 | ||
159 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT) | ||
160 | |||
161 | #include <linux/netfilter/nfnetlink.h> | ||
162 | #include <linux/netfilter/nfnetlink_cttimeout.h> | ||
163 | |||
164 | static int udplite_timeout_nlattr_to_obj(struct nlattr *tb[], void *data) | ||
165 | { | ||
166 | unsigned int *timeouts = data; | ||
167 | |||
168 | /* set default timeouts for UDPlite. */ | ||
169 | timeouts[UDPLITE_CT_UNREPLIED] = udplite_timeouts[UDPLITE_CT_UNREPLIED]; | ||
170 | timeouts[UDPLITE_CT_REPLIED] = udplite_timeouts[UDPLITE_CT_REPLIED]; | ||
171 | |||
172 | if (tb[CTA_TIMEOUT_UDPLITE_UNREPLIED]) { | ||
173 | timeouts[UDPLITE_CT_UNREPLIED] = | ||
174 | ntohl(nla_get_be32(tb[CTA_TIMEOUT_UDPLITE_UNREPLIED])) * HZ; | ||
175 | } | ||
176 | if (tb[CTA_TIMEOUT_UDPLITE_REPLIED]) { | ||
177 | timeouts[UDPLITE_CT_REPLIED] = | ||
178 | ntohl(nla_get_be32(tb[CTA_TIMEOUT_UDPLITE_REPLIED])) * HZ; | ||
179 | } | ||
180 | return 0; | ||
181 | } | ||
182 | |||
183 | static int | ||
184 | udplite_timeout_obj_to_nlattr(struct sk_buff *skb, const void *data) | ||
185 | { | ||
186 | const unsigned int *timeouts = data; | ||
187 | |||
188 | NLA_PUT_BE32(skb, CTA_TIMEOUT_UDPLITE_UNREPLIED, | ||
189 | htonl(timeouts[UDPLITE_CT_UNREPLIED] / HZ)); | ||
190 | NLA_PUT_BE32(skb, CTA_TIMEOUT_UDPLITE_REPLIED, | ||
191 | htonl(timeouts[UDPLITE_CT_REPLIED] / HZ)); | ||
192 | return 0; | ||
193 | |||
194 | nla_put_failure: | ||
195 | return -ENOSPC; | ||
196 | } | ||
197 | |||
198 | static const struct nla_policy | ||
199 | udplite_timeout_nla_policy[CTA_TIMEOUT_UDPLITE_MAX+1] = { | ||
200 | [CTA_TIMEOUT_UDPLITE_UNREPLIED] = { .type = NLA_U32 }, | ||
201 | [CTA_TIMEOUT_UDPLITE_REPLIED] = { .type = NLA_U32 }, | ||
202 | }; | ||
203 | #endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */ | ||
204 | |||
159 | #ifdef CONFIG_SYSCTL | 205 | #ifdef CONFIG_SYSCTL |
160 | static unsigned int udplite_sysctl_table_users; | 206 | static unsigned int udplite_sysctl_table_users; |
161 | static struct ctl_table_header *udplite_sysctl_header; | 207 | static struct ctl_table_header *udplite_sysctl_header; |
@@ -196,6 +242,16 @@ static struct nf_conntrack_l4proto nf_conntrack_l4proto_udplite4 __read_mostly = | |||
196 | .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, | 242 | .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, |
197 | .nla_policy = nf_ct_port_nla_policy, | 243 | .nla_policy = nf_ct_port_nla_policy, |
198 | #endif | 244 | #endif |
245 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT) | ||
246 | .ctnl_timeout = { | ||
247 | .nlattr_to_obj = udplite_timeout_nlattr_to_obj, | ||
248 | .obj_to_nlattr = udplite_timeout_obj_to_nlattr, | ||
249 | .nlattr_max = CTA_TIMEOUT_UDPLITE_MAX, | ||
250 | .obj_size = sizeof(unsigned int) * | ||
251 | CTA_TIMEOUT_UDPLITE_MAX, | ||
252 | .nla_policy = udplite_timeout_nla_policy, | ||
253 | }, | ||
254 | #endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */ | ||
199 | #ifdef CONFIG_SYSCTL | 255 | #ifdef CONFIG_SYSCTL |
200 | .ctl_table_users = &udplite_sysctl_table_users, | 256 | .ctl_table_users = &udplite_sysctl_table_users, |
201 | .ctl_table_header = &udplite_sysctl_header, | 257 | .ctl_table_header = &udplite_sysctl_header, |
@@ -221,6 +277,16 @@ static struct nf_conntrack_l4proto nf_conntrack_l4proto_udplite6 __read_mostly = | |||
221 | .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, | 277 | .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, |
222 | .nla_policy = nf_ct_port_nla_policy, | 278 | .nla_policy = nf_ct_port_nla_policy, |
223 | #endif | 279 | #endif |
280 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT) | ||
281 | .ctnl_timeout = { | ||
282 | .nlattr_to_obj = udplite_timeout_nlattr_to_obj, | ||
283 | .obj_to_nlattr = udplite_timeout_obj_to_nlattr, | ||
284 | .nlattr_max = CTA_TIMEOUT_UDPLITE_MAX, | ||
285 | .obj_size = sizeof(unsigned int) * | ||
286 | CTA_TIMEOUT_UDPLITE_MAX, | ||
287 | .nla_policy = udplite_timeout_nla_policy, | ||
288 | }, | ||
289 | #endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */ | ||
224 | #ifdef CONFIG_SYSCTL | 290 | #ifdef CONFIG_SYSCTL |
225 | .ctl_table_users = &udplite_sysctl_table_users, | 291 | .ctl_table_users = &udplite_sysctl_table_users, |
226 | .ctl_table_header = &udplite_sysctl_header, | 292 | .ctl_table_header = &udplite_sysctl_header, |
diff --git a/net/netfilter/nfnetlink_cttimeout.c b/net/netfilter/nfnetlink_cttimeout.c new file mode 100644 index 000000000000..b860d5217189 --- /dev/null +++ b/net/netfilter/nfnetlink_cttimeout.c | |||
@@ -0,0 +1,398 @@ | |||
1 | /* | ||
2 | * (C) 2012 by Pablo Neira Ayuso <pablo@netfilter.org> | ||
3 | * (C) 2012 by Vyatta Inc. <http://www.vyatta.com> | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License version 2 as | ||
7 | * published by the Free Software Foundation (or any later at your option). | ||
8 | */ | ||
9 | #include <linux/init.h> | ||
10 | #include <linux/module.h> | ||
11 | #include <linux/kernel.h> | ||
12 | #include <linux/rculist.h> | ||
13 | #include <linux/rculist_nulls.h> | ||
14 | #include <linux/types.h> | ||
15 | #include <linux/timer.h> | ||
16 | #include <linux/security.h> | ||
17 | #include <linux/skbuff.h> | ||
18 | #include <linux/errno.h> | ||
19 | #include <linux/netlink.h> | ||
20 | #include <linux/spinlock.h> | ||
21 | #include <linux/interrupt.h> | ||
22 | #include <linux/slab.h> | ||
23 | |||
24 | #include <linux/netfilter.h> | ||
25 | #include <net/netlink.h> | ||
26 | #include <net/sock.h> | ||
27 | #include <net/netfilter/nf_conntrack.h> | ||
28 | #include <net/netfilter/nf_conntrack_core.h> | ||
29 | #include <net/netfilter/nf_conntrack_l3proto.h> | ||
30 | #include <net/netfilter/nf_conntrack_l4proto.h> | ||
31 | #include <net/netfilter/nf_conntrack_tuple.h> | ||
32 | |||
33 | #include <linux/netfilter/nfnetlink.h> | ||
34 | #include <linux/netfilter/nfnetlink_cttimeout.h> | ||
35 | |||
36 | MODULE_LICENSE("GPL"); | ||
37 | MODULE_AUTHOR("Pablo Neira Ayuso <pablo@netfilter.org>"); | ||
38 | MODULE_DESCRIPTION("cttimeout: Extended Netfilter Connection Tracking timeout tuning"); | ||
39 | |||
40 | struct ctnl_timeout { | ||
41 | struct list_head head; | ||
42 | struct rcu_head rcu_head; | ||
43 | atomic_t refcnt; | ||
44 | char name[CTNL_TIMEOUT_NAME_MAX]; | ||
45 | __u16 l3num; | ||
46 | __u8 l4num; | ||
47 | char data[0]; | ||
48 | }; | ||
49 | |||
50 | static LIST_HEAD(cttimeout_list); | ||
51 | |||
52 | static const struct nla_policy cttimeout_nla_policy[CTA_TIMEOUT_MAX+1] = { | ||
53 | [CTA_TIMEOUT_NAME] = { .type = NLA_NUL_STRING }, | ||
54 | [CTA_TIMEOUT_L3PROTO] = { .type = NLA_U16 }, | ||
55 | [CTA_TIMEOUT_L4PROTO] = { .type = NLA_U8 }, | ||
56 | [CTA_TIMEOUT_DATA] = { .type = NLA_NESTED }, | ||
57 | }; | ||
58 | |||
59 | static int | ||
60 | ctnl_timeout_parse_policy(struct ctnl_timeout *timeout, | ||
61 | struct nf_conntrack_l4proto *l4proto, | ||
62 | const struct nlattr *attr) | ||
63 | { | ||
64 | int ret = 0; | ||
65 | |||
66 | if (likely(l4proto->ctnl_timeout.nlattr_to_obj)) { | ||
67 | struct nlattr *tb[l4proto->ctnl_timeout.nlattr_max+1]; | ||
68 | |||
69 | nla_parse_nested(tb, l4proto->ctnl_timeout.nlattr_max, | ||
70 | attr, l4proto->ctnl_timeout.nla_policy); | ||
71 | |||
72 | ret = l4proto->ctnl_timeout.nlattr_to_obj(tb, &timeout->data); | ||
73 | } | ||
74 | return ret; | ||
75 | } | ||
76 | |||
77 | static int | ||
78 | cttimeout_new_timeout(struct sock *ctnl, struct sk_buff *skb, | ||
79 | const struct nlmsghdr *nlh, | ||
80 | const struct nlattr * const cda[]) | ||
81 | { | ||
82 | __u16 l3num; | ||
83 | __u8 l4num; | ||
84 | struct nf_conntrack_l4proto *l4proto; | ||
85 | struct ctnl_timeout *timeout, *matching = NULL; | ||
86 | char *name; | ||
87 | int ret; | ||
88 | |||
89 | if (!cda[CTA_TIMEOUT_NAME] || | ||
90 | !cda[CTA_TIMEOUT_L3PROTO] || | ||
91 | !cda[CTA_TIMEOUT_L4PROTO] || | ||
92 | !cda[CTA_TIMEOUT_DATA]) | ||
93 | return -EINVAL; | ||
94 | |||
95 | name = nla_data(cda[CTA_TIMEOUT_NAME]); | ||
96 | l3num = ntohs(nla_get_be16(cda[CTA_TIMEOUT_L3PROTO])); | ||
97 | l4num = nla_get_u8(cda[CTA_TIMEOUT_L4PROTO]); | ||
98 | |||
99 | list_for_each_entry(timeout, &cttimeout_list, head) { | ||
100 | if (strncmp(timeout->name, name, CTNL_TIMEOUT_NAME_MAX) != 0) | ||
101 | continue; | ||
102 | |||
103 | if (nlh->nlmsg_flags & NLM_F_EXCL) | ||
104 | return -EEXIST; | ||
105 | |||
106 | matching = timeout; | ||
107 | break; | ||
108 | } | ||
109 | |||
110 | l4proto = __nf_ct_l4proto_find(l3num, l4num); | ||
111 | |||
112 | /* This protocol is not supportted, skip. */ | ||
113 | if (l4proto->l4proto != l4num) | ||
114 | return -EOPNOTSUPP; | ||
115 | |||
116 | if (matching) { | ||
117 | if (nlh->nlmsg_flags & NLM_F_REPLACE) { | ||
118 | /* You cannot replace one timeout policy by another of | ||
119 | * different kind, sorry. | ||
120 | */ | ||
121 | if (matching->l3num != l3num || | ||
122 | matching->l4num != l4num) | ||
123 | return -EINVAL; | ||
124 | |||
125 | ret = ctnl_timeout_parse_policy(matching, l4proto, | ||
126 | cda[CTA_TIMEOUT_DATA]); | ||
127 | return ret; | ||
128 | } | ||
129 | return -EBUSY; | ||
130 | } | ||
131 | |||
132 | timeout = kzalloc(sizeof(struct ctnl_timeout) + | ||
133 | l4proto->ctnl_timeout.obj_size, GFP_KERNEL); | ||
134 | if (timeout == NULL) | ||
135 | return -ENOMEM; | ||
136 | |||
137 | ret = ctnl_timeout_parse_policy(timeout, l4proto, | ||
138 | cda[CTA_TIMEOUT_DATA]); | ||
139 | if (ret < 0) | ||
140 | goto err; | ||
141 | |||
142 | strcpy(timeout->name, nla_data(cda[CTA_TIMEOUT_NAME])); | ||
143 | timeout->l3num = l3num; | ||
144 | timeout->l4num = l4num; | ||
145 | atomic_set(&timeout->refcnt, 1); | ||
146 | list_add_tail_rcu(&timeout->head, &cttimeout_list); | ||
147 | |||
148 | return 0; | ||
149 | err: | ||
150 | kfree(timeout); | ||
151 | return ret; | ||
152 | } | ||
153 | |||
154 | static int | ||
155 | ctnl_timeout_fill_info(struct sk_buff *skb, u32 pid, u32 seq, u32 type, | ||
156 | int event, struct ctnl_timeout *timeout) | ||
157 | { | ||
158 | struct nlmsghdr *nlh; | ||
159 | struct nfgenmsg *nfmsg; | ||
160 | unsigned int flags = pid ? NLM_F_MULTI : 0; | ||
161 | struct nf_conntrack_l4proto *l4proto; | ||
162 | |||
163 | event |= NFNL_SUBSYS_CTNETLINK_TIMEOUT << 8; | ||
164 | nlh = nlmsg_put(skb, pid, seq, event, sizeof(*nfmsg), flags); | ||
165 | if (nlh == NULL) | ||
166 | goto nlmsg_failure; | ||
167 | |||
168 | nfmsg = nlmsg_data(nlh); | ||
169 | nfmsg->nfgen_family = AF_UNSPEC; | ||
170 | nfmsg->version = NFNETLINK_V0; | ||
171 | nfmsg->res_id = 0; | ||
172 | |||
173 | NLA_PUT_STRING(skb, CTA_TIMEOUT_NAME, timeout->name); | ||
174 | NLA_PUT_BE16(skb, CTA_TIMEOUT_L3PROTO, htons(timeout->l3num)); | ||
175 | NLA_PUT_U8(skb, CTA_TIMEOUT_L4PROTO, timeout->l4num); | ||
176 | NLA_PUT_BE32(skb, CTA_TIMEOUT_USE, | ||
177 | htonl(atomic_read(&timeout->refcnt))); | ||
178 | |||
179 | l4proto = __nf_ct_l4proto_find(timeout->l3num, timeout->l4num); | ||
180 | |||
181 | /* If the timeout object does not match the layer 4 protocol tracker, | ||
182 | * then skip dumping the data part since we don't know how to | ||
183 | * interpret it. This may happen for UPDlite, SCTP and DCCP since | ||
184 | * you can unload the module. | ||
185 | */ | ||
186 | if (timeout->l4num != l4proto->l4proto) | ||
187 | goto out; | ||
188 | |||
189 | if (likely(l4proto->ctnl_timeout.obj_to_nlattr)) { | ||
190 | struct nlattr *nest_parms; | ||
191 | int ret; | ||
192 | |||
193 | nest_parms = nla_nest_start(skb, | ||
194 | CTA_TIMEOUT_DATA | NLA_F_NESTED); | ||
195 | if (!nest_parms) | ||
196 | goto nla_put_failure; | ||
197 | |||
198 | ret = l4proto->ctnl_timeout.obj_to_nlattr(skb, &timeout->data); | ||
199 | if (ret < 0) | ||
200 | goto nla_put_failure; | ||
201 | |||
202 | nla_nest_end(skb, nest_parms); | ||
203 | } | ||
204 | out: | ||
205 | nlmsg_end(skb, nlh); | ||
206 | return skb->len; | ||
207 | |||
208 | nlmsg_failure: | ||
209 | nla_put_failure: | ||
210 | nlmsg_cancel(skb, nlh); | ||
211 | return -1; | ||
212 | } | ||
213 | |||
214 | static int | ||
215 | ctnl_timeout_dump(struct sk_buff *skb, struct netlink_callback *cb) | ||
216 | { | ||
217 | struct ctnl_timeout *cur, *last; | ||
218 | |||
219 | if (cb->args[2]) | ||
220 | return 0; | ||
221 | |||
222 | last = (struct ctnl_timeout *)cb->args[1]; | ||
223 | if (cb->args[1]) | ||
224 | cb->args[1] = 0; | ||
225 | |||
226 | rcu_read_lock(); | ||
227 | list_for_each_entry_rcu(cur, &cttimeout_list, head) { | ||
228 | if (last && cur != last) | ||
229 | continue; | ||
230 | |||
231 | if (ctnl_timeout_fill_info(skb, NETLINK_CB(cb->skb).pid, | ||
232 | cb->nlh->nlmsg_seq, | ||
233 | NFNL_MSG_TYPE(cb->nlh->nlmsg_type), | ||
234 | IPCTNL_MSG_TIMEOUT_NEW, cur) < 0) { | ||
235 | cb->args[1] = (unsigned long)cur; | ||
236 | break; | ||
237 | } | ||
238 | } | ||
239 | if (!cb->args[1]) | ||
240 | cb->args[2] = 1; | ||
241 | rcu_read_unlock(); | ||
242 | return skb->len; | ||
243 | } | ||
244 | |||
245 | static int | ||
246 | cttimeout_get_timeout(struct sock *ctnl, struct sk_buff *skb, | ||
247 | const struct nlmsghdr *nlh, | ||
248 | const struct nlattr * const cda[]) | ||
249 | { | ||
250 | int ret = -ENOENT; | ||
251 | char *name; | ||
252 | struct ctnl_timeout *cur; | ||
253 | |||
254 | if (nlh->nlmsg_flags & NLM_F_DUMP) { | ||
255 | struct netlink_dump_control c = { | ||
256 | .dump = ctnl_timeout_dump, | ||
257 | }; | ||
258 | return netlink_dump_start(ctnl, skb, nlh, &c); | ||
259 | } | ||
260 | |||
261 | if (!cda[CTA_TIMEOUT_NAME]) | ||
262 | return -EINVAL; | ||
263 | name = nla_data(cda[CTA_TIMEOUT_NAME]); | ||
264 | |||
265 | list_for_each_entry(cur, &cttimeout_list, head) { | ||
266 | struct sk_buff *skb2; | ||
267 | |||
268 | if (strncmp(cur->name, name, CTNL_TIMEOUT_NAME_MAX) != 0) | ||
269 | continue; | ||
270 | |||
271 | skb2 = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | ||
272 | if (skb2 == NULL) { | ||
273 | ret = -ENOMEM; | ||
274 | break; | ||
275 | } | ||
276 | |||
277 | ret = ctnl_timeout_fill_info(skb2, NETLINK_CB(skb).pid, | ||
278 | nlh->nlmsg_seq, | ||
279 | NFNL_MSG_TYPE(nlh->nlmsg_type), | ||
280 | IPCTNL_MSG_TIMEOUT_NEW, cur); | ||
281 | if (ret <= 0) { | ||
282 | kfree_skb(skb2); | ||
283 | break; | ||
284 | } | ||
285 | ret = netlink_unicast(ctnl, skb2, NETLINK_CB(skb).pid, | ||
286 | MSG_DONTWAIT); | ||
287 | if (ret > 0) | ||
288 | ret = 0; | ||
289 | |||
290 | /* this avoids a loop in nfnetlink. */ | ||
291 | return ret == -EAGAIN ? -ENOBUFS : ret; | ||
292 | } | ||
293 | return ret; | ||
294 | } | ||
295 | |||
296 | /* try to delete object, fail if it is still in use. */ | ||
297 | static int ctnl_timeout_try_del(struct ctnl_timeout *timeout) | ||
298 | { | ||
299 | int ret = 0; | ||
300 | |||
301 | /* we want to avoid races with nf_ct_timeout_find_get. */ | ||
302 | if (atomic_dec_and_test(&timeout->refcnt)) { | ||
303 | /* We are protected by nfnl mutex. */ | ||
304 | list_del_rcu(&timeout->head); | ||
305 | kfree_rcu(timeout, rcu_head); | ||
306 | } else { | ||
307 | /* still in use, restore reference counter. */ | ||
308 | atomic_inc(&timeout->refcnt); | ||
309 | ret = -EBUSY; | ||
310 | } | ||
311 | return ret; | ||
312 | } | ||
313 | |||
314 | static int | ||
315 | cttimeout_del_timeout(struct sock *ctnl, struct sk_buff *skb, | ||
316 | const struct nlmsghdr *nlh, | ||
317 | const struct nlattr * const cda[]) | ||
318 | { | ||
319 | char *name; | ||
320 | struct ctnl_timeout *cur; | ||
321 | int ret = -ENOENT; | ||
322 | |||
323 | if (!cda[CTA_TIMEOUT_NAME]) { | ||
324 | list_for_each_entry(cur, &cttimeout_list, head) | ||
325 | ctnl_timeout_try_del(cur); | ||
326 | |||
327 | return 0; | ||
328 | } | ||
329 | name = nla_data(cda[CTA_TIMEOUT_NAME]); | ||
330 | |||
331 | list_for_each_entry(cur, &cttimeout_list, head) { | ||
332 | if (strncmp(cur->name, name, CTNL_TIMEOUT_NAME_MAX) != 0) | ||
333 | continue; | ||
334 | |||
335 | ret = ctnl_timeout_try_del(cur); | ||
336 | if (ret < 0) | ||
337 | return ret; | ||
338 | |||
339 | break; | ||
340 | } | ||
341 | return ret; | ||
342 | } | ||
343 | |||
344 | static const struct nfnl_callback cttimeout_cb[IPCTNL_MSG_TIMEOUT_MAX] = { | ||
345 | [IPCTNL_MSG_TIMEOUT_NEW] = { .call = cttimeout_new_timeout, | ||
346 | .attr_count = CTA_TIMEOUT_MAX, | ||
347 | .policy = cttimeout_nla_policy }, | ||
348 | [IPCTNL_MSG_TIMEOUT_GET] = { .call = cttimeout_get_timeout, | ||
349 | .attr_count = CTA_TIMEOUT_MAX, | ||
350 | .policy = cttimeout_nla_policy }, | ||
351 | [IPCTNL_MSG_TIMEOUT_DELETE] = { .call = cttimeout_del_timeout, | ||
352 | .attr_count = CTA_TIMEOUT_MAX, | ||
353 | .policy = cttimeout_nla_policy }, | ||
354 | }; | ||
355 | |||
356 | static const struct nfnetlink_subsystem cttimeout_subsys = { | ||
357 | .name = "conntrack_timeout", | ||
358 | .subsys_id = NFNL_SUBSYS_CTNETLINK_TIMEOUT, | ||
359 | .cb_count = IPCTNL_MSG_TIMEOUT_MAX, | ||
360 | .cb = cttimeout_cb, | ||
361 | }; | ||
362 | |||
363 | MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_CTNETLINK_TIMEOUT); | ||
364 | |||
365 | static int __init cttimeout_init(void) | ||
366 | { | ||
367 | int ret; | ||
368 | |||
369 | ret = nfnetlink_subsys_register(&cttimeout_subsys); | ||
370 | if (ret < 0) { | ||
371 | pr_err("cttimeout_init: cannot register cttimeout with " | ||
372 | "nfnetlink.\n"); | ||
373 | goto err_out; | ||
374 | } | ||
375 | return 0; | ||
376 | |||
377 | err_out: | ||
378 | return ret; | ||
379 | } | ||
380 | |||
381 | static void __exit cttimeout_exit(void) | ||
382 | { | ||
383 | struct ctnl_timeout *cur, *tmp; | ||
384 | |||
385 | pr_info("cttimeout: unregistering from nfnetlink.\n"); | ||
386 | |||
387 | nfnetlink_subsys_unregister(&cttimeout_subsys); | ||
388 | list_for_each_entry_safe(cur, tmp, &cttimeout_list, head) { | ||
389 | list_del_rcu(&cur->head); | ||
390 | /* We are sure that our objects have no clients at this point, | ||
391 | * it's safe to release them all without checking refcnt. | ||
392 | */ | ||
393 | kfree_rcu(cur, rcu_head); | ||
394 | } | ||
395 | } | ||
396 | |||
397 | module_init(cttimeout_init); | ||
398 | module_exit(cttimeout_exit); | ||