]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - net/netfilter/nf_conntrack_proto_tcp.c
Merge branch 'r6040' of git://git.kernel.org/pub/scm/linux/kernel/git/romieu/netdev...
[linux-2.6-omap-h63xx.git] / net / netfilter / nf_conntrack_proto_tcp.c
index 9807af677a564d6265b5f663f404cb87978b0ed2..202d7fa09483841ac91143f1d1c53dab9d6a6d50 100644 (file)
@@ -46,7 +46,7 @@ static int nf_ct_tcp_max_retrans __read_mostly = 3;
   /* FIXME: Examine ipfilter's timeouts and conntrack transitions more
      closely.  They're more complex. --RR */
 
-static const char *tcp_conntrack_names[] = {
+static const char *const tcp_conntrack_names[] = {
        "NONE",
        "SYN_SENT",
        "SYN_RECV",
@@ -125,7 +125,7 @@ enum tcp_bit_set {
  * CLOSE_WAIT: ACK seen (after FIN)
  * LAST_ACK:   FIN seen (after FIN)
  * TIME_WAIT:  last ACK seen
- * CLOSE:      closed connection
+ * CLOSE:      closed connection (RST)
  *
  * LISTEN state is not used.
  *
@@ -261,7 +261,8 @@ static int tcp_pkt_to_tuple(const struct sk_buff *skb,
                            unsigned int dataoff,
                            struct nf_conntrack_tuple *tuple)
 {
-       struct tcphdr _hdr, *hp;
+       const struct tcphdr *hp;
+       struct tcphdr _hdr;
 
        /* Actually only need first 8 bytes. */
        hp = skb_header_pointer(skb, dataoff, 8, &_hdr);
@@ -343,7 +344,7 @@ static unsigned int get_conntrack_index(const struct tcphdr *tcph)
 static inline __u32 segment_seq_plus_len(__u32 seq,
                                         size_t len,
                                         unsigned int dataoff,
-                                        struct tcphdr *tcph)
+                                        const struct tcphdr *tcph)
 {
        /* XXX Should I use payload length field in IP/IPv6 header ?
         * - YK */
@@ -362,11 +363,11 @@ static inline __u32 segment_seq_plus_len(__u32 seq,
  */
 static void tcp_options(const struct sk_buff *skb,
                        unsigned int dataoff,
-                       struct tcphdr *tcph,
+                       const struct tcphdr *tcph,
                        struct ip_ct_tcp_state *state)
 {
        unsigned char buff[(15 * 4) - sizeof(struct tcphdr)];
-       unsigned char *ptr;
+       const unsigned char *ptr;
        int length = (tcph->doff*4) - sizeof(struct tcphdr);
 
        if (!length)
@@ -417,10 +418,10 @@ static void tcp_options(const struct sk_buff *skb,
 }
 
 static void tcp_sack(const struct sk_buff *skb, unsigned int dataoff,
-                    struct tcphdr *tcph, __u32 *sack)
+                     const struct tcphdr *tcph, __u32 *sack)
 {
        unsigned char buff[(15 * 4) - sizeof(struct tcphdr)];
-       unsigned char *ptr;
+       const unsigned char *ptr;
        int length = (tcph->doff*4) - sizeof(struct tcphdr);
        __u32 tmp;
 
@@ -477,18 +478,18 @@ static void tcp_sack(const struct sk_buff *skb, unsigned int dataoff,
        }
 }
 
-static int tcp_in_window(struct nf_conn *ct,
+static int tcp_in_window(const struct nf_conn *ct,
                         struct ip_ct_tcp *state,
                         enum ip_conntrack_dir dir,
                         unsigned int index,
                         const struct sk_buff *skb,
                         unsigned int dataoff,
-                        struct tcphdr *tcph,
+                        const struct tcphdr *tcph,
                         int pf)
 {
        struct ip_ct_tcp_state *sender = &state->seen[dir];
        struct ip_ct_tcp_state *receiver = &state->seen[!dir];
-       struct nf_conntrack_tuple *tuple = &ct->tuplehash[dir].tuple;
+       const struct nf_conntrack_tuple *tuple = &ct->tuplehash[dir].tuple;
        __u32 seq, ack, sack, end, win, swin;
        int res;
 
@@ -686,14 +687,14 @@ static int tcp_in_window(struct nf_conn *ct,
 #ifdef CONFIG_NF_NAT_NEEDED
 /* Update sender->td_end after NAT successfully mangled the packet */
 /* Caller must linearize skb at tcp header. */
-void nf_conntrack_tcp_update(struct sk_buff *skb,
+void nf_conntrack_tcp_update(const struct sk_buff *skb,
                             unsigned int dataoff,
                             struct nf_conn *ct,
                             int dir)
 {
-       struct tcphdr *tcph = (void *)skb->data + dataoff;
-       struct ip_ct_tcp_state *sender = &ct->proto.tcp.seen[dir];
-       struct ip_ct_tcp_state *receiver = &ct->proto.tcp.seen[!dir];
+       const struct tcphdr *tcph = (const void *)skb->data + dataoff;
+       const struct ip_ct_tcp_state *sender = &ct->proto.tcp.seen[dir];
+       const struct ip_ct_tcp_state *receiver = &ct->proto.tcp.seen[!dir];
        __u32 end;
 
        end = segment_seq_plus_len(ntohl(tcph->seq), skb->len, dataoff, tcph);
@@ -726,7 +727,7 @@ EXPORT_SYMBOL_GPL(nf_conntrack_tcp_update);
 #define        TH_CWR  0x80
 
 /* table of valid flag combinations - PUSH, ECE and CWR are always valid */
-static u8 tcp_valid_flags[(TH_FIN|TH_SYN|TH_RST|TH_ACK|TH_URG) + 1] =
+static const u8 tcp_valid_flags[(TH_FIN|TH_SYN|TH_RST|TH_ACK|TH_URG) + 1] =
 {
        [TH_SYN]                        = 1,
        [TH_SYN|TH_URG]                 = 1,
@@ -746,7 +747,8 @@ static int tcp_error(struct sk_buff *skb,
                     int pf,
                     unsigned int hooknum)
 {
-       struct tcphdr _tcph, *th;
+       const struct tcphdr *th;
+       struct tcphdr _tcph;
        unsigned int tcplen = skb->len - dataoff;
        u_int8_t tcpflags;
 
@@ -803,7 +805,8 @@ static int tcp_packet(struct nf_conn *ct,
        struct nf_conntrack_tuple *tuple;
        enum tcp_conntrack new_state, old_state;
        enum ip_conntrack_dir dir;
-       struct tcphdr *th, _tcph;
+       const struct tcphdr *th;
+       struct tcphdr _tcph;
        unsigned long timeout;
        unsigned int index;
 
@@ -821,7 +824,21 @@ static int tcp_packet(struct nf_conn *ct,
        case TCP_CONNTRACK_SYN_SENT:
                if (old_state < TCP_CONNTRACK_TIME_WAIT)
                        break;
-               if ((ct->proto.tcp.seen[!dir].flags & IP_CT_TCP_FLAG_CLOSE_INIT)
+               /* RFC 1122: "When a connection is closed actively,
+                * it MUST linger in TIME-WAIT state for a time 2xMSL
+                * (Maximum Segment Lifetime). However, it MAY accept
+                * a new SYN from the remote TCP to reopen the connection
+                * directly from TIME-WAIT state, if..."
+                * We ignore the conditions because we are in the
+                * TIME-WAIT state anyway.
+                *
+                * Handle aborted connections: we and the server
+                * think there is an existing connection but the client
+                * aborts it and starts a new one.
+                */
+               if (((ct->proto.tcp.seen[dir].flags
+                     | ct->proto.tcp.seen[!dir].flags)
+                    & IP_CT_TCP_FLAG_CLOSE_INIT)
                    || (ct->proto.tcp.last_dir == dir
                        && ct->proto.tcp.last_index == TCP_RST_SET)) {
                        /* Attempt to reopen a closed/aborted connection.
@@ -834,16 +851,23 @@ static int tcp_packet(struct nf_conn *ct,
                /* Fall through */
        case TCP_CONNTRACK_IGNORE:
                /* Ignored packets:
+                *
+                * Our connection entry may be out of sync, so ignore
+                * packets which may signal the real connection between
+                * the client and the server.
                 *
                 * a) SYN in ORIGINAL
                 * b) SYN/ACK in REPLY
                 * c) ACK in reply direction after initial SYN in original.
+                *
+                * If the ignored packet is invalid, the receiver will send
+                * a RST we'll catch below.
                 */
                if (index == TCP_SYNACK_SET
                    && ct->proto.tcp.last_index == TCP_SYN_SET
                    && ct->proto.tcp.last_dir != dir
                    && ntohl(th->ack_seq) == ct->proto.tcp.last_end) {
-                       /* This SYN/ACK acknowledges a SYN that we earlier
+                       /* 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
@@ -867,7 +891,7 @@ static int tcp_packet(struct nf_conn *ct,
                write_unlock_bh(&tcp_lock);
                if (LOG_INVALID(IPPROTO_TCP))
                        nf_log_packet(pf, 0, skb, NULL, NULL, NULL,
-                                 "nf_ct_tcp: invalid packed ignored ");
+                                 "nf_ct_tcp: invalid packet ignored ");
                return NF_ACCEPT;
        case TCP_CONNTRACK_MAX:
                /* Invalid packet */
@@ -921,8 +945,7 @@ static int tcp_packet(struct nf_conn *ct,
 
        ct->proto.tcp.state = new_state;
        if (old_state != new_state
-           && (new_state == TCP_CONNTRACK_FIN_WAIT
-               || new_state == TCP_CONNTRACK_CLOSE))
+           && new_state == TCP_CONNTRACK_CLOSE)
                ct->proto.tcp.seen[dir].flags |= IP_CT_TCP_FLAG_CLOSE_INIT;
        timeout = ct->proto.tcp.retrans >= nf_ct_tcp_max_retrans
                  && tcp_timeouts[new_state] > nf_ct_tcp_timeout_max_retrans
@@ -964,9 +987,10 @@ static int tcp_new(struct nf_conn *ct,
                   unsigned int dataoff)
 {
        enum tcp_conntrack new_state;
-       struct tcphdr *th, _tcph;
-       struct ip_ct_tcp_state *sender = &ct->proto.tcp.seen[0];
-       struct ip_ct_tcp_state *receiver = &ct->proto.tcp.seen[1];
+       const struct tcphdr *th;
+       struct tcphdr _tcph;
+       const struct ip_ct_tcp_state *sender = &ct->proto.tcp.seen[0];
+       const struct ip_ct_tcp_state *receiver = &ct->proto.tcp.seen[1];
 
        th = skb_header_pointer(skb, dataoff, sizeof(_tcph), &_tcph);
        BUG_ON(th == NULL);