improve netfilter against DOS

diff -upr linux-2.6.17.8/include/linux/netfilter/nf_conntrack_tcp.h msyn-linux-2.6.17.8/include/linux/netfilter/nf_conntrack_tcp.h
--- linux-2.6.17.8/include/linux/netfilter/nf_conntrack_tcp.h        2006-08-07 12:18:54.000000000 +0800
+++ msyn-linux-2.6.17.8/include/linux/netfilter/nf_conntrack_tcp.h        2007-04-09 15:06:47.000000000 +0800
@@ -36,6 +36,7 @@ struct ip_ct_tcp_state {
        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 */
+        u_int8_t        dummy;
};

struct ip_ct_tcp
@@ -49,6 +50,8 @@ struct ip_ct_tcp
        u_int32_t        last_seq;        /* Last sequence number seen in dir */
        u_int32_t        last_ack;        /* Last sequence number seen in opposite dir */
        u_int32_t        last_end;        /* Last seq + len */
+        u_int32_t        aseq;
+        u_int32_t        pseq;
};

#endif /* __KERNEL__ */
diff -upr linux-2.6.17.8/include/linux/netfilter_ipv4/ip_conntrack.h msyn-linux-2.6.17.8/include/linux/netfilter_ipv4/ip_conntrack.h
--- linux-2.6.17.8/include/linux/netfilter_ipv4/ip_conntrack.h        2006-08-07 12:18:54.000000000 +0800
+++ msyn-linux-2.6.17.8/include/linux/netfilter_ipv4/ip_conntrack.h        2007-04-29 15:23:07.000000000 +0800
@@ -81,6 +81,10 @@ struct ip_conntrack

        /* Have we seen traffic both ways yet? (bitset) */
        unsigned long status;
+       
+        unsigned long cookie;
+#define IPCT_COOKIE        0x00001000        /* cookie ct */
+#define IPCT_HOCONT        0x00000010        /* half-open-cnt ct */

        /* Timer function; drops refcnt when it goes off. */
        struct timer_list timeout;
@@ -287,6 +291,10 @@ static inline int is_confirmed(struct ip
        return test_bit(IPS_CONFIRMED_BIT, &ct->status);
}

