aboutsummaryrefslogtreecommitdiffstats
path: root/net/netfilter
diff options
context:
space:
mode:
authorPablo Neira Ayuso <pablo@netfilter.org>2012-02-28 13:13:48 -0500
committerPablo Neira Ayuso <pablo@netfilter.org>2012-03-07 11:41:22 -0500
commit50978462300f74dc48aea4a38471cb69bdf741a5 (patch)
tree0d63f721f996d4c4a4e37cd08df949e25d4c980e /net/netfilter
parent2c8503f55fbdfbeff4164f133df804cf4d316290 (diff)
netfilter: add cttimeout infrastructure for fine timeout tuning
This patch adds the infrastructure to add fine timeout tuning over nfnetlink. Now you can use the NFNL_SUBSYS_CTNETLINK_TIMEOUT subsystem to create/delete/dump timeout objects that contain some specific timeout policy for one flow. The follow up patches will allow you attach timeout policy object to conntrack via the CT target and the conntrack extension infrastructure. Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Diffstat (limited to 'net/netfilter')
-rw-r--r--net/netfilter/Kconfig11
-rw-r--r--net/netfilter/Makefile1
-rw-r--r--net/netfilter/nf_conntrack_proto_dccp.c70
-rw-r--r--net/netfilter/nf_conntrack_proto_generic.c48
-rw-r--r--net/netfilter/nf_conntrack_proto_gre.c55
-rw-r--r--net/netfilter/nf_conntrack_proto_sctp.c69
-rw-r--r--net/netfilter/nf_conntrack_proto_tcp.c127
-rw-r--r--net/netfilter/nf_conntrack_proto_udp.c64
-rw-r--r--net/netfilter/nf_conntrack_proto_udplite.c66
-rw-r--r--net/netfilter/nfnetlink_cttimeout.c398
10 files changed, 909 insertions, 0 deletions
diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig
index b895d8b1321..f3efb6570dd 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
317config 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
317endif # NF_CONNTRACK 328endif # NF_CONNTRACK
318 329
319# transparent proxy support 330# transparent proxy support
diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile
index a28c2a6563f..cf7cdd630bd 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
24obj-$(CONFIG_NF_CT_NETLINK) += nf_conntrack_netlink.o 24obj-$(CONFIG_NF_CT_NETLINK) += nf_conntrack_netlink.o
25obj-$(CONFIG_NF_CT_NETLINK_TIMEOUT) += nfnetlink_cttimeout.o
25 26
26# connection tracking helpers 27# connection tracking helpers
27nf_conntrack_h323-objs := nf_conntrack_h323_main.o nf_conntrack_h323_asn1.o 28nf_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 8ea33598a0a..24fdce256cb 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
717static 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
736static int
737dccp_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
747nla_put_failure:
748 return -ENOSPC;
749}
750
751static const struct nla_policy
752dccp_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 */
713static struct ctl_table dccp_sysctl_table[] = { 765static 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
789static struct nf_conntrack_l4proto dccp_proto6 __read_mostly = { 850static 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
812static __net_init int dccp_net_init(struct net *net) 882static __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 0e6c5451db8..835e24c58f0 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
73static 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
88static int
89generic_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
97nla_put_failure:
98 return -ENOSPC;
99}
100
101static const struct nla_policy
102generic_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
69static struct ctl_table_header *generic_sysctl_header; 108static struct ctl_table_header *generic_sysctl_header;
70static struct ctl_table generic_sysctl_table[] = { 109static 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 1bf01c95658..659648c4b14 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
300static 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
319static int
320gre_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
330nla_put_failure:
331 return -ENOSPC;
332}
333
334static const struct nla_policy
335gre_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 */
296static struct nf_conntrack_l4proto nf_conntrack_l4proto_gre4 __read_mostly = { 342static 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
317static int proto_gre_net_init(struct net *net) 372static 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 2a0703371e2..72b5088592d 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
557static 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
575static int
576sctp_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
586nla_put_failure:
587 return -ENOSPC;
588}
589
590static const struct nla_policy
591sctp_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
553static unsigned int sctp_sysctl_table_users; 604static unsigned int sctp_sysctl_table_users;
554static struct ctl_table_header *sctp_sysctl_header; 605static 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 8372bb43feb..361eade62a0 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
1252static 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
1308static int
1309tcp_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
1337nla_put_failure:
1338 return -ENOSPC;
1339}
1340
1341static 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
1248static unsigned int tcp_sysctl_table_users; 1355static unsigned int tcp_sysctl_table_users;
1249static struct ctl_table_header *tcp_sysctl_header; 1356static 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 70e005992d5..a9073dc1548 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
160static 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
179static int
180udp_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
190nla_put_failure:
191 return -ENOSPC;
192}
193
194static const struct nla_policy
195udp_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
156static unsigned int udp_sysctl_table_users; 202static unsigned int udp_sysctl_table_users;
157static struct ctl_table_header *udp_sysctl_header; 203static 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 0b32ccb1d51..e0606392cda 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
164static 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
183static int
184udplite_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
194nla_put_failure:
195 return -ENOSPC;
196}
197
198static const struct nla_policy
199udplite_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
160static unsigned int udplite_sysctl_table_users; 206static unsigned int udplite_sysctl_table_users;
161static struct ctl_table_header *udplite_sysctl_header; 207static 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 00000000000..b860d521718
--- /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
36MODULE_LICENSE("GPL");
37MODULE_AUTHOR("Pablo Neira Ayuso <pablo@netfilter.org>");
38MODULE_DESCRIPTION("cttimeout: Extended Netfilter Connection Tracking timeout tuning");
39
40struct 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
50static LIST_HEAD(cttimeout_list);
51
52static 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
59static int
60ctnl_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
77static int
78cttimeout_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;
149err:
150 kfree(timeout);
151 return ret;
152}
153
154static int
155ctnl_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 }
204out:
205 nlmsg_end(skb, nlh);
206 return skb->len;
207
208nlmsg_failure:
209nla_put_failure:
210 nlmsg_cancel(skb, nlh);
211 return -1;
212}
213
214static int
215ctnl_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
245static int
246cttimeout_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. */
297static 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
314static int
315cttimeout_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
344static 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
356static 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
363MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_CTNETLINK_TIMEOUT);
364
365static 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
377err_out:
378 return ret;
379}
380
381static 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
397module_init(cttimeout_init);
398module_exit(cttimeout_exit);