netfilter: add protocol independent NAT core
[deliverable/linux.git] / net / netfilter / nf_conntrack_proto_tcp.c
index 21ff1a99f5341c1fe475c10a0170a1b62fc9a5f5..9c2cc716f4a5ac1c622db9b8586f72fe9324cc88 100644 (file)
@@ -270,6 +270,11 @@ static const u8 tcp_conntracks[2][6][TCP_CONNTRACK_MAX] = {
        }
 };
 
+static inline struct nf_tcp_net *tcp_pernet(struct net *net)
+{
+       return &net->ct.nf_ct_proto.tcp;
+}
+
 static bool tcp_pkt_to_tuple(const struct sk_buff *skb, unsigned int dataoff,
                             struct nf_conntrack_tuple *tuple)
 {
@@ -500,10 +505,10 @@ static inline s16 nat_offset(const struct nf_conn *ct,
 
        return get_offset != NULL ? get_offset(ct, dir, seq) : 0;
 }
-#define NAT_OFFSET(pf, ct, dir, seq) \
-       (pf == NFPROTO_IPV4 ? nat_offset(ct, dir, seq) : 0)
+#define NAT_OFFSET(ct, dir, seq) \
+       (nat_offset(ct, dir, seq))
 #else
-#define NAT_OFFSET(pf, ct, dir, seq)   0
+#define NAT_OFFSET(ct, dir, seq)       0
 #endif
 
 static bool tcp_in_window(const struct nf_conn *ct,
@@ -516,6 +521,7 @@ static bool tcp_in_window(const struct nf_conn *ct,
                          u_int8_t pf)
 {
        struct net *net = nf_ct_net(ct);
+       struct nf_tcp_net *tn = tcp_pernet(net);
        struct ip_ct_tcp_state *sender = &state->seen[dir];
        struct ip_ct_tcp_state *receiver = &state->seen[!dir];
        const struct nf_conntrack_tuple *tuple = &ct->tuplehash[dir].tuple;
@@ -535,7 +541,7 @@ static bool tcp_in_window(const struct nf_conn *ct,
                tcp_sack(skb, dataoff, tcph, &sack);
 
        /* Take into account NAT sequence number mangling */
-       receiver_offset = NAT_OFFSET(pf, ct, !dir, ack - 1);
+       receiver_offset = NAT_OFFSET(ct, !dir, ack - 1);
        ack -= receiver_offset;
        sack -= receiver_offset;
 
@@ -720,7 +726,7 @@ static bool tcp_in_window(const struct nf_conn *ct,
        } else {
                res = false;
                if (sender->flags & IP_CT_TCP_FLAG_BE_LIBERAL ||
-                   nf_ct_tcp_be_liberal)
+                   tn->tcp_be_liberal)
                        res = true;
                if (!res && LOG_INVALID(net, IPPROTO_TCP))
                        nf_log_packet(pf, 0, skb, NULL, NULL, NULL,
@@ -815,7 +821,7 @@ static int tcp_error(struct net *net, struct nf_conn *tmpl,
 
 static unsigned int *tcp_get_timeouts(struct net *net)
 {
-       return tcp_timeouts;
+       return tcp_pernet(net)->timeouts;
 }
 
 /* Returns verdict for packet, or -1 for invalid. */
@@ -828,6 +834,7 @@ static int tcp_packet(struct nf_conn *ct,
                      unsigned int *timeouts)
 {
        struct net *net = nf_ct_net(ct);
+       struct nf_tcp_net *tn = tcp_pernet(net);
        struct nf_conntrack_tuple *tuple;
        enum tcp_conntrack new_state, old_state;
        enum ip_conntrack_dir dir;
@@ -1020,7 +1027,7 @@ static int tcp_packet(struct nf_conn *ct,
            && new_state == TCP_CONNTRACK_FIN_WAIT)
                ct->proto.tcp.seen[dir].flags |= IP_CT_TCP_FLAG_CLOSE_INIT;
 
-       if (ct->proto.tcp.retrans >= nf_ct_tcp_max_retrans &&
+       if (ct->proto.tcp.retrans >= tn->tcp_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) &
@@ -1065,6 +1072,8 @@ static bool tcp_new(struct nf_conn *ct, const struct sk_buff *skb,
        enum tcp_conntrack new_state;
        const struct tcphdr *th;
        struct tcphdr _tcph;
+       struct net *net = nf_ct_net(ct);
+       struct nf_tcp_net *tn = tcp_pernet(net);
        const struct ip_ct_tcp_state *sender = &ct->proto.tcp.seen[0];
        const struct ip_ct_tcp_state *receiver = &ct->proto.tcp.seen[1];
 
@@ -1093,7 +1102,7 @@ static bool tcp_new(struct nf_conn *ct, const struct sk_buff *skb,
                        ct->proto.tcp.seen[0].td_end;
 
                tcp_options(skb, dataoff, th, &ct->proto.tcp.seen[0]);
-       } else if (nf_ct_tcp_loose == 0) {
+       } else if (tn->tcp_loose == 0) {
                /* Don't try to pick up connections. */
                return false;
        } else {
@@ -1251,14 +1260,16 @@ static int tcp_nlattr_tuple_size(void)
 #include <linux/netfilter/nfnetlink.h>
 #include <linux/netfilter/nfnetlink_cttimeout.h>
 
-static int tcp_timeout_nlattr_to_obj(struct nlattr *tb[], void *data)
+static int tcp_timeout_nlattr_to_obj(struct nlattr *tb[],
+                                    struct net *net, void *data)
 {
        unsigned int *timeouts = data;
+       struct nf_tcp_net *tn = tcp_pernet(net);
        int i;
 
        /* set default TCP timeouts. */
        for (i=0; i<TCP_CONNTRACK_TIMEOUT_MAX; i++)
-               timeouts[i] = tcp_timeouts[i];
+               timeouts[i] = tn->timeouts[i];
 
        if (tb[CTA_TIMEOUT_TCP_SYN_SENT]) {
                timeouts[TCP_CONNTRACK_SYN_SENT] =
@@ -1355,96 +1366,81 @@ static const struct nla_policy tcp_timeout_nla_policy[CTA_TIMEOUT_TCP_MAX+1] = {
 #endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
 
 #ifdef CONFIG_SYSCTL
-static unsigned int tcp_sysctl_table_users;
-static struct ctl_table_header *tcp_sysctl_header;
 static struct ctl_table tcp_sysctl_table[] = {
        {
                .procname       = "nf_conntrack_tcp_timeout_syn_sent",
-               .data           = &tcp_timeouts[TCP_CONNTRACK_SYN_SENT],
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
        },
        {
                .procname       = "nf_conntrack_tcp_timeout_syn_recv",
-               .data           = &tcp_timeouts[TCP_CONNTRACK_SYN_RECV],
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
        },
        {
                .procname       = "nf_conntrack_tcp_timeout_established",
-               .data           = &tcp_timeouts[TCP_CONNTRACK_ESTABLISHED],
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
        },
        {
                .procname       = "nf_conntrack_tcp_timeout_fin_wait",
-               .data           = &tcp_timeouts[TCP_CONNTRACK_FIN_WAIT],
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
        },
        {
                .procname       = "nf_conntrack_tcp_timeout_close_wait",
-               .data           = &tcp_timeouts[TCP_CONNTRACK_CLOSE_WAIT],
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
        },
        {
                .procname       = "nf_conntrack_tcp_timeout_last_ack",
-               .data           = &tcp_timeouts[TCP_CONNTRACK_LAST_ACK],
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
        },
        {
                .procname       = "nf_conntrack_tcp_timeout_time_wait",
-               .data           = &tcp_timeouts[TCP_CONNTRACK_TIME_WAIT],
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
        },
        {
                .procname       = "nf_conntrack_tcp_timeout_close",
-               .data           = &tcp_timeouts[TCP_CONNTRACK_CLOSE],
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
        },
        {
                .procname       = "nf_conntrack_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           = &tcp_timeouts[TCP_CONNTRACK_UNACK],
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
        },
        {
                .procname       = "nf_conntrack_tcp_loose",
-               .data           = &nf_ct_tcp_loose,
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec,
        },
        {
                .procname       = "nf_conntrack_tcp_be_liberal",
-               .data           = &nf_ct_tcp_be_liberal,
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec,
        },
        {
                .procname       = "nf_conntrack_tcp_max_retrans",
-               .data           = &nf_ct_tcp_max_retrans,
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec,
@@ -1456,91 +1452,78 @@ static struct ctl_table tcp_sysctl_table[] = {
 static struct ctl_table tcp_compat_sysctl_table[] = {
        {
                .procname       = "ip_conntrack_tcp_timeout_syn_sent",
-               .data           = &tcp_timeouts[TCP_CONNTRACK_SYN_SENT],
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
        },
        {
                .procname       = "ip_conntrack_tcp_timeout_syn_sent2",
-               .data           = &tcp_timeouts[TCP_CONNTRACK_SYN_SENT2],
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
        },
        {
                .procname       = "ip_conntrack_tcp_timeout_syn_recv",
-               .data           = &tcp_timeouts[TCP_CONNTRACK_SYN_RECV],
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
        },
        {
                .procname       = "ip_conntrack_tcp_timeout_established",
-               .data           = &tcp_timeouts[TCP_CONNTRACK_ESTABLISHED],
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
        },
        {
                .procname       = "ip_conntrack_tcp_timeout_fin_wait",
-               .data           = &tcp_timeouts[TCP_CONNTRACK_FIN_WAIT],
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
        },
        {
                .procname       = "ip_conntrack_tcp_timeout_close_wait",
-               .data           = &tcp_timeouts[TCP_CONNTRACK_CLOSE_WAIT],
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
        },
        {
                .procname       = "ip_conntrack_tcp_timeout_last_ack",
-               .data           = &tcp_timeouts[TCP_CONNTRACK_LAST_ACK],
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
        },
        {
                .procname       = "ip_conntrack_tcp_timeout_time_wait",
-               .data           = &tcp_timeouts[TCP_CONNTRACK_TIME_WAIT],
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
        },
        {
                .procname       = "ip_conntrack_tcp_timeout_close",
-               .data           = &tcp_timeouts[TCP_CONNTRACK_CLOSE],
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
        },
        {
                .procname       = "ip_conntrack_tcp_timeout_max_retrans",
-               .data           = &tcp_timeouts[TCP_CONNTRACK_RETRANS],
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
        },
        {
                .procname       = "ip_conntrack_tcp_loose",
-               .data           = &nf_ct_tcp_loose,
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec,
        },
        {
                .procname       = "ip_conntrack_tcp_be_liberal",
-               .data           = &nf_ct_tcp_be_liberal,
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec,
        },
        {
                .procname       = "ip_conntrack_tcp_max_retrans",
-               .data           = &nf_ct_tcp_max_retrans,
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec,
@@ -1550,6 +1533,101 @@ static struct ctl_table tcp_compat_sysctl_table[] = {
 #endif /* CONFIG_NF_CONNTRACK_PROC_COMPAT */
 #endif /* CONFIG_SYSCTL */
 
+static int tcp_kmemdup_sysctl_table(struct nf_proto_net *pn,
+                                   struct nf_tcp_net *tn)
+{
+#ifdef CONFIG_SYSCTL
+       if (pn->ctl_table)
+               return 0;
+
+       pn->ctl_table = kmemdup(tcp_sysctl_table,
+                               sizeof(tcp_sysctl_table),
+                               GFP_KERNEL);
+       if (!pn->ctl_table)
+               return -ENOMEM;
+
+       pn->ctl_table[0].data = &tn->timeouts[TCP_CONNTRACK_SYN_SENT];
+       pn->ctl_table[1].data = &tn->timeouts[TCP_CONNTRACK_SYN_RECV];
+       pn->ctl_table[2].data = &tn->timeouts[TCP_CONNTRACK_ESTABLISHED];
+       pn->ctl_table[3].data = &tn->timeouts[TCP_CONNTRACK_FIN_WAIT];
+       pn->ctl_table[4].data = &tn->timeouts[TCP_CONNTRACK_CLOSE_WAIT];
+       pn->ctl_table[5].data = &tn->timeouts[TCP_CONNTRACK_LAST_ACK];
+       pn->ctl_table[6].data = &tn->timeouts[TCP_CONNTRACK_TIME_WAIT];
+       pn->ctl_table[7].data = &tn->timeouts[TCP_CONNTRACK_CLOSE];
+       pn->ctl_table[8].data = &tn->timeouts[TCP_CONNTRACK_RETRANS];
+       pn->ctl_table[9].data = &tn->timeouts[TCP_CONNTRACK_UNACK];
+       pn->ctl_table[10].data = &tn->tcp_loose;
+       pn->ctl_table[11].data = &tn->tcp_be_liberal;
+       pn->ctl_table[12].data = &tn->tcp_max_retrans;
+#endif
+       return 0;
+}
+
+static int tcp_kmemdup_compat_sysctl_table(struct nf_proto_net *pn,
+                                          struct nf_tcp_net *tn)
+{
+#ifdef CONFIG_SYSCTL
+#ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT
+       pn->ctl_compat_table = kmemdup(tcp_compat_sysctl_table,
+                                      sizeof(tcp_compat_sysctl_table),
+                                      GFP_KERNEL);
+       if (!pn->ctl_compat_table)
+               return -ENOMEM;
+
+       pn->ctl_compat_table[0].data = &tn->timeouts[TCP_CONNTRACK_SYN_SENT];
+       pn->ctl_compat_table[1].data = &tn->timeouts[TCP_CONNTRACK_SYN_SENT2];
+       pn->ctl_compat_table[2].data = &tn->timeouts[TCP_CONNTRACK_SYN_RECV];
+       pn->ctl_compat_table[3].data = &tn->timeouts[TCP_CONNTRACK_ESTABLISHED];
+       pn->ctl_compat_table[4].data = &tn->timeouts[TCP_CONNTRACK_FIN_WAIT];
+       pn->ctl_compat_table[5].data = &tn->timeouts[TCP_CONNTRACK_CLOSE_WAIT];
+       pn->ctl_compat_table[6].data = &tn->timeouts[TCP_CONNTRACK_LAST_ACK];
+       pn->ctl_compat_table[7].data = &tn->timeouts[TCP_CONNTRACK_TIME_WAIT];
+       pn->ctl_compat_table[8].data = &tn->timeouts[TCP_CONNTRACK_CLOSE];
+       pn->ctl_compat_table[9].data = &tn->timeouts[TCP_CONNTRACK_RETRANS];
+       pn->ctl_compat_table[10].data = &tn->tcp_loose;
+       pn->ctl_compat_table[11].data = &tn->tcp_be_liberal;
+       pn->ctl_compat_table[12].data = &tn->tcp_max_retrans;
+#endif
+#endif
+       return 0;
+}
+
+static int tcp_init_net(struct net *net, u_int16_t proto)
+{
+       int ret;
+       struct nf_tcp_net *tn = tcp_pernet(net);
+       struct nf_proto_net *pn = &tn->pn;
+
+       if (!pn->users) {
+               int i;
+
+               for (i = 0; i < TCP_CONNTRACK_TIMEOUT_MAX; i++)
+                       tn->timeouts[i] = tcp_timeouts[i];
+
+               tn->tcp_loose = nf_ct_tcp_loose;
+               tn->tcp_be_liberal = nf_ct_tcp_be_liberal;
+               tn->tcp_max_retrans = nf_ct_tcp_max_retrans;
+       }
+
+       if (proto == AF_INET) {
+               ret = tcp_kmemdup_compat_sysctl_table(pn, tn);
+               if (ret < 0)
+                       return ret;
+
+               ret = tcp_kmemdup_sysctl_table(pn, tn);
+               if (ret < 0)
+                       nf_ct_kfree_compat_sysctl_table(pn);
+       } else
+               ret = tcp_kmemdup_sysctl_table(pn, tn);
+
+       return ret;
+}
+
+static struct nf_proto_net *tcp_get_net_proto(struct net *net)
+{
+       return &net->ct.nf_ct_proto.tcp.pn;
+}
+
 struct nf_conntrack_l4proto nf_conntrack_l4proto_tcp4 __read_mostly =
 {
        .l3proto                = PF_INET,
@@ -1582,14 +1660,8 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_tcp4 __read_mostly =
                .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,
-       .ctl_table              = tcp_sysctl_table,
-#ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT
-       .ctl_compat_table       = tcp_compat_sysctl_table,
-#endif
-#endif
+       .init_net               = tcp_init_net,
+       .get_net_proto          = tcp_get_net_proto,
 };
 EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_tcp4);
 
@@ -1625,10 +1697,7 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_tcp6 __read_mostly =
                .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,
-       .ctl_table              = tcp_sysctl_table,
-#endif
+       .init_net               = tcp_init_net,
+       .get_net_proto          = tcp_get_net_proto,
 };
 EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_tcp6);
This page took 0.044581 seconds and 5 git commands to generate.