+extern int nr_ho;
+//extern int cfg_nic_ok(struct sk_buff *);
+extern int sysctl_nt_syn_cookie[4];
+
static inline int is_dying(struct ip_conntrack *ct)
{
        return test_bit(IPS_DYING_BIT, &ct->status);
diff -upr linux-2.6.17.8/include/linux/netfilter_ipv4/ip_conntrack_tuple.h msyn-linux-2.6.17.8/include/linux/netfilter_ipv4/ip_conntrack_tuple.h
--- linux-2.6.17.8/include/linux/netfilter_ipv4/ip_conntrack_tuple.h        2006-08-07 12:18:54.000000000 +0800
+++ msyn-linux-2.6.17.8/include/linux/netfilter_ipv4/ip_conntrack_tuple.h        2007-04-09 15:09:11.000000000 +0800
@@ -47,7 +47,7 @@ struct ip_conntrack_manip
struct ip_conntrack_tuple
{
        struct ip_conntrack_manip src;
-
+       
        /* These are the parts of the tuple which are fixed. */
        struct {
                u_int32_t ip;
diff -upr linux-2.6.17.8/include/linux/skbuff.h msyn-linux-2.6.17.8/include/linux/skbuff.h
--- linux-2.6.17.8/include/linux/skbuff.h        2006-08-07 12:18:54.000000000 +0800
+++ msyn-linux-2.6.17.8/include/linux/skbuff.h        2007-04-03 11:51:08.000000000 +0800
@@ -89,6 +89,7 @@ struct net_device;
struct nf_conntrack {
        atomic_t use;
        void (*destroy)(struct nf_conntrack *);
+        unsigned long dummy, cook2;
};

#ifdef CONFIG_BRIDGE_NETFILTER
diff -upr linux-2.6.17.8/net/ipv4/netfilter/ip_conntrack_core.c msyn-linux-2.6.17.8/net/ipv4/netfilter/ip_conntrack_core.c
--- linux-2.6.17.8/net/ipv4/netfilter/ip_conntrack_core.c        2006-08-07 12:18:54.000000000 +0800
+++ msyn-linux-2.6.17.8/net/ipv4/netfilter/ip_conntrack_core.c        2007-04-29 15:23:38.000000000 +0800
@@ -21,6 +21,7 @@
#include <linux/types.h>
#include <linux/icmp.h>
#include <linux/ip.h>
+#include <linux/tcp.h>
#include <linux/netfilter.h>
#include <linux/netfilter_ipv4.h>
#include <linux/module.h>
@@ -69,6 +70,8 @@ struct ip_conntrack_protocol *ip_ct_prot
static LIST_HEAD(helpers);
unsigned int ip_conntrack_htable_size = 0;
int ip_conntrack_max;
+int sysctl_nt_syn_cookie[4] = { 8192, 128, 0, 0 };
+int nr_ho = 0;
struct list_head *ip_conntrack_hash;
static kmem_cache_t *ip_conntrack_cachep __read_mostly;
static kmem_cache_t *ip_conntrack_expect_cachep __read_mostly;
@@ -352,6 +355,13 @@ destroy_conntrack(struct nf_conntrack *n
                ip_conntrack_put(ct->master);

        DEBUGP("destroy_conntrack: returning ct=%p to slab/n", ct);
+        if (nfct->cook2) {
+                struct sk_buff * tmp =
+                (struct sk_buff *) nfct->cook2;
+                nfct->cook2 = 0;
+                atomic_dec(&(tmp->users));
+                kfree_skb(tmp);
+        }
        ip_conntrack_free(ct);
}

@@ -363,7 +373,13 @@ static void death_by_timeout(unsigned lo
        /* Inside lock so preempt is disabled on module removal path.
         * Otherwise we can get spurious warnings. */
        CONNTRACK_STAT_INC(delete_list);
-        clean_from_lists(ct);
+        clean_from_lists(ct);
+        if ((ct->cookie & IPCT_HOCONT)
+            && (ct->proto.tcp.state == TCP_CONNTRACK_SYN_SENT
+                || ct->proto.tcp.state == TCP_CONNTRACK_SYN_RECV))
+                --nr_ho;
+        if (nr_ho <0)
+                nr_ho = 0;
        write_unlock_bh(&ip_conntrack_lock);
        ip_conntrack_put(ct);
}
@@ -492,6 +508,9 @@ __ip_conntrack_confirm(struct sk_buff **
                set_bit(IPS_CONFIRMED_BIT, &ct->status);
                CONNTRACK_STAT_INC(insert);
                write_unlock_bh(&ip_conntrack_lock);
+                if ((ct->cookie & IPCT_HOCONT)
+                    && ct->proto.tcp.state == TCP_CONNTRACK_SYN_SENT)
+                        ++nr_ho;
                if (ct->helper)
                        ip_conntrack_event_cache(IPCT_HELPER, *pskb);
#ifdef CONFIG_IP_NF_NAT_NEEDED
@@ -503,8 +522,7 @@ __ip_conntrack_confirm(struct sk_buff **
                                         IPCT_RELATED : IPCT_NEW, *pskb);

                return NF_ACCEPT;
-        }
-
+        }
        CONNTRACK_STAT_INC(insert_failed);
        write_unlock_bh(&ip_conntrack_lock);

@@ -745,7 +763,192 @@ init_conntrack(struct ip_conntrack_tuple

        return &conntrack->tuplehash[IP_CT_DIR_ORIGINAL];
}
+static struct sk_buff * make_new_syn(struct sk_buff *);
+static void give_cookie_toc(struct sk_buff *);
+static int skb_is_cookie_ok(struct sk_buff *);
+static u32 make_cookie(struct sk_buff * , int);
+static int skb_is_syn_ack(struct sk_buff * , int);
+
+static struct sk_buff * make_new_syn (struct sk_buff * skbo)
+{
+        struct sk_buff * skb ;
+        struct tcphdr *th, *oth;
+        struct iphdr *iph, *oiph;
+        struct ethhdr *eth, *oeth;
+        unsigned int size = 20 + 28;
+       
+        size += (((skbo->nh.raw - skbo->mac.raw) +15) & ~15);
+        if ((skb = alloc_skb(size, GFP_ATOMIC)) == NULL)
+                return NULL;
+        skb_reserve(skb, size);
+
+        oeth = (struct ethhdr *)skbo->mac.raw;
+        oiph = skbo->nh.iph;
+        oth  = (void *)oiph + (oiph->ihl<<2) ;
+
+        th = (struct tcphdr *) skb_push(skb, 28);
+        memset(th, 0, 28);
+
+        th->source = oth->source;
+        th->dest   = oth->dest;
+
+        th->seq = htonl(ntohl(oth->seq) -1);
+
+        th->syn = 1;
+        th->doff = 28 >> 2;
+        th->window = oth->window ;
+        *(__be32 *)(th + 1) = htonl((2 << 24) | (4 << 16) | 1460);
+        th->check  = csum_tcpudp_magic(oiph->saddr, oiph->daddr,
+                                        skb->len, IPPROTO_TCP,
+                        csum_partial((char *)th, skb->len, 0));       
+
+        skb->nh.iph = iph = (struct iphdr *)skb_push(skb, 20);
+        memset(iph, 0, 20);
+
+        iph->version  = 4;
+        iph->ihl      = 5;
+        iph->ttl      = oiph->ttl;
+        iph->tos      = oiph->tos;
+        iph->protocol = oiph->protocol;
+        iph->id       = oiph->id ;
+
+        iph->daddr    = oiph->daddr;
+        iph->saddr    = oiph->saddr;
+
+        iph->tot_len  = htons(skb->len);
+        iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
+
+        size = skbo->nh.raw - skbo->mac.raw;
+        eth = (struct ethhdr *)skb_push(skb, size);
+        skb_pull(skb, size);
+        skb->mac.raw = (void *)eth;
+        memcpy(skb->mac.raw, skbo->mac.raw, size);
+        skb->protocol = skbo->protocol;
+        skb->pkt_type = skbo->pkt_type;
+        skb->dev = skbo->dev;
+        return skb;
+}
+static void give_cookie_toc (struct sk_buff * skbo)
+{
+        struct sk_buff * skb ;
+        struct tcphdr *th, *oth;
+        struct iphdr *iph, *oiph;
+        struct ethhdr *eth, *oeth;
+        unsigned int size = 20 + 28;
+       
+        size += (((skbo->nh.raw - skbo->mac.raw) +15) & ~15);
+        if ((skb = alloc_skb(size, GFP_ATOMIC)) == NULL)
+                return;
+        skb_reserve(skb, size);
+
+        oeth = (struct ethhdr *) skbo->mac.raw;
+        oiph = skbo->nh.iph;
+        oth  = (struct tcphdr *)((char *)oiph + (oiph->ihl<<2));
+
+        skb->h.th = th = (struct tcphdr *) skb_push(skb, 28);
+        memset(th, 0, 28);
+
+        th->source = oth->dest;
+        th->dest   = oth->source;
+       
+        th->ack_seq = htonl(ntohl(oth->seq) + 1);
+        th->seq     = htonl(make_cookie(skbo, 1));
+
+        th->syn = th->ack = 1;
+        th->doff = 28 >> 2;
+
+        th->window = htons(5840);
+        *(__be32 *)(th + 1) = htonl((2 << 24) | (4 << 16) | 1460);
+
+        th->check = csum_tcpudp_magic(oiph->daddr, oiph->saddr,
+                                        skb->len, IPPROTO_TCP,
+                        csum_partial((char *)th, skb->len, 0));       
+
+        skb->nh.iph = iph = (struct iphdr *)skb_push(skb, 20);
+        memset(iph, 0, 20);
+
+        iph->daddr    = oiph->saddr;
+        iph->saddr    = oiph->daddr;
+
+        iph->version  = 4;
+        iph->ihl      = 5;
+        iph->ttl      = 64;
+        iph->tos      = oiph->tos;
+        iph->protocol = oiph->protocol;
+        iph->id       = oiph->id ;
+
+        iph->tot_len  = htons(skb->len);
+        iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
+
+        size = skbo->nh.raw - skbo->mac.raw;
+        eth = (struct ethhdr *)skb_push(skb, size);
+        skb->mac.raw = (void *)eth;
+        memcpy(skb->mac.raw, skbo->mac.raw, size);
+        memcpy(eth->h_dest, oeth->h_source, ETH_ALEN);
+        memcpy(eth->h_source, oeth->h_dest, ETH_ALEN);
+
+        skb->protocol = skbo->protocol;
+        skb->dev = (skbo->dev->priv_flags & IFF_EBRIDGE) ?
+                    skbo->nf_bridge->physindev :
+                    skbo->input_dev;
+        dev_queue_xmit(skb);
+}
+static int skb_is_syn_ack (struct sk_buff * skb, int syn)
+{
+        struct iphdr * i = skb->nh.iph;
+        struct tcphdr * t =
+        (struct tcphdr *)((char *)i +(i->ihl<<2));
+
+        if ((syn ? (t->syn == 1 && t->ack == 0) :
+                   (t->syn == 0 && t->ack == 1))
+            && t->fin == 0 && t->rst == 0
+            && skb->len == 4*(i->ihl + t->doff))
+                return 1;
+        return 0;
+}
+static u32 make_cookie (struct sk_buff * skb, int is_syn)
+{
+        /*
+        * code granted by other guys,
+        * though simple and effective,
+        * no need to appreciate.
+        *
+        * and linux has other nicee codes,
+        * isnt it?
+        *
+        *
+        *
+        *
+        *
+        */
+}
+static int skb_is_cookie_ok (struct sk_buff * skb)
+{
+        struct iphdr * i = skb->nh.iph;
+        struct tcphdr * t =
+        (struct tcphdr *)((char *)i +(i->ihl<<2));

+        if (skb/*xxuglyx*/)
+                return 1;
+        return 0;
+}
+static int cfg_nic_ok(struct sk_buff * skb)
+{
+        int j, k;
+       
+        k = sizeof(sysctl_nt_syn_cookie) / sizeof(int);
+        for (j = 2; j < k; j++) {
+                if (sysctl_nt_syn_cookie[j] > 0 &&
+                    sysctl_nt_syn_cookie[j] == (
+#ifdef CONFIG_BRIDGE_NETFILTER
+                    skb->nf_bridge ?
+                    skb->nf_bridge->physindev->ifindex :
+#endif
+                    skb->input_dev->ifindex))
+                        return 1;
+        }
+        return 0;
+}
/* On success, returns conntrack ptr, sets skb->nfct and ctinfo */
static inline struct ip_conntrack *
resolve_normal_ct(struct sk_buff *skb,
@@ -758,6 +961,9 @@ resolve_normal_ct(struct sk_buff *skb,
        struct ip_conntrack_tuple_hash *h;
        struct ip_conntrack *ct;

+        static unsigned long cnt_ho, tstamp = 0;
+        unsigned long now;
+
        IP_NF_ASSERT((skb->nh.iph->frag_off & htons(IP_OFFSET)) == 0);

        if (!ip_ct_get_tuple(skb->nh.iph, skb, skb->nh.iph->ihl*4,
@@ -767,6 +973,48 @@ resolve_normal_ct(struct sk_buff *skb,
        /* look for tuple match */
        h = ip_conntrack_find_get(&tuple, NULL);
        if (!h) {
+#define cfg_anr  sysctl_nt_syn_cookie[0]
+#define cfg_snr  sysctl_nt_syn_cookie[1]
+
+                if (proto->proto == IPPROTO_TCP &&
+                    hooknum == NF_IP_PRE_ROUTING &&
+                    cfg_nic_ok(skb))
+                {
+                        if (cfg_anr < 0 || cfg_snr < 0) {
+        mixi:
+                                h = ERR_PTR(-601);
+                                return (void *)h;
+                        }
+                        tuple.dst.dir = 0;
+                        if (skb_is_syn_ack(skb, 1)) {
+                                int buk = 0;
+                               
+                                now = jiffies ;
+                                cnt_ho += (now - tstamp);
+                                tstamp = now;
+                                if (cnt_ho > HZ * cfg_snr)
+                                        cnt_ho = HZ * cfg_snr;
+                                if (cnt_ho >= HZ) {
+                                        cnt_ho -= HZ ;
+                                        buk = 1;
+                                }
+                                if (nr_ho < cfg_anr && buk) {
+                                        tuple.dst.dir = 4;
+                                        goto nook;
+                                }
+                                h = ERR_PTR(-600);
+                                return (void *)h;
+                        } else if (skb_is_syn_ack(skb, 0) &&
+                                   skb_is_cookie_ok(skb)) {
+                                tuple.dst.dir = 12;
+                                goto nook;
+                        } else
+                                goto mixi;
+                }
+#undef cfg_anr
+#undef cfg_snr
+
+        nook:
                h = init_conntrack(&tuple, proto, skb);
                if (!h)
                        return NULL;
@@ -801,7 +1049,24 @@ resolve_normal_ct(struct sk_buff *skb,
        skb->nfctinfo = *ctinfo;
        return ct;
}
-
+static void rechk_skb(struct tcphdr * th,
+                        enum ip_conntrack_dir dir,
+                        u_int32_t aseq, u_int32_t pseq)
+{
+        u32 diffs[2];
+       
+        if (!dir) {
+                diffs[0] = ~(th->ack_seq);
+                th->ack_seq = diffs[1] =
+                        htonl(ntohl(th->ack_seq) - pseq+aseq) ;
+        } else {
+                diffs[0] = ~(th->seq);
+                th->seq = diffs[1] =
+                        htonl(ntohl(th->seq) - aseq+pseq) ;
+        }
+        th->check = csum_fold(csum_partial((char *)diffs,
+                        sizeof(diffs), th->check^0xFFFF));
+}
/* Netfilter hook itself. */
unsigned int ip_conntrack_in(unsigned int hooknum,
                             struct sk_buff **pskb,
@@ -815,6 +1080,16 @@ unsigned int ip_conntrack_in(unsigned in
        int set_reply = 0;
        int ret;

+        u_int8_t old_state = 0;
+        enum ip_conntrack_dir dir;
+        struct iphdr *iph;
+        struct tcphdr *th;
+        unsigned int index;
+
+        int ala = 0;
+        int cry, br;
+        struct sk_buff *new_skb;
+
        /* Previously seen (loopback or untracked)?  Ignore. */
        if ((*pskb)->nfct) {
                CONNTRACK_STAT_INC(ignore);
@@ -856,21 +1131,103 @@ unsigned int ip_conntrack_in(unsigned in
                CONNTRACK_STAT_INC(invalid);
                return -ret;
        }
-
-        if (!(ct = resolve_normal_ct(*pskb, proto,&set_reply,hooknum,&ctinfo))) {
+        if (!(ct = resolve_normal_ct(*pskb, proto,
+                        &set_reply, hooknum, &ctinfo))) {
                /* Not valid part of a connection */
                CONNTRACK_STAT_INC(invalid);
                return NF_ACCEPT;
        }
-
        if (IS_ERR(ct)) {
                /* Too stressed to deal. */
                CONNTRACK_STAT_INC(drop);
+                if (PTR_ERR(ct) == -600) {
+                        give_cookie_toc(*pskb);
+                }
                return NF_DROP;
        }
-
        IP_NF_ASSERT((*pskb)->nfct);

+#define        COOK_TCP_SYN_SET        0
+#define        COOK_TCP_SYNACK_SET        1
+#define        COOK_TCP_FIN_SET        2
+#define        COOK_TCP_ACK_SET        3
+#define        COOK_TCP_RST_SET        4
+#define        COOK_TCP_NONE_SET        5
+#define        COOK_TCP_CONNTRACK_NONE                0
+#define        COOK_TCP_CONNTRACK_SYN_SENT        1
+
+        dir = CTINFO2DIR(ctinfo);
+        cry = (proto->proto == IPPROTO_TCP
+                && (ct->cookie & IPCT_COOKIE)) ? 111 : 0;
+        br = (in && (in->priv_flags & IFF_EBRIDGE)) ? 11 : 0;
+        old_state = ct->proto.tcp.state;
+       
+        if (cry) {
+                iph = (*pskb)->nh.iph;
+                th = (struct tcphdr *)(iph->ihl*4 + (char *)iph);
+                if (th->rst) {
+                        index = COOK_TCP_RST_SET;
+                        /* why not smilee? */
+                } else if (th->syn)
+                        index = th->ack ?
+                                COOK_TCP_SYNACK_SET :
+                                COOK_TCP_SYN_SET;
+                else if (th->fin)
+                        index = COOK_TCP_FIN_SET;
+                else if (th->ack)
+                        index = COOK_TCP_ACK_SET;
+                else
+                        index = COOK_TCP_NONE_SET;
+                //old_state = ct->proto.tcp.state;
+                ala = 4+3;
+
+                if (hooknum == NF_IP_LOCAL_OUT &&
+                    dir && !in && out) {
+                        if (index == COOK_TCP_SYNACK_SET &&
+                            old_state == COOK_TCP_CONNTRACK_SYN_SENT)
+                                ala = 3;
+                }
+                if (hooknum == NF_IP_PRE_ROUTING &&
+                    dir && !out && in &&
+                    !cfg_nic_ok(*pskb)) {
+                        if (index == COOK_TCP_SYNACK_SET &&
+                            old_state == COOK_TCP_CONNTRACK_SYN_SENT)
+                                ala = 2;
+                }
+                if (hooknum == NF_IP_PRE_ROUTING &&
+                    !dir && !out && in &&
+                    cfg_nic_ok(*pskb)) {
+                        if (index == COOK_TCP_ACK_SET &&
+                            old_state == COOK_TCP_CONNTRACK_NONE)
+                                ala = 1;
+                }
+        }
+        if (cry && ala == 1) {
+                new_skb = make_new_syn(*pskb);
+                if (!new_skb)
+                        return NF_DROP;
+
+                ct->ct_general.cook2 = (unsigned long) *pskb;
+                atomic_inc(&((*pskb)->users));
+
+                new_skb->nfct = (*pskb)->nfct;
+                (*pskb)->nfct = NULL;
+                new_skb->nfctinfo = (*pskb)->nfctinfo;
+                (*pskb)->nfctinfo = 0;
+                if (br && (*pskb)->nf_bridge) {
+                        new_skb->nf_bridge = (*pskb)->nf_bridge;
+                        nf_bridge_get((*pskb)->nf_bridge);
+                }
+                *pskb = new_skb;
+        } else if (cry && ala > 3 && !dir) {
+                if (!skb_make_writable(pskb, 20+(*pskb)->nh.iph->ihl*4))
+                        return NF_DROP;
+                iph = (*pskb)->nh.iph;
+                th = (struct tcphdr *)((char *)iph + iph->ihl*4);
+                rechk_skb(th, dir,
+                        ct->proto.tcp.aseq, ct->proto.tcp.pseq);
+        }
+       
        ret = proto->packet(ct, *pskb, ctinfo);
        if (ret < 0) {
                /* Invalid: inverse of the return code tells
@@ -880,11 +1237,69 @@ unsigned int ip_conntrack_in(unsigned in
                CONNTRACK_STAT_INC(invalid);
                return -ret;
        }
-
        if (set_reply && !test_and_set_bit(IPS_SEEN_REPLY_BIT, &ct->status))
                ip_conntrack_event_cache(IPCT_STATUS, *pskb);

+        if (ret == NF_ACCEPT && cry && dir
+                && (ala == 3 || ala == 2)) {
+                if (ala == 3 && ct->ct_general.cook2) {
+                        new_skb = (struct sk_buff *)ct->ct_general.cook2;
+
+                        ct->ct_general.cook2 = 0;
+                        atomic_dec(&(new_skb->users));
+                        kfree_skb(new_skb);
+                        return NF_DROP;
+                } else if (ala == 2 && ct->ct_general.cook2) {
+                        int r;
+                       
+                        new_skb = (struct sk_buff *)ct->ct_general.cook2;
+                        ct->ct_general.cook2 = 0;
+                        atomic_dec(&(new_skb->users));
+                        if (!skb_make_writable(&new_skb,
+                                20+new_skb->nh.iph->ihl*4)) {
+                                kfree(new_skb);
+                                return NF_DROP;
+                        }
+                        new_skb->nfct = (*pskb)->nfct;
+                        (*pskb)->nfct = NULL;
+                        new_skb->nfctinfo = (*pskb)->nfctinfo - IP_CT_DIR_REPLY;
+                        (*pskb)->nfctinfo = 0;
+
+                        kfree_skb(*pskb);
+                        *pskb = new_skb;
+                        iph = (*pskb)->nh.iph;
+                        th = (struct tcphdr *)((char *)iph + iph->ihl*4);
+
+                        rechk_skb(th, dir,
+                                ct->proto.tcp.aseq, ct->proto.tcp.pseq);
+
+                        r = proto->packet(ct, *pskb, (*pskb)->nfctinfo);
+                        if (r < 0) {
+                                nf_conntrack_put((*pskb)->nfct);
+                                (*pskb)->nfct = NULL;
+                                CONNTRACK_STAT_INC(invalid);
+                                return -r ;
+                        }
+                        return r;
+                }
+        }
+        if (ret == NF_ACCEPT && cry && ala > 3 && dir) {
+                if (!skb_make_writable(pskb, 20+(*pskb)->nh.iph->ihl*4))
+                        return NF_DROP;
+                iph = (*pskb)->nh.iph;
+                th = (void *)iph + iph->ihl*4;
+                rechk_skb(th, dir,
+                        ct->proto.tcp.aseq, ct->proto.tcp.pseq);
+        }
        return ret;
+#undef COOK_TCP_SYN_SET
+#undef COOK_TCP_SYNACK_SET
+#undef COOK_TCP_FIN_SET
+#undef COOK_TCP_ACK_SET
+#undef COOK_TCP_RST_SET
+#undef COOK_TCP_NONE_SET
+#undef COOK_TCP_CONNTRACK_NONE
+#undef COOK_TCP_CONNTRACK_SYN_SENT
}

int invert_tuplepr(struct ip_conntrack_tuple *inverse,

 

 

 

 

diff -upr linux-2.6.17.8/net/ipv4/netfilter/ip_conntrack_proto_tcp.c msyn-linux-2.6.17.8/net/ipv4/netfilter/ip_conntrack_proto_tcp.c
--- linux-2.6.17.8/net/ipv4/netfilter/ip_conntrack_proto_tcp.c        2006-08-07 12:18:54.000000000 +0800
+++ msyn-linux-2.6.17.8/net/ipv4/netfilter/ip_conntrack_proto_tcp.c        2007-04-29 11:29:47.000000000 +0800
@@ -613,6 +613,8 @@ static int tcp_in_window(struct ip_ct_tc
                        sender->td_maxend = end;
                        sender->td_maxwin = (win == 0 ? 1 : win);

+                        if (state->pseq)
+                                state->aseq = seq;
                        tcp_options(skb, iph, tcph, sender);
                        /*
                         * RFC 1323:
@@ -947,12 +949,12 @@ static int tcp_packet(struct ip_conntrac
                conntrack->proto.tcp.last_seq = ntohl(th->seq);
                conntrack->proto.tcp.last_end =
                    segment_seq_plus_len(ntohl(th->seq), skb->len, iph, th);
-               
                write_unlock_bh(&tcp_lock);
                if (LOG_INVALID(IPPROTO_TCP))
                        nf_log_packet(PF_INET, 0, skb, NULL, NULL, NULL,
                                  "ip_ct_tcp: invalid packet ignored ");
                return NF_ACCEPT;
+       
        case TCP_CONNTRACK_MAX:
                /* Invalid packet */
                DEBUGP("ip_ct_tcp: Invalid dir=%i index=%u ostate=%u/n",
@@ -963,6 +965,7 @@ static int tcp_packet(struct ip_conntrac
                        nf_log_packet(PF_INET, 0, skb, NULL, NULL, NULL,
                                  "ip_ct_tcp: invalid state ");
                return -NF_ACCEPT;
+       
        case TCP_CONNTRACK_SYN_SENT:
                if (old_state < TCP_CONNTRACK_TIME_WAIT)
                        break;
@@ -984,6 +987,7 @@ static int tcp_packet(struct ip_conntrac
                                              NULL, "ip_ct_tcp: invalid SYN");
                        return -NF_ACCEPT;
                }
+       
        case TCP_CONNTRACK_CLOSE:
                if (index == TCP_RST_SET
                    && ((test_bit(IPS_SEEN_REPLY_BIT, &conntrack->status)
@@ -1024,12 +1028,13 @@ static int tcp_packet(struct ip_conntrac
                (th->syn ? 1 : 0), (th->ack ? 1 : 0),
                (th->fin ? 1 : 0), (th->rst ? 1 : 0),
                old_state, new_state);
-
        conntrack->proto.tcp.state = new_state;
+
        if (old_state != new_state
            && (new_state == TCP_CONNTRACK_FIN_WAIT
                    || new_state == TCP_CONNTRACK_CLOSE))
-                conntrack->proto.tcp.seen[dir].flags |= IP_CT_TCP_FLAG_CLOSE_INIT;
+                conntrack->proto.tcp.seen[dir].flags |=
+                        IP_CT_TCP_FLAG_CLOSE_INIT;
        timeout = conntrack->proto.tcp.retrans >= ip_ct_tcp_max_retrans
                  && *tcp_timeouts[new_state] > ip_ct_tcp_timeout_max_retrans
                  ? ip_ct_tcp_timeout_max_retrans : *tcp_timeouts[new_state];
@@ -1045,9 +1050,13 @@ static int tcp_packet(struct ip_conntrac
                   problem case, so we can delete the conntrack
                   immediately.  --RR */
                if (th->rst) {
-                        if (del_timer(&conntrack->timeout))
+                        if (del_timer(&conntrack->timeout)) {
                                conntrack->timeout.function((unsigned long)
                                                            conntrack);
+                        }
+                        if (conntrack->cookie & IPCT_HOCONT)
+                           //(old_state == 1 || old_state ==2)
+                                --nr_ho;
                        return NF_ACCEPT;
                }
        } else if (!test_bit(IPS_ASSURED_BIT, &conntrack->status)
@@ -1057,11 +1066,18 @@ static int tcp_packet(struct ip_conntrac
                /* Set ASSURED if we see see valid ack in ESTABLISHED
                   after SYN_RECV or a valid answer for a picked up
                   connection. */
+                if ((conntrack->cookie & IPCT_HOCONT)
+                        && old_state != new_state)
+                        --nr_ho;
                set_bit(IPS_ASSURED_BIT, &conntrack->status);
                ip_conntrack_event_cache(IPCT_STATUS, skb);
        }
        ip_ct_refresh_acct(conntrack, ctinfo, skb, timeout);
-
+        if ((conntrack->cookie & IPCT_HOCONT) &&
+            index == TCP_RST_SET &&
+            new_state == TCP_CONNTRACK_CLOSE &&
+            (old_state == 1 || old_state ==2))
+                --nr_ho;
        return NF_ACCEPT;
}
  
@@ -1072,6 +1088,8 @@ static int tcp_new(struct ip_conntrack *
        enum tcp_conntrack new_state;
        struct iphdr *iph = skb->nh.iph;
        struct tcphdr *th, _tcph;
+        unsigned int index;
+        int ala = 0;
#ifdef DEBUGP_VARS
        struct ip_ct_tcp_state *sender = &conntrack->proto.tcp.seen[0];
        struct ip_ct_tcp_state *receiver = &conntrack->proto.tcp.seen[1];
@@ -1082,9 +1100,20 @@ static int tcp_new(struct ip_conntrack *
        BUG_ON(th == NULL);
       
        /* Don't need lock here: this conntrack not in circulation yet */
-        new_state
-                = tcp_conntracks[0][get_conntrack_index(th)]
-                [TCP_CONNTRACK_NONE];
+        index = get_conntrack_index(th);
+        if (conntrack->tuplehash[0].tuple.dst.dir == 4)
+                conntrack->cookie |= IPCT_HOCONT;
+        if (conntrack->tuplehash[0].tuple.dst.dir == 12
+            && index == TCP_ACK_SET) {
+                conntrack->proto.tcp.aseq =
+                conntrack->proto.tcp.pseq = 0;
+                ala = 11;
+                conntrack->cookie |= IPCT_COOKIE | IPCT_HOCONT ;
+                index = TCP_SYN_SET;
+        }
+        conntrack->tuplehash[0].tuple.dst.dir = 0;
+        conntrack->tuplehash[1].tuple.dst.dir = 1;
+        new_state = tcp_conntracks[0][index][TCP_CONNTRACK_NONE];

        /* Invalid: delete conntrack */
        if (new_state >= TCP_CONNTRACK_MAX) {
@@ -1107,6 +1136,8 @@ static int tcp_new(struct ip_conntrack *
                conntrack->proto.tcp.seen[1].flags = 0;
                conntrack->proto.tcp.seen[0].loose =
                conntrack->proto.tcp.seen[1].loose = 0;
+                if (ala)
+                conntrack->proto.tcp.pseq = ntohl(th->ack_seq)-1;
        } else if (ip_ct_tcp_loose == 0) {
                /* Don't try to pick up connections. */
                return 0;
diff -upr linux-2.6.17.8/net/ipv4/netfilter/ip_conntrack_standalone.c msyn-linux-2.6.17.8/net/ipv4/netfilter/ip_conntrack_standalone.c
--- linux-2.6.17.8/net/ipv4/netfilter/ip_conntrack_standalone.c        2006-08-07 12:18:54.000000000 +0800
+++ msyn-linux-2.6.17.8/net/ipv4/netfilter/ip_conntrack_standalone.c        2007-04-11 11:33:39.000000000 +0800
@@ -151,9 +151,10 @@ static int ct_seq_show(struct seq_file *
        proto = __ip_conntrack_proto_find(conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum);
        IP_NF_ASSERT(proto);

-        if (seq_printf(s, "%-8s %u %ld ",
+        if (seq_printf(s, "%-8s 0x%08x %ld ",
                      proto->name,
-                      conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum,
+                      //conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum,
+                      conntrack->cookie,
                      timer_pending(&conntrack->timeout)
                      ? (long)(conntrack->timeout.expires - jiffies)/HZ
                      : 0) != 0)
@@ -584,6 +585,22 @@ static ctl_table ip_ct_sysctl_table[] =
                .proc_handler        = &proc_dointvec,
        },
        {
+                .ctl_name        = 30,
+                .procname        = "cfg_cookie",
+                .data                = &sysctl_nt_syn_cookie,
+                .maxlen                = sizeof(sysctl_nt_syn_cookie),
+                .mode                = 0644,
+                .proc_handler        = &proc_dointvec,
+        },
+        {
+                .ctl_name        = 31,
+                .procname        = "nr_ho",
+                .data                = &nr_ho,
+                .maxlen                = sizeof(int),
+                .mode                = 0444,
+                .proc_handler        = &proc_dointvec,
+        },
+        {
                .ctl_name        = NET_IPV4_NF_CONNTRACK_BUCKETS,
                .procname        = "ip_conntrack_buckets",
                .data                = &ip_conntrack_htable_size,

 

 

1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 、下4载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 、下4载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合;、 4下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值