- patches.suse/slab-handle-memoryless-nodes-v2a.patch: Refresh.
[linux-flexiantxendom0-3.2.10.git] / net / netfilter / nf_conntrack_proto_tcp.c
index ba2b769..3c96437 100644 (file)
@@ -896,23 +896,54 @@ static int tcp_packet(struct nf_conn *ct,
                        /* b) This SYN/ACK acknowledges a SYN that we earlier
                         * ignored as invalid. This means that the client and
                         * the server are both in sync, while the firewall is
-                        * not. We kill this session and block the SYN/ACK so
-                        * that the client cannot but retransmit its SYN and
-                        * thus initiate a clean new session.
+                        * not. We get in sync from the previously annotated
+                        * values.
                         */
-                       spin_unlock_bh(&ct->lock);
-                       if (LOG_INVALID(net, IPPROTO_TCP))
-                               nf_log_packet(pf, 0, skb, NULL, NULL, NULL,
-                                         "nf_ct_tcp: killing out of sync session ");
-                       nf_ct_kill(ct);
-                       return NF_DROP;
+                       old_state = TCP_CONNTRACK_SYN_SENT;
+                       new_state = TCP_CONNTRACK_SYN_RECV;
+                       ct->proto.tcp.seen[ct->proto.tcp.last_dir].td_end =
+                               ct->proto.tcp.last_end;
+                       ct->proto.tcp.seen[ct->proto.tcp.last_dir].td_maxend =
+                               ct->proto.tcp.last_end;
+                       ct->proto.tcp.seen[ct->proto.tcp.last_dir].td_maxwin =
+                               ct->proto.tcp.last_win == 0 ?
+                                       1 : ct->proto.tcp.last_win;
+                       ct->proto.tcp.seen[ct->proto.tcp.last_dir].td_scale =
+                               ct->proto.tcp.last_wscale;
+                       ct->proto.tcp.seen[ct->proto.tcp.last_dir].flags =
+                               ct->proto.tcp.last_flags;
+                       memset(&ct->proto.tcp.seen[dir], 0,
+                              sizeof(struct ip_ct_tcp_state));
+                       break;
                }
                ct->proto.tcp.last_index = index;
                ct->proto.tcp.last_dir = dir;
                ct->proto.tcp.last_seq = ntohl(th->seq);
                ct->proto.tcp.last_end =
                    segment_seq_plus_len(ntohl(th->seq), skb->len, dataoff, th);
-
+               ct->proto.tcp.last_win = ntohs(th->window);
+
+               /* a) This is a SYN in ORIGINAL. The client and the server
+                * may be in sync but we are not. In that case, we annotate
+                * the TCP options and let the packet go through. If it is a
+                * valid SYN packet, the server will reply with a SYN/ACK, and
+                * then we'll get in sync. Otherwise, the server ignores it. */
+               if (index == TCP_SYN_SET && dir == IP_CT_DIR_ORIGINAL) {
+                       struct ip_ct_tcp_state seen = {};
+
+                       ct->proto.tcp.last_flags =
+                       ct->proto.tcp.last_wscale = 0;
+                       tcp_options(skb, dataoff, th, &seen);
+                       if (seen.flags & IP_CT_TCP_FLAG_WINDOW_SCALE) {
+                               ct->proto.tcp.last_flags |=
+                                       IP_CT_TCP_FLAG_WINDOW_SCALE;
+                               ct->proto.tcp.last_wscale = seen.td_scale;
+                       }
+                       if (seen.flags & IP_CT_TCP_FLAG_SACK_PERM) {
+                               ct->proto.tcp.last_flags |=
+                                       IP_CT_TCP_FLAG_SACK_PERM;
+                       }
+               }
                spin_unlock_bh(&ct->lock);
                if (LOG_INVALID(net, IPPROTO_TCP))
                        nf_log_packet(pf, 0, skb, NULL, NULL, NULL,
@@ -1291,7 +1322,6 @@ static struct ctl_table tcp_sysctl_table[] = {
                .proc_handler   = proc_dointvec_jiffies,
        },
        {
-               .ctl_name       = NET_NF_CONNTRACK_TCP_LOOSE,
                .procname       = "nf_conntrack_tcp_loose",
                .data           = &nf_ct_tcp_loose,
                .maxlen         = sizeof(unsigned int),
@@ -1299,7 +1329,6 @@ static struct ctl_table tcp_sysctl_table[] = {
                .proc_handler   = proc_dointvec,
        },
        {
-               .ctl_name       = NET_NF_CONNTRACK_TCP_BE_LIBERAL,
                .procname       = "nf_conntrack_tcp_be_liberal",
                .data           = &nf_ct_tcp_be_liberal,
                .maxlen         = sizeof(unsigned int),
@@ -1307,16 +1336,13 @@ static struct ctl_table tcp_sysctl_table[] = {
                .proc_handler   = proc_dointvec,
        },
        {
-               .ctl_name       = NET_NF_CONNTRACK_TCP_MAX_RETRANS,
                .procname       = "nf_conntrack_tcp_max_retrans",
                .data           = &nf_ct_tcp_max_retrans,
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec,
        },
-       {
-               .ctl_name       = 0
-       }
+       { }
 };
 
 #ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT
@@ -1392,7 +1418,6 @@ static struct ctl_table tcp_compat_sysctl_table[] = {
                .proc_handler   = proc_dointvec_jiffies,
        },
        {
-               .ctl_name       = NET_IPV4_NF_CONNTRACK_TCP_LOOSE,
                .procname       = "ip_conntrack_tcp_loose",
                .data           = &nf_ct_tcp_loose,
                .maxlen         = sizeof(unsigned int),
@@ -1400,7 +1425,6 @@ static struct ctl_table tcp_compat_sysctl_table[] = {
                .proc_handler   = proc_dointvec,
        },
        {
-               .ctl_name       = NET_IPV4_NF_CONNTRACK_TCP_BE_LIBERAL,
                .procname       = "ip_conntrack_tcp_be_liberal",
                .data           = &nf_ct_tcp_be_liberal,
                .maxlen         = sizeof(unsigned int),
@@ -1408,16 +1432,13 @@ static struct ctl_table tcp_compat_sysctl_table[] = {
                .proc_handler   = proc_dointvec,
        },
        {
-               .ctl_name       = NET_IPV4_NF_CONNTRACK_TCP_MAX_RETRANS,
                .procname       = "ip_conntrack_tcp_max_retrans",
                .data           = &nf_ct_tcp_max_retrans,
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec,
        },
-       {
-               .ctl_name       = 0
-       }
+       { }
 };
 #endif /* CONFIG_NF_CONNTRACK_PROC_COMPAT */
 #endif /* CONFIG_SYSCTL */