]> Pileus Git - ~andy/linux/blobdiff - net/netfilter/nf_conntrack_proto_tcp.c
Merge branch 'master' of git://1984.lsi.us.es/net
[~andy/linux] / net / netfilter / nf_conntrack_proto_tcp.c
index 97b9f3ebf28c2113be8ea5bfa015c75af0df9dbf..361eade62a09e58e06194fb78d8c6b07333f015a 100644 (file)
@@ -64,13 +64,7 @@ static const char *const tcp_conntrack_names[] = {
 #define HOURS * 60 MINS
 #define DAYS * 24 HOURS
 
-/* RFC1122 says the R2 limit should be at least 100 seconds.
-   Linux uses 15 packets as limit, which corresponds
-   to ~13-30min depending on RTO. */
-static unsigned int nf_ct_tcp_timeout_max_retrans __read_mostly    =   5 MINS;
-static unsigned int nf_ct_tcp_timeout_unacknowledged __read_mostly =   5 MINS;
-
-static unsigned int tcp_timeouts[TCP_CONNTRACK_MAX] __read_mostly = {
+static unsigned int tcp_timeouts[TCP_CONNTRACK_TIMEOUT_MAX] __read_mostly = {
        [TCP_CONNTRACK_SYN_SENT]        = 2 MINS,
        [TCP_CONNTRACK_SYN_RECV]        = 60 SECS,
        [TCP_CONNTRACK_ESTABLISHED]     = 5 DAYS,
@@ -80,6 +74,11 @@ static unsigned int tcp_timeouts[TCP_CONNTRACK_MAX] __read_mostly = {
        [TCP_CONNTRACK_TIME_WAIT]       = 2 MINS,
        [TCP_CONNTRACK_CLOSE]           = 10 SECS,
        [TCP_CONNTRACK_SYN_SENT2]       = 2 MINS,
+/* RFC1122 says the R2 limit should be at least 100 seconds.
+   Linux uses 15 packets as limit, which corresponds
+   to ~13-30min depending on RTO. */
+       [TCP_CONNTRACK_RETRANS]         = 5 MINS,
+       [TCP_CONNTRACK_UNACK]           = 5 MINS,
 };
 
 #define sNO TCP_CONNTRACK_NONE
@@ -814,13 +813,19 @@ static int tcp_error(struct net *net, struct nf_conn *tmpl,
        return NF_ACCEPT;
 }
 
+static unsigned int *tcp_get_timeouts(struct net *net)
+{
+       return tcp_timeouts;
+}
+
 /* Returns verdict for packet, or -1 for invalid. */
 static int tcp_packet(struct nf_conn *ct,
                      const struct sk_buff *skb,
                      unsigned int dataoff,
                      enum ip_conntrack_info ctinfo,
                      u_int8_t pf,
-                     unsigned int hooknum)
+                     unsigned int hooknum,
+                     unsigned int *timeouts)
 {
        struct net *net = nf_ct_net(ct);
        struct nf_conntrack_tuple *tuple;
@@ -1015,14 +1020,14 @@ static int tcp_packet(struct nf_conn *ct,
                ct->proto.tcp.seen[dir].flags |= IP_CT_TCP_FLAG_CLOSE_INIT;
 
        if (ct->proto.tcp.retrans >= nf_ct_tcp_max_retrans &&
-           tcp_timeouts[new_state] > nf_ct_tcp_timeout_max_retrans)
-               timeout = nf_ct_tcp_timeout_max_retrans;
+           timeouts[new_state] > timeouts[TCP_CONNTRACK_RETRANS])
+               timeout = timeouts[TCP_CONNTRACK_RETRANS];
        else if ((ct->proto.tcp.seen[0].flags | ct->proto.tcp.seen[1].flags) &
                 IP_CT_TCP_FLAG_DATA_UNACKNOWLEDGED &&
-                tcp_timeouts[new_state] > nf_ct_tcp_timeout_unacknowledged)
-               timeout = nf_ct_tcp_timeout_unacknowledged;
+                timeouts[new_state] > timeouts[TCP_CONNTRACK_UNACK])
+               timeout = timeouts[TCP_CONNTRACK_UNACK];
        else
-               timeout = tcp_timeouts[new_state];
+               timeout = timeouts[new_state];
        spin_unlock_bh(&ct->lock);
 
        if (new_state != old_state)
@@ -1054,7 +1059,7 @@ static int tcp_packet(struct nf_conn *ct,
 
 /* Called when a new connection for this protocol found. */
 static bool tcp_new(struct nf_conn *ct, const struct sk_buff *skb,
-                   unsigned int dataoff)
+                   unsigned int dataoff, unsigned int *timeouts)
 {
        enum tcp_conntrack new_state;
        const struct tcphdr *th;
@@ -1239,6 +1244,113 @@ static int tcp_nlattr_tuple_size(void)
 }
 #endif
 
+#if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT)
+
+#include <linux/netfilter/nfnetlink.h>
+#include <linux/netfilter/nfnetlink_cttimeout.h>
+
+static int tcp_timeout_nlattr_to_obj(struct nlattr *tb[], void *data)
+{
+       unsigned int *timeouts = data;
+       int i;
+
+       /* set default TCP timeouts. */
+       for (i=0; i<TCP_CONNTRACK_TIMEOUT_MAX; i++)
+               timeouts[i] = tcp_timeouts[i];
+
+       if (tb[CTA_TIMEOUT_TCP_SYN_SENT]) {
+               timeouts[TCP_CONNTRACK_SYN_SENT] =
+                       ntohl(nla_get_be32(tb[CTA_TIMEOUT_TCP_SYN_SENT]))*HZ;
+       }
+       if (tb[CTA_TIMEOUT_TCP_SYN_RECV]) {
+               timeouts[TCP_CONNTRACK_SYN_RECV] =
+                       ntohl(nla_get_be32(tb[CTA_TIMEOUT_TCP_SYN_RECV]))*HZ;
+       }
+       if (tb[CTA_TIMEOUT_TCP_ESTABLISHED]) {
+               timeouts[TCP_CONNTRACK_ESTABLISHED] =
+                       ntohl(nla_get_be32(tb[CTA_TIMEOUT_TCP_ESTABLISHED]))*HZ;
+       }
+       if (tb[CTA_TIMEOUT_TCP_FIN_WAIT]) {
+               timeouts[TCP_CONNTRACK_FIN_WAIT] =
+                       ntohl(nla_get_be32(tb[CTA_TIMEOUT_TCP_FIN_WAIT]))*HZ;
+       }
+       if (tb[CTA_TIMEOUT_TCP_CLOSE_WAIT]) {
+               timeouts[TCP_CONNTRACK_CLOSE_WAIT] =
+                       ntohl(nla_get_be32(tb[CTA_TIMEOUT_TCP_CLOSE_WAIT]))*HZ;
+       }
+       if (tb[CTA_TIMEOUT_TCP_LAST_ACK]) {
+               timeouts[TCP_CONNTRACK_LAST_ACK] =
+                       ntohl(nla_get_be32(tb[CTA_TIMEOUT_TCP_LAST_ACK]))*HZ;
+       }
+       if (tb[CTA_TIMEOUT_TCP_TIME_WAIT]) {
+               timeouts[TCP_CONNTRACK_TIME_WAIT] =
+                       ntohl(nla_get_be32(tb[CTA_TIMEOUT_TCP_TIME_WAIT]))*HZ;
+       }
+       if (tb[CTA_TIMEOUT_TCP_CLOSE]) {
+               timeouts[TCP_CONNTRACK_CLOSE] =
+                       ntohl(nla_get_be32(tb[CTA_TIMEOUT_TCP_CLOSE]))*HZ;
+       }
+       if (tb[CTA_TIMEOUT_TCP_SYN_SENT2]) {
+               timeouts[TCP_CONNTRACK_SYN_SENT2] =
+                       ntohl(nla_get_be32(tb[CTA_TIMEOUT_TCP_SYN_SENT2]))*HZ;
+       }
+       if (tb[CTA_TIMEOUT_TCP_RETRANS]) {
+               timeouts[TCP_CONNTRACK_RETRANS] =
+                       ntohl(nla_get_be32(tb[CTA_TIMEOUT_TCP_RETRANS]))*HZ;
+       }
+       if (tb[CTA_TIMEOUT_TCP_UNACK]) {
+               timeouts[TCP_CONNTRACK_UNACK] =
+                       ntohl(nla_get_be32(tb[CTA_TIMEOUT_TCP_UNACK]))*HZ;
+       }
+       return 0;
+}
+
+static int
+tcp_timeout_obj_to_nlattr(struct sk_buff *skb, const void *data)
+{
+       const unsigned int *timeouts = data;
+
+       NLA_PUT_BE32(skb, CTA_TIMEOUT_TCP_SYN_SENT,
+                       htonl(timeouts[TCP_CONNTRACK_SYN_SENT] / HZ));
+       NLA_PUT_BE32(skb, CTA_TIMEOUT_TCP_SYN_RECV,
+                       htonl(timeouts[TCP_CONNTRACK_SYN_RECV] / HZ));
+       NLA_PUT_BE32(skb, CTA_TIMEOUT_TCP_ESTABLISHED,
+                       htonl(timeouts[TCP_CONNTRACK_ESTABLISHED] / HZ));
+       NLA_PUT_BE32(skb, CTA_TIMEOUT_TCP_FIN_WAIT,
+                       htonl(timeouts[TCP_CONNTRACK_FIN_WAIT] / HZ));
+       NLA_PUT_BE32(skb, CTA_TIMEOUT_TCP_CLOSE_WAIT,
+                       htonl(timeouts[TCP_CONNTRACK_CLOSE_WAIT] / HZ));
+       NLA_PUT_BE32(skb, CTA_TIMEOUT_TCP_LAST_ACK,
+                       htonl(timeouts[TCP_CONNTRACK_LAST_ACK] / HZ));
+       NLA_PUT_BE32(skb, CTA_TIMEOUT_TCP_TIME_WAIT,
+                       htonl(timeouts[TCP_CONNTRACK_TIME_WAIT] / HZ));
+       NLA_PUT_BE32(skb, CTA_TIMEOUT_TCP_CLOSE,
+                       htonl(timeouts[TCP_CONNTRACK_CLOSE] / HZ));
+       NLA_PUT_BE32(skb, CTA_TIMEOUT_TCP_SYN_SENT2,
+                       htonl(timeouts[TCP_CONNTRACK_SYN_SENT2] / HZ));
+       NLA_PUT_BE32(skb, CTA_TIMEOUT_TCP_RETRANS,
+                       htonl(timeouts[TCP_CONNTRACK_RETRANS] / HZ));
+       NLA_PUT_BE32(skb, CTA_TIMEOUT_TCP_UNACK,
+                       htonl(timeouts[TCP_CONNTRACK_UNACK] / HZ));
+       return 0;
+
+nla_put_failure:
+       return -ENOSPC;
+}
+
+static const struct nla_policy tcp_timeout_nla_policy[CTA_TIMEOUT_TCP_MAX+1] = {
+       [CTA_TIMEOUT_TCP_SYN_SENT]      = { .type = NLA_U32 },
+       [CTA_TIMEOUT_TCP_SYN_RECV]      = { .type = NLA_U32 },
+       [CTA_TIMEOUT_TCP_ESTABLISHED]   = { .type = NLA_U32 },
+       [CTA_TIMEOUT_TCP_FIN_WAIT]      = { .type = NLA_U32 },
+       [CTA_TIMEOUT_TCP_CLOSE_WAIT]    = { .type = NLA_U32 },
+       [CTA_TIMEOUT_TCP_LAST_ACK]      = { .type = NLA_U32 },
+       [CTA_TIMEOUT_TCP_TIME_WAIT]     = { .type = NLA_U32 },
+       [CTA_TIMEOUT_TCP_CLOSE]         = { .type = NLA_U32 },
+       [CTA_TIMEOUT_TCP_SYN_SENT2]     = { .type = NLA_U32 },
+};
+#endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
+
 #ifdef CONFIG_SYSCTL
 static unsigned int tcp_sysctl_table_users;
 static struct ctl_table_header *tcp_sysctl_header;
@@ -1301,14 +1413,14 @@ static struct ctl_table tcp_sysctl_table[] = {
        },
        {
                .procname       = "nf_conntrack_tcp_timeout_max_retrans",
-               .data           = &nf_ct_tcp_timeout_max_retrans,
+               .data           = &tcp_timeouts[TCP_CONNTRACK_RETRANS],
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
        },
        {
                .procname       = "nf_conntrack_tcp_timeout_unacknowledged",
-               .data           = &nf_ct_tcp_timeout_unacknowledged,
+               .data           = &tcp_timeouts[TCP_CONNTRACK_UNACK],
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
@@ -1404,7 +1516,7 @@ static struct ctl_table tcp_compat_sysctl_table[] = {
        },
        {
                .procname       = "ip_conntrack_tcp_timeout_max_retrans",
-               .data           = &nf_ct_tcp_timeout_max_retrans,
+               .data           = &tcp_timeouts[TCP_CONNTRACK_RETRANS],
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
@@ -1445,6 +1557,7 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_tcp4 __read_mostly =
        .print_tuple            = tcp_print_tuple,
        .print_conntrack        = tcp_print_conntrack,
        .packet                 = tcp_packet,
+       .get_timeouts           = tcp_get_timeouts,
        .new                    = tcp_new,
        .error                  = tcp_error,
 #if IS_ENABLED(CONFIG_NF_CT_NETLINK)
@@ -1456,6 +1569,16 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_tcp4 __read_mostly =
        .nlattr_tuple_size      = tcp_nlattr_tuple_size,
        .nla_policy             = nf_ct_port_nla_policy,
 #endif
+#if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT)
+       .ctnl_timeout           = {
+               .nlattr_to_obj  = tcp_timeout_nlattr_to_obj,
+               .obj_to_nlattr  = tcp_timeout_obj_to_nlattr,
+               .nlattr_max     = CTA_TIMEOUT_TCP_MAX,
+               .obj_size       = sizeof(unsigned int) *
+                                       TCP_CONNTRACK_TIMEOUT_MAX,
+               .nla_policy     = tcp_timeout_nla_policy,
+       },
+#endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
 #ifdef CONFIG_SYSCTL
        .ctl_table_users        = &tcp_sysctl_table_users,
        .ctl_table_header       = &tcp_sysctl_header,
@@ -1477,6 +1600,7 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_tcp6 __read_mostly =
        .print_tuple            = tcp_print_tuple,
        .print_conntrack        = tcp_print_conntrack,
        .packet                 = tcp_packet,
+       .get_timeouts           = tcp_get_timeouts,
        .new                    = tcp_new,
        .error                  = tcp_error,
 #if IS_ENABLED(CONFIG_NF_CT_NETLINK)
@@ -1488,6 +1612,16 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_tcp6 __read_mostly =
        .nlattr_tuple_size      = tcp_nlattr_tuple_size,
        .nla_policy             = nf_ct_port_nla_policy,
 #endif
+#if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT)
+       .ctnl_timeout           = {
+               .nlattr_to_obj  = tcp_timeout_nlattr_to_obj,
+               .obj_to_nlattr  = tcp_timeout_obj_to_nlattr,
+               .nlattr_max     = CTA_TIMEOUT_TCP_MAX,
+               .obj_size       = sizeof(unsigned int) *
+                                       TCP_CONNTRACK_TIMEOUT_MAX,
+               .nla_policy     = tcp_timeout_nla_policy,
+       },
+#endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
 #ifdef CONFIG_SYSCTL
        .ctl_table_users        = &tcp_sysctl_table_users,
        .ctl_table_header       = &tcp_sysctl_header,