[NETFILTER]: tcp conntrack: do liberal tracking for picked up connections
authorPatrick McHardy <kaber@trash.net>
Wed, 7 Feb 2007 23:05:33 +0000 (15:05 -0800)
committerDavid S. Miller <davem@sunset.davemloft.net>
Thu, 8 Feb 2007 20:39:10 +0000 (12:39 -0800)
Do liberal tracking (only RSTs need to be in-window) for connections picked
up without seeing a SYN to deal with window scaling. Also change logging
of invalid packets not to log packets accepted by liberal tracking to avoid
spamming the logs.

Based on suggestion from James Ralston <ralston@pobox.com>

Signed-off-by: Patrick McHardy <kaber@trash.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
include/linux/netfilter/nf_conntrack_tcp.h
net/ipv4/netfilter/ip_conntrack_proto_tcp.c
net/netfilter/nf_conntrack_proto_tcp.c

index 2f4e98b90cc0d0849f9bf2489cc5ddd183a3fa58..007af4c2770b70dd004ebe51403ae90fc93e9097 100644 (file)
@@ -27,6 +27,9 @@ enum tcp_conntrack {
 /* This sender sent FIN first */
 #define IP_CT_TCP_FLAG_CLOSE_INIT              0x04
 
+/* Be liberal in window checking */
+#define IP_CT_TCP_FLAG_BE_LIBERAL              0x08
+
 #ifdef __KERNEL__
 
 struct ip_ct_tcp_state {
@@ -34,7 +37,6 @@ struct ip_ct_tcp_state {
        u_int32_t       td_maxend;      /* max of ack + max(win, 1) */
        u_int32_t       td_maxwin;      /* max(win) */
        u_int8_t        td_scale;       /* window scale factor */
-       u_int8_t        loose;          /* used when connection picked up from the middle */
        u_int8_t        flags;          /* per direction options */
 };
 
index 06e4e8a6dd9f88db85452c556d51058025db3dde..c34f48fe547875e5bb48f9552526dd257eb79cfb 100644 (file)
@@ -50,12 +50,9 @@ static DEFINE_RWLOCK(tcp_lock);
     If it's non-zero, we mark only out of window RST segments as INVALID. */
 int ip_ct_tcp_be_liberal __read_mostly = 0;
 
-/* When connection is picked up from the middle, how many packets are required
-   to pass in each direction when we assume we are in sync - if any side uses
-   window scaling, we lost the game. 
-   If it is set to zero, we disable picking up already established 
+/* If it is set to zero, we disable picking up already established
    connections. */
-int ip_ct_tcp_loose __read_mostly = 3;
+int ip_ct_tcp_loose __read_mostly = 1;
 
 /* Max number of the retransmitted packets without receiving an (acceptable) 
    ACK from the destination. If this number is reached, a shorter timer 
@@ -694,11 +691,10 @@ static int tcp_in_window(struct ip_ct_tcp *state,
                before(sack, receiver->td_end + 1),
                after(ack, receiver->td_end - MAXACKWINDOW(sender)));
        
-       if (sender->loose || receiver->loose ||
-           (before(seq, sender->td_maxend + 1) &&
-            after(end, sender->td_end - receiver->td_maxwin - 1) &&
-            before(sack, receiver->td_end + 1) &&
-            after(ack, receiver->td_end - MAXACKWINDOW(sender)))) {
+       if (before(seq, sender->td_maxend + 1) &&
+           after(end, sender->td_end - receiver->td_maxwin - 1) &&
+           before(sack, receiver->td_end + 1) &&
+           after(ack, receiver->td_end - MAXACKWINDOW(sender))) {
                /*
                 * Take into account window scaling (RFC 1323).
                 */
@@ -743,15 +739,13 @@ static int tcp_in_window(struct ip_ct_tcp *state,
                                state->retrans = 0;
                        }
                }
-               /*
-                * Close the window of disabled window tracking :-)
-                */
-               if (sender->loose)
-                       sender->loose--;
-               
                res = 1;
        } else {
-               if (LOG_INVALID(IPPROTO_TCP))
+               res = 0;
+               if (sender->flags & IP_CT_TCP_FLAG_BE_LIBERAL ||
+                   ip_ct_tcp_be_liberal)
+                       res = 1;
+               if (!res && LOG_INVALID(IPPROTO_TCP))
                        nf_log_packet(PF_INET, 0, skb, NULL, NULL, NULL,
                        "ip_ct_tcp: %s ",
                        before(seq, sender->td_maxend + 1) ?
@@ -762,8 +756,6 @@ static int tcp_in_window(struct ip_ct_tcp *state,
                        : "ACK is over the upper bound (ACKed data not seen yet)"
                        : "SEQ is under the lower bound (already ACKed data retransmitted)"
                        : "SEQ is over the upper bound (over the window of the receiver)");
-
-               res = ip_ct_tcp_be_liberal;
        }
   
        DEBUGP("tcp_in_window: res=%i sender end=%u maxend=%u maxwin=%u "
@@ -1105,8 +1097,6 @@ static int tcp_new(struct ip_conntrack *conntrack,
 
                tcp_options(skb, iph, th, &conntrack->proto.tcp.seen[0]);
                conntrack->proto.tcp.seen[1].flags = 0;
-               conntrack->proto.tcp.seen[0].loose = 
-               conntrack->proto.tcp.seen[1].loose = 0;
        } else if (ip_ct_tcp_loose == 0) {
                /* Don't try to pick up connections. */
                return 0;
@@ -1127,11 +1117,11 @@ static int tcp_new(struct ip_conntrack *conntrack,
                        conntrack->proto.tcp.seen[0].td_maxwin;
                conntrack->proto.tcp.seen[0].td_scale = 0;
 
-               /* We assume SACK. Should we assume window scaling too? */
+               /* We assume SACK and liberal window checking to handle
+                * window scaling */
                conntrack->proto.tcp.seen[0].flags =
-               conntrack->proto.tcp.seen[1].flags = IP_CT_TCP_FLAG_SACK_PERM;
-               conntrack->proto.tcp.seen[0].loose = 
-               conntrack->proto.tcp.seen[1].loose = ip_ct_tcp_loose;
+               conntrack->proto.tcp.seen[1].flags = IP_CT_TCP_FLAG_SACK_PERM |
+                                                    IP_CT_TCP_FLAG_BE_LIBERAL;
        }
     
        conntrack->proto.tcp.seen[1].td_end = 0;
index 626b0011dd8955ee950bd8bc675eb53392a3317b..6fccdcf43e08a0e2738b8060b1d98f2f89e6f2d8 100644 (file)
@@ -60,12 +60,9 @@ static DEFINE_RWLOCK(tcp_lock);
     If it's non-zero, we mark only out of window RST segments as INVALID. */
 int nf_ct_tcp_be_liberal __read_mostly = 0;
 
-/* When connection is picked up from the middle, how many packets are required
-   to pass in each direction when we assume we are in sync - if any side uses
-   window scaling, we lost the game. 
-   If it is set to zero, we disable picking up already established 
+/* If it is set to zero, we disable picking up already established
    connections. */
-int nf_ct_tcp_loose __read_mostly = 3;
+int nf_ct_tcp_loose __read_mostly = 1;
 
 /* Max number of the retransmitted packets without receiving an (acceptable) 
    ACK from the destination. If this number is reached, a shorter timer 
@@ -650,11 +647,10 @@ static int tcp_in_window(struct ip_ct_tcp *state,
                before(sack, receiver->td_end + 1),
                after(ack, receiver->td_end - MAXACKWINDOW(sender)));
 
-       if (sender->loose || receiver->loose ||
-           (before(seq, sender->td_maxend + 1) &&
-            after(end, sender->td_end - receiver->td_maxwin - 1) &&
-            before(sack, receiver->td_end + 1) &&
-            after(ack, receiver->td_end - MAXACKWINDOW(sender)))) {
+       if (before(seq, sender->td_maxend + 1) &&
+           after(end, sender->td_end - receiver->td_maxwin - 1) &&
+           before(sack, receiver->td_end + 1) &&
+           after(ack, receiver->td_end - MAXACKWINDOW(sender))) {
                /*
                 * Take into account window scaling (RFC 1323).
                 */
@@ -699,15 +695,13 @@ static int tcp_in_window(struct ip_ct_tcp *state,
                                state->retrans = 0;
                        }
                }
-               /*
-                * Close the window of disabled window tracking :-)
-                */
-               if (sender->loose)
-                       sender->loose--;
-
                res = 1;
        } else {
-               if (LOG_INVALID(IPPROTO_TCP))
+               res = 0;
+               if (sender->flags & IP_CT_TCP_FLAG_BE_LIBERAL ||
+                   nf_ct_tcp_be_liberal)
+                       res = 1;
+               if (!res && LOG_INVALID(IPPROTO_TCP))
                        nf_log_packet(pf, 0, skb, NULL, NULL, NULL,
                        "nf_ct_tcp: %s ",
                        before(seq, sender->td_maxend + 1) ?
@@ -718,8 +712,6 @@ static int tcp_in_window(struct ip_ct_tcp *state,
                        : "ACK is over the upper bound (ACKed data not seen yet)"
                        : "SEQ is under the lower bound (already ACKed data retransmitted)"
                        : "SEQ is over the upper bound (over the window of the receiver)");
-
-               res = nf_ct_tcp_be_liberal;
        }
   
        DEBUGP("tcp_in_window: res=%i sender end=%u maxend=%u maxwin=%u "
@@ -1063,8 +1055,6 @@ static int tcp_new(struct nf_conn *conntrack,
 
                tcp_options(skb, dataoff, th, &conntrack->proto.tcp.seen[0]);
                conntrack->proto.tcp.seen[1].flags = 0;
-               conntrack->proto.tcp.seen[0].loose = 
-               conntrack->proto.tcp.seen[1].loose = 0;
        } else if (nf_ct_tcp_loose == 0) {
                /* Don't try to pick up connections. */
                return 0;
@@ -1085,11 +1075,11 @@ static int tcp_new(struct nf_conn *conntrack,
                        conntrack->proto.tcp.seen[0].td_maxwin;
                conntrack->proto.tcp.seen[0].td_scale = 0;
 
-               /* We assume SACK. Should we assume window scaling too? */
+               /* We assume SACK and liberal window checking to handle
+                * window scaling */
                conntrack->proto.tcp.seen[0].flags =
-               conntrack->proto.tcp.seen[1].flags = IP_CT_TCP_FLAG_SACK_PERM;
-               conntrack->proto.tcp.seen[0].loose = 
-               conntrack->proto.tcp.seen[1].loose = nf_ct_tcp_loose;
+               conntrack->proto.tcp.seen[1].flags = IP_CT_TCP_FLAG_SACK_PERM |
+                                                    IP_CT_TCP_FLAG_BE_LIBERAL;
        }
     
        conntrack->proto.tcp.seen[1].td_end = 0